# Instant integrator API (full text) > The guide, every operation and the webhooks, each as its page's markdown. Index: [llms.txt](https://booksbyinstant.com/docs/llms.txt). The OpenAPI document: [openapi.json](https://booksbyinstant.com/docs/openapi.json). # Instant integrator API guide The integrator API is what an integrator's servers call to run their customers in Instant: the customers, their members and the members' tokens, the webhook Instant posts to, and the return URL and its origins. Credentials are issued by the Instant team, who also bring an integrator live. The reference ([booksbyinstant.com/docs](https://booksbyinstant.com/docs)) has every path, field and status. This guide says what a reference cannot: the conventions every route follows, how to retry, how to verify a webhook, and how each object lives. Every id and secret below is a placeholder. ## The API - **Base.** `https://app.booksbyinstant.com`, with every route under `/api/integrator/v1`. - **Production only.** Integrators integrate against production; there is no test environment. A customer you make while building is a real one. A customer cannot be deleted. A bank connected in it from a page on your own machine is a real bank too. - **Versions.** Versions are in the path: a breaking change gets `v2` beside `v1`. A field may be added to an answer at any time; a client ignores fields it does not know. - **The customer API.** A member token works on the customer API, as that member. The customer API has its own reference and guide, for integrators with a credential: they are not on this page, and [Fetching these docs](#fetching-these-docs) says how to fetch them. ## Authentication Every request carries one secret as `Authorization: Bearer `, exactly: the scheme `Bearer`, one space, and the secret in its minted format. Anything else is `401` before anything else is read. Whether a well-formed secret is live is checked after the request's own validation: a malformed request can answer `400`, `404`, `413` or `415` before a dead secret's `401` (`PUT /api/integrator/v1/webhook` checks the credential before it looks at the URL). | Secret | Format | Where it works | Who mints it | | --- | --- | --- | --- | | Integrator credential | `live_<100 hex>` | the integrator API only | the people running Instant, shown once | | Member token | `live_m_<100 hex>` | the customer API, as that member | the integrator (`POST /api/integrator/v1/customers/{id}/members/{memberId}/tokens`), shown once | | Webhook signing secret | `live_w_<64 hex>` | never sent to Instant; it verifies what Instant posts | Instant, on every `PUT /api/integrator/v1/webhook`, shown once | A credential is never accepted where a member token is expected and the other way round; a session cookie or any other token is never accepted. Unknown, revoked, rotated and a disabled integrator's credentials are the same `401` "Unauthorized.", indistinguishable on purpose. A `401` carries `WWW-Authenticate: Bearer realm="instant-integrator-api"`. Keep every secret on the integrator's servers only, in a secret manager. Instant keeps the credential and member tokens only as a SHA-512 hash, and the webhook secret encrypted, because it signs with it. Each has a hint: the prefix, `…` and the last four hex characters (`live_…`, `live_m_…`, `live_w_…`). Instant never shows a secret again. ## Requests - A body is `Content-Type: application/json` (anything else is `415` "Use a JSON request."), one JSON object (else `400` "Check your details and try again."), within the route's size limit ([Limits](#limits); over it, declared or sent, is `413` "Request is too large."). - Bodies are strict: a field the route does not take is `400` "Invalid request: unknown field.", and the field is not repeated in the answer. A refused field is named by its path with what it must be ("Invalid customer request: member.language must be one of Instant's languages: …"). - A route that takes a query (the two lists) is strict about it: another parameter, one given twice, an empty value or a number with a leading zero is `400`. A route that takes none ignores one. - Ids are UUIDs, matched in any case and answered in lower case. A path id that is not a UUID is the same `404` as an unknown one, never `400`. Another integrator's object is `404`, never `403`. - References (`reference`, `member.reference`) are the integrator's own ids, 1 to 200 characters; a member reference is unique across all the integrator's customers, so a person in two customers is two members. Spaces at either end are trimmed; any other whitespace at an end (a tab, a newline, a no-break space) is refused, never trimmed. ## Responses Every answer a route gives, success or not, is `X-Content-Type-Options: nosniff` and `Cache-Control: no-store`, except the docs themselves: a `200` or `304` of [the docs endpoints](#fetching-these-docs) is `private, no-cache`, with an `ETag`. JSON is UTF-8; times are ISO 8601 in UTC with milliseconds (`2026-11-06T10:00:00.000Z`). A create answers `201`; everything else that succeeds answers `200`. ## Errors Every answer that is not a success is one envelope: ```json { "error": "A customer with that reference already exists.", "code": "CONFLICT", "existingId": "00000000-0000-7000-8000-000000000000" } ``` `error` is Instant's sentence for people; `code` is stable and is what an integrator branches on; `retryAfter` (seconds) is there only when above 0, with a `Retry-After` header (as a `429` does when there is a wait). A `409` that names an object already there carries `existingId` too. | Status | `code` | Meaning | | --- | --- | --- | | `400` | `VALIDATION_ERROR` | the request is refused as sent; the sentence says why | | `401` | `UNAUTHENTICATED` | no live secret ([Authentication](#authentication)) | | `403` | `FORBIDDEN` | the member may not do this (a role, an approval rule) | | `404` | `NOT_FOUND` | no such object for this caller | | `409` | `CONFLICT` | the state does not allow it now (a duplicate, a decided approval, a changed object) | | `413` | `LIMIT_EXCEEDED` | the body or a part is too large | | `415` | `UNSUPPORTED_MEDIA_TYPE` | the wrong content type, or a file of a kind Instant never reads | | `422` | `UNREADABLE_FILE` | a file of a kind Instant reads that it could not read | | `429` | `RATE_LIMITED` | a rate limit; wait `retryAfter` when given | | any other (`5xx`) | `UNAVAILABLE` | always "Instant is temporarily unavailable. Please try again shortly."; retry later | A `4xx` keeps the refusal's own sentence; a `5xx` always answers the generic one. More codes may be added: treat one you do not know by its status. This API answers `400`, `401`, `404`, `409`, `413`, `415` and `5xx`; `403`, `422` and `429` are the customer API's today. ## Unknown paths and methods What a request outside the routes gets: | Request | Answer | | --- | --- | | A path under `/api/integrator/v1/` that is not a route, or one under a version that does not exist (`v2`) | `404` with the framework's HTML not-found page, **not** the envelope; `Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate` | | A method the route does not take (`POST /api/integrator/v1/me`, `DELETE /api/integrator/v1/customers`, `PUT /api/integrator/v1/customers/{id}`) | `405` with an empty body, no `Allow` header and no envelope | | `OPTIONS` on a route | `204` with `Allow` listing its methods and no CORS header: the API is server to server | | `HEAD` on a `GET` route | the `GET` answer without its body | | A path with a trailing slash (`/api/integrator/v1/`) | `308` to the path without it | So a client treats a `404` or `405` without a JSON body as a wrong path or method in its own code, never as a missing object. ## Idempotency and retries There is no `Idempotency-Key` header. What a repeat of each write does: | Route | A repeat | | --- | --- | | `POST /api/integrator/v1/customers` | `409` "A customer with that reference already exists." with `existingId`, also when two identical creates race: the retry after a lost answer finds what it created | | `POST /api/integrator/v1/customers/{id}/members` | `409` "A member with that reference already exists." without an id: list the customer's members and find the reference; if it is not there, another of your customers has it, because a member reference is unique across all your customers | | `PATCH /api/integrator/v1/customers/{id}`, `PATCH /api/integrator/v1/customers/{id}/members/{memberId}` | the same values again are a `200` that changes nothing | | `POST /api/integrator/v1/customers/{id}/members/{memberId}/tokens` | not idempotent: each call issues a new token. A token whose answer was lost is never shown again and counts toward the cap of 20 until it is revoked or expires: list the member's tokens and revoke what nobody holds | | `DELETE /api/integrator/v1/customers/{id}/members/{memberId}/tokens/{tokenId}` | `409` "That token is no longer active.": it is revoked, as asked | | `PUT /api/integrator/v1/webhook` | every call mints a new secret and the previous one stops at once. After a lost answer, `PUT` again and keep the new secret | | `DELETE /api/integrator/v1/webhook`, `PUT /api/integrator/v1/return-url`, `DELETE /api/integrator/v1/return-url`, `PUT /api/integrator/v1/return-origins` | idempotent: the same state again is a `200` | Retry a `429` after `retryAfter`, and a `5xx` with backoff. Never retry a `4xx` unchanged. ## Pagination `GET /api/integrator/v1/customers` and `GET /api/integrator/v1/webhook/deliveries` answer a page at a time, newest first. A page's `nextCursor` is the next request's `cursor`, and it is null on the last page. Pages hold steady while customers are added: a customer created after the first page never shifts a later one. `limit` (1 to 200, 50 by default) sets the page's size; a deliveries page can be narrowed by `status`. The other lists are whole: a customer's members and entities, oldest first, and a member's tokens, newest first. ## Limits | Limit | Value | | --- | --- | | Request body | 4096 bytes by default; a member's 32 KiB, which 500 entity ids need | | Fields | references 1–200 characters; names 1–120; URLs at most 2000; up to 500 entity ids in a selection | | Tokens | at most 20 active, unexpired tokens per member (a resource, not a rate) | | Rates, per integrator or per customer | none of their own yet | | Webhook | a payload is at most 2048 bytes; a receiver has 10 seconds; 7 attempts; deliveries are kept 30 days | ## Webhooks Instant posts to the integrator's webhook what it would otherwise have told a person: the kinds and the payload are in the reference. Instant adds kinds and fields over time: answer 2xx to a kind you do not know and drop it; ignore fields you do not know. A notice is delivered only when its recipient is the integrator's member: a person who is not, such as an accountant a customer has let in, gets none. Deliveries continue while a customer is paused. A payload holds ids and the integrator's own references, never content: read what it is about through the customer API, as the member; for `docs.updated`, fetch the docs. `docs.updated` concerns no customer. A production release changed a reference or a guide: this API's or the customer API's. It is sent to every active integrator with a webhook, at most once an hour; changes in the meantime go out together. `changed` names each part that changed, its new version (its ETag without the quotes) and the URL to fetch it with the integrator credential. Like every kind it is delivered at least once: deduplicate on `Instant-Event-Id`. A rollback that changes what Instant serves is announced like any other change, so a version can be announced again. `link.finished` says that a bank connection link ended, once for each link. `item` is the `bank_link`: its `id`, as the link answered it, and its `outcome`, `connected`, `cancelled`, `failed` or `expired`. A link expires when nobody opened it within 15 minutes, or its consent did not come back within the hour. Instant tells of that end within about a quarter of an hour. Like every delivery, it can come late or after a later one. Read the link by its id through the customer API for its status, its connection and why it failed. ### Headers and verification Each delivery is a `POST` of the payload with: ``` Content-Type: application/json User-Agent: Instant-Webhooks/1 Instant-Event-Id: Instant-Event-Kind: Instant-Signature: t=,v1=." keyed with the whole secret> ``` ```js import { createHmac, timingSafeEqual } from 'node:crypto'; // secret: the live_w_<64 hex> string from PUT /api/integrator/v1/webhook, kept in a secret manager. // rawBody: the request body exactly as received, a Buffer, before any parsing. export function verify(secret, header, rawBody, now = Date.now() / 1000) { const [, t, v1] = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? '') ?? []; if (!t || Math.abs(now - Number(t)) > 300) return false; // a 5-minute tolerance const expected = createHmac('sha256', secret).update(`${t}.`).update(rawBody).digest(); const given = Buffer.from(v1, 'hex'); return given.length === expected.length && timingSafeEqual(expected, given); } // In the receiver: verify the raw bytes before parsing, then deduplicate on the event id. // if (!verify(secret, request.headers['instant-signature'], rawBody)) return respond(401); // if (await seen(request.headers['instant-event-id'])) return respond(200); // await enqueue(JSON.parse(rawBody)); return respond(200); ``` - Verify the raw body as received, before parsing it; check the timestamp. - Delivery is **at least once**: the same event can arrive more than once, always with the same `Instant-Event-Id`, so deduplicate on it. - Answer any `2xx` within 10 seconds and do the work afterwards; the body is read up to 1 KiB and ignored. A redirect is a failure and is never followed. - Test a duplicate delivery, a slow answer and a receiver outage before going live. ### Retries and retention A delivery has 7 attempts, due at 0 s, 1 m, 5 m, 30 m, 2 h, 6 h and 24 h after its creation; a late attempt skips the offsets it missed. Delivery runs once a minute, so an attempt can follow its due time by a minute or more. After the seventh failure it is `failed` and never sent again. While the integrator is disabled its deliveries wait unsent. Deliveries are kept 30 days: a pending one older than that fails `expired`, and delivered and failed ones are then deleted. There is no replay; the deliveries list and the customer API are how a missed event is found. ## Lifecycle | Object | States | What the integrator sees | | --- | --- | --- | | Integrator | `active` → `disabled` → `active` (the people running Instant) | Disabled: the credential and every member token are `401`; no agent work runs in its customers; deliveries wait; a member's connection links are refused. Enabled again, all of it works; tokens were not revoked | | Credential | rotated by the people running Instant | The old credential is `401` at once; there is no overlap. Agree a cut-over time | | Customer | `active` ↔ `paused` (`PATCH /api/integrator/v1/customers/{id}`) | Paused: Instant answers every chat message with a fixed sentence that the customer is paused, and runs no scheduled, background or event work; reads, decisions, uploads, connections and member changes work; `customer.paused` / `customer.resumed` are posted. Nothing is deleted. There is no delete | | Member | active → deactivated → active (`PATCH /api/integrator/v1/customers/{id}/members/{memberId}`) | Deactivated: every token is revoked for good (`revokedReason: "deactivated"`) and `401`; reactivated: role and access come back, tokens do not. There is no delete. The owner and the last admin cannot be deactivated | | Member token | `active` → `expired` or `revoked` | Both are `401`. Revoked by the integrator (`integrator`), by deactivation (`deactivated`) or by the people running Instant (`operator`) | | Webhook | set ↔ removed (`PUT /api/integrator/v1/webhook`, `DELETE /api/integrator/v1/webhook`; the people running Instant may remove it) | Removed: pending deliveries fail `webhook_removed`; the history stays 30 days | | Return URL | set ↔ cleared (the people running Instant may clear it) | Cleared: a connection ends on Instant's own result page | | Return origins | set, `[]` clears (`PUT /api/integrator/v1/return-origins`) | Up to ten origins your return URLs may be on, each exactly as a browser writes it: https, or http on a loopback address on your own machine. The return URL's own origin counts without being listed | | Delivery | `pending` → `delivered` or `failed` | 7 attempts in 24 hours; kept 30 days | | Connection link (a member's one-use link to connect a mailbox, a calendar or a bank) | unused → used or expired | 15 minutes, once | ## Fetching these docs This guide and the reference are served with the integrator credential, so your servers can fetch them: - `GET /api/integrator/v1/docs/guide.md` answers this guide, as `text/markdown; charset=utf-8; variant=GFM`. - `GET /api/integrator/v1/docs/openapi.json` answers the reference, an OpenAPI 3.1 document. Without a query they answer the integrator API's docs. With `?api=customer` they answer the customer API's guide and reference, fetched with the same integrator credential. Each answer has an `ETag`: the version of that file, an opaque string that changes when the file changes, and only then. Keep it with your copy and send it back as `If-None-Match`; while your copy is current, the answer is `304` without a body. The answers are `Cache-Control: private, no-cache`: keep your copy, and ask again before you use it. A fetch is a use of the credential like any other request, a `304` included. With a webhook, `docs.updated` says when to fetch: fetch once after you set the webhook, then when a notice names a part. Without one, check at most once an hour. The public docs page updates within the hour after a notice. --- # Read the integrator `GET https://app.booksbyinstant.com/api/integrator/v1/me` Which integrator the credential belongs to: the way to check a credential. operationId `integratorMe`; tag Integrator. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/me' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/me", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/me", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Responses ### 200 The integrator. `application/json`: object - `integrator` (object; required) - `id` (string · uuid; required): The integrator's id. - `name` (string; required): The integrator's name. Example, built from the schema: ```json { "integrator": { "id": "01900000-0000-7000-8000-000000000000", "name": "string" } } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/integrator-me/ · Overview: https://booksbyinstant.com/docs/index.md # List customers `GET https://app.booksbyinstant.com/api/integrator/v1/customers` The integrator's customers, newest first, a page at a time. Pages hold steady while customers are added. There is no last-use time per customer. operationId `listCustomers`; tag Customers. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/customers' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/customers", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Query parameters - `limit` (integer; from `1` to `200`; default `50`): How many to answer: a whole number from 1 to 200, without a leading zero. - `cursor` (string · uuid): The nextCursor of the previous page. ## Responses ### 200 A page of customers. `application/json`: object - `items` (array of object; required) - `id` (string · uuid; required): The customer's id. - `reference` (string; required): The integrator's own reference for the customer. - `status` (string; required; one of `active`, `paused`): paused while the integrator has paused the customer. - `country` (string or null; required): The customer's ISO 3166-1 alpha-2 country code, in capitals, or null when none is recorded. - `createdAt` (string · date-time; required): When the customer was created. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `pausedAt` (string · date-time or null; required): When the customer was paused, or null while it is active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `nextCursor` (string · uuid or null; required): The cursor of the next page, or null on the last page. Example, built from the schema: ```json { "items": [ { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "status": "active", "country": "string", "createdAt": "2026-01-15T09:30:00.000Z", "pausedAt": "2026-01-15T09:30:00.000Z" } ], "nextCursor": "01900000-0000-7000-8000-000000000000" } ``` ### 400 A query parameter is unknown or invalid. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/list-customers/ · Overview: https://booksbyinstant.com/docs/index.md # Create a customer `POST https://app.booksbyinstant.com/api/integrator/v1/customers` A new customer and its first member, who owns it and is an admin. The member's first chat turn starts the company's setup conversation. Approvals need a second member: nobody approves their own submission, and every new customer has the default bill approval workflow, so a bill the only member posts waits until a second member approves it; the answer does not say so. A country without a setup of its own gets the general company setup. operationId `createCustomer`; tag Customers. ## Example request cURL: ```bash curl -X POST 'https://app.booksbyinstant.com/api/integrator/v1/customers' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "reference": "string", "country": "AD", "member": { "reference": "string", "name": "string", "language": "en", "timezone": "Europe/Copenhagen" } }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers", { method: "POST", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "reference": "string", "country": "AD", "member": { "reference": "string", "name": "string", "language": "en", "timezone": "Europe/Copenhagen" } }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.post( "https://app.booksbyinstant.com/api/integrator/v1/customers", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "reference": "string", "country": "AD", "member": { "reference": "string", "name": "string", "language": "en", "timezone": "Europe/Copenhagen", }, }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Request body At most 4096 bytes. `application/json`, required: object; no other fields - `reference` (string; required; 1 to 1000 characters): The integrator's own reference: 1 to 200 characters after spaces at either end are trimmed. Any other whitespace at an end (a tab, a newline, a no-break space) is refused, never trimmed. - `country` (string; required; one of `AD`, `AE`, `AF`, `AG`, `AI`, `AL`, `AM`, `AO`, `AQ`, `AR`, `AS`, `AT`, `AU`, `AW`, `AX`, `AZ`, `BA`, `BB`, `BD`, `BE`, `BF`, `BG`, `BH`, `BI`, `BJ`, `BL`, `BM`, `BN`, `BO`, `BQ`, `BR`, `BS`, `BT`, `BV`, `BW`, `BY`, `BZ`, `CA`, `CC`, `CD`, `CF`, `CG`, `CH`, `CI`, `CK`, `CL`, `CM`, `CN`, `CO`, `CR`, `CU`, `CV`, `CW`, `CX`, `CY`, `CZ`, `DE`, `DJ`, `DK`, `DM`, `DO`, `DZ`, `EC`, `EE`, `EG`, `EH`, `ER`, `ES`, `ET`, `FI`, `FJ`, `FK`, `FM`, `FO`, `FR`, `GA`, `GB`, `GD`, `GE`, `GF`, `GG`, `GH`, `GI`, `GL`, `GM`, `GN`, `GP`, `GQ`, `GR`, `GS`, `GT`, `GU`, `GW`, `GY`, `HK`, `HM`, `HN`, `HR`, `HT`, `HU`, `ID`, `IE`, `IL`, `IM`, `IN`, `IO`, `IQ`, `IR`, `IS`, `IT`, `JE`, `JM`, `JO`, `JP`, `KE`, `KG`, `KH`, `KI`, `KM`, `KN`, `KP`, `KR`, `KW`, `KY`, `KZ`, `LA`, `LB`, `LC`, `LI`, `LK`, `LR`, `LS`, `LT`, `LU`, `LV`, `LY`, `MA`, `MC`, `MD`, `ME`, `MF`, `MG`, `MH`, `MK`, `ML`, `MM`, `MN`, `MO`, `MP`, `MQ`, `MR`, `MS`, `MT`, `MU`, `MV`, `MW`, `MX`, `MY`, `MZ`, `NA`, `NC`, `NE`, `NF`, `NG`, `NI`, `NL`, `NO`, `NP`, `NR`, `NU`, `NZ`, `OM`, `PA`, `PE`, `PF`, `PG`, `PH`, `PK`, `PL`, `PM`, `PN`, `PR`, `PS`, `PT`, `PW`, `PY`, `QA`, `RE`, `RO`, `RS`, `RU`, `RW`, `SA`, `SB`, `SC`, `SD`, `SE`, `SG`, `SH`, `SI`, `SJ`, `SK`, `SL`, `SM`, `SN`, `SO`, `SR`, `SS`, `ST`, `SV`, `SX`, `SY`, `SZ`, `TC`, `TD`, `TF`, `TG`, `TH`, `TJ`, `TK`, `TL`, `TM`, `TN`, `TO`, `TR`, `TT`, `TV`, `TW`, `TZ`, `UA`, `UG`, `UM`, `US`, `UY`, `UZ`, `VA`, `VC`, `VE`, `VG`, `VI`, `VN`, `VU`, `WF`, `WS`, `YE`, `YT`, `ZA`, `ZM`, `ZW`): An assigned ISO 3166-1 alpha-2 code in capitals, such as DK (GB, not UK). - `member` (object; required; no other fields) - `reference` (string; required; 1 to 1000 characters): The integrator's own reference: 1 to 200 characters after spaces at either end are trimmed. Any other whitespace at an end (a tab, a newline, a no-break space) is refused, never trimmed. - `name` (string; required; at least 1 character): The member's name: 1 to 120 characters after leading and trailing whitespace is removed. With two or more words, the last is the last name. - `language` (string; required; one of `en`, `de`, `sv`, `nb`, `da`, `fr`, `es`, `pl`, `pt-BR`, `it`, `hr`, `tr`, `he`, `ar`, `ro`): One of Instant's languages. - `timezone` (string; 1 to 100 characters): An IANA time zone. Example, built from the schema: ```json { "reference": "string", "country": "AD", "member": { "reference": "string", "name": "string", "language": "en", "timezone": "Europe/Copenhagen" } } ``` ## Responses ### 201 The customer and its member. `application/json`: object - `customer` (object; required): A customer: a company in Instant that the integrator created. - `id` (string · uuid; required): The customer's id. - `reference` (string; required): The integrator's own reference for the customer. - `status` (string; required; one of `active`, `paused`): paused while the integrator has paused the customer. - `country` (string or null; required): The customer's ISO 3166-1 alpha-2 country code, in capitals, or null when none is recorded. - `createdAt` (string · date-time; required): When the customer was created. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `pausedAt` (string · date-time or null; required): When the customer was paused, or null while it is active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `member` (object; required): A person in a customer, with a role and entity access. - `id` (string · uuid; required): The member's id. - `reference` (string; required): The integrator's own reference for the member, unique across all its customers. - `name` (string; required): The member's name. - `role` (string; required; one of `admin`, `user`, `auditor`): admin manages the company and sees every entity, user works within their entities, auditor reads. - `owner` (boolean; required): True for the one member who owns the customer. - `language` (string or null; required): The member's language: one of the language values the requests take, or null when none is set. - `timezone` (string or null; required): The member's IANA time zone, or null when none is set. - `active` (boolean; required): False while the member is deactivated. - `joinedAt` (string · date-time; required): When the member joined the customer. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deactivatedAt` (string · date-time or null; required): When the member was deactivated, or null while active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `entityAccess` (one of 2 shapes; required): Which of the customer's entities the member works in: all of them, or a selection. An admin always has all. A deactivated member shows the selection that reactivating them restores. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required): The entity ids of the selection, sorted. - `tokens` (object; required) - `active` (integer; required; at least `0`): How many of the member's tokens are active and unexpired, at most 20. Example, built from the schema: ```json { "customer": { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "status": "active", "country": "string", "createdAt": "2026-01-15T09:30:00.000Z", "pausedAt": "2026-01-15T09:30:00.000Z" }, "member": { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "name": "string", "role": "admin", "owner": true, "language": "string", "timezone": "string", "active": true, "joinedAt": "2026-01-15T09:30:00.000Z", "deactivatedAt": "2026-01-15T09:30:00.000Z", "entityAccess": { "mode": "all" }, "tokens": { "active": 0 } } } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 409 A customer with that reference already exists: the answer carries its `existingId`, so a retry after a lost answer finds what it created. Or a member with that reference already exists, and the answer has no id. `application/json`: the `Error` object, as in 400. ### 413 The body is over 4096 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/create-customer/ · Overview: https://booksbyinstant.com/docs/index.md # Read a customer `GET https://app.booksbyinstant.com/api/integrator/v1/customers/{id}` operationId `readCustomer`; tag Customers. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. ## Responses ### 200 The customer and its members, oldest first. `application/json`: object - `customer` (object; required): A customer: a company in Instant that the integrator created. - `id` (string · uuid; required): The customer's id. - `reference` (string; required): The integrator's own reference for the customer. - `status` (string; required; one of `active`, `paused`): paused while the integrator has paused the customer. - `country` (string or null; required): The customer's ISO 3166-1 alpha-2 country code, in capitals, or null when none is recorded. - `createdAt` (string · date-time; required): When the customer was created. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `pausedAt` (string · date-time or null; required): When the customer was paused, or null while it is active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `members` (array of object; required) - `id` (string · uuid; required): The member's id. - `reference` (string; required): The integrator's own reference for the member, unique across all its customers. - `name` (string; required): The member's name. - `role` (string; required; one of `admin`, `user`, `auditor`): admin manages the company and sees every entity, user works within their entities, auditor reads. - `owner` (boolean; required): True for the one member who owns the customer. - `language` (string or null; required): The member's language: one of the language values the requests take, or null when none is set. - `timezone` (string or null; required): The member's IANA time zone, or null when none is set. - `active` (boolean; required): False while the member is deactivated. - `joinedAt` (string · date-time; required): When the member joined the customer. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deactivatedAt` (string · date-time or null; required): When the member was deactivated, or null while active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `entityAccess` (one of 2 shapes; required): Which of the customer's entities the member works in: all of them, or a selection. An admin always has all. A deactivated member shows the selection that reactivating them restores. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required): The entity ids of the selection, sorted. - `tokens` (object; required) - `active` (integer; required; at least `0`): How many of the member's tokens are active and unexpired, at most 20. Example, built from the schema: ```json { "customer": { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "status": "active", "country": "string", "createdAt": "2026-01-15T09:30:00.000Z", "pausedAt": "2026-01-15T09:30:00.000Z" }, "members": [ { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "name": "string", "role": "admin", "owner": true, "language": "string", "timezone": "string", "active": true, "joinedAt": "2026-01-15T09:30:00.000Z", "deactivatedAt": "2026-01-15T09:30:00.000Z", "entityAccess": { "mode": "all" }, "tokens": { "active": 0 } } ] } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 404 `id` names nothing this caller can see. `application/json`: the `Error` object, as in 401. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/read-customer/ · Overview: https://booksbyinstant.com/docs/index.md # Pause, resume or hand over a customer `PATCH https://app.booksbyinstant.com/api/integrator/v1/customers/{id}` `status` pauses or resumes the customer; the answer is the customer. While it is paused, Instant answers every message with a fixed sentence that the customer is paused, and runs no scheduled, background or event work; reads, decisions, uploads, connections and member changes work, and nothing is deleted. `customer.paused` or `customer.resumed` is posted to the webhook. `ownerMemberId` hands the ownership to that member and answers the customer with its members. operationId `updateCustomer`; tag Customers. ## Example request cURL: ```bash curl -X PATCH 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "status": "active" }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000", { method: "PATCH", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "status": "active" }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.patch( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "status": "active", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. ## Request body At most 4096 bytes. `application/json`, required: object; send exactly 1 field; no other fields Exactly one of status or ownerMemberId; both, or neither, is refused. status pauses or resumes the customer, and the same status again changes nothing. ownerMemberId hands the ownership to one of the customer's members, who must be an active admin. - `status` (string; one of `active`, `paused`) - `ownerMemberId` (string · uuid): The id of one of the customer's members, an active admin, who becomes its owner. Example, built from the schema: ```json { "status": "active" } ``` ## Responses ### 200 The customer; with its members after a handover. `application/json`: object - `customer` (object; required): A customer: a company in Instant that the integrator created. - `id` (string · uuid; required): The customer's id. - `reference` (string; required): The integrator's own reference for the customer. - `status` (string; required; one of `active`, `paused`): paused while the integrator has paused the customer. - `country` (string or null; required): The customer's ISO 3166-1 alpha-2 country code, in capitals, or null when none is recorded. - `createdAt` (string · date-time; required): When the customer was created. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `pausedAt` (string · date-time or null; required): When the customer was paused, or null while it is active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `members` (array of object): Only after an ownerMemberId handover. - `id` (string · uuid; required): The member's id. - `reference` (string; required): The integrator's own reference for the member, unique across all its customers. - `name` (string; required): The member's name. - `role` (string; required; one of `admin`, `user`, `auditor`): admin manages the company and sees every entity, user works within their entities, auditor reads. - `owner` (boolean; required): True for the one member who owns the customer. - `language` (string or null; required): The member's language: one of the language values the requests take, or null when none is set. - `timezone` (string or null; required): The member's IANA time zone, or null when none is set. - `active` (boolean; required): False while the member is deactivated. - `joinedAt` (string · date-time; required): When the member joined the customer. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deactivatedAt` (string · date-time or null; required): When the member was deactivated, or null while active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `entityAccess` (one of 2 shapes; required): Which of the customer's entities the member works in: all of them, or a selection. An admin always has all. A deactivated member shows the selection that reactivating them restores. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required): The entity ids of the selection, sorted. - `tokens` (object; required) - `active` (integer; required; at least `0`): How many of the member's tokens are active and unexpired, at most 20. Example, built from the schema: ```json { "customer": { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "status": "active", "country": "string", "createdAt": "2026-01-15T09:30:00.000Z", "pausedAt": "2026-01-15T09:30:00.000Z" }, "members": [ { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "name": "string", "role": "admin", "owner": true, "language": "string", "timezone": "string", "active": true, "joinedAt": "2026-01-15T09:30:00.000Z", "deactivatedAt": "2026-01-15T09:30:00.000Z", "entityAccess": { "mode": "all" }, "tokens": { "active": 0 } } ] } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. Also when the body has both `status` and `ownerMemberId`, or neither. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 404 `id` names nothing this caller can see. Also when `ownerMemberId` names no member of the customer. `application/json`: the `Error` object, as in 400. ### 409 The new owner is not an active admin, or the company changed meanwhile: read it again. `application/json`: the `Error` object, as in 400. ### 413 The body is over 4096 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/update-customer/ · Overview: https://booksbyinstant.com/docs/index.md # List a customer's entities `GET https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/entities` The customer's legal entities, which a selected entity access names: oldest first, archived ones included, no paging. A new customer has none until its setup has made one. operationId `listEntities`; tag Customers. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/entities' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/entities", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/entities", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. ## Responses ### 200 The entities. `application/json`: object - `entities` (array of object; required) - `id` (string · uuid; required): The entity's id, which a selected entity access names. - `name` (string; required): The entity's name. - `legalName` (string or null; required): Its legal name, or null when it is not known. - `country` (string; required): Its ISO 3166-1 alpha-2 country code. - `legalForm` (string or null; required): Its legal form, such as ApS, or null when it is not known. - `functionalCurrency` (string; required): The ISO 4217 code of the currency its books are kept in. - `status` (string; required; one of `active`, `archived`): archived once the entity is archived; it stays in the list. - `createdAt` (string · date-time; required): When the entity was created. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. Example, built from the schema: ```json { "entities": [ { "id": "01900000-0000-7000-8000-000000000000", "name": "string", "legalName": "string", "country": "string", "legalForm": "string", "functionalCurrency": "string", "status": "active", "createdAt": "2026-01-15T09:30:00.000Z" } ] } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 404 `id` names nothing this caller can see. `application/json`: the `Error` object, as in 401. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/list-entities/ · Overview: https://booksbyinstant.com/docs/index.md # List a customer's members `GET https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/members` operationId `listMembers`; tag Members. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. ## Responses ### 200 The members, oldest first. `application/json`: object - `members` (array of object; required) - `id` (string · uuid; required): The member's id. - `reference` (string; required): The integrator's own reference for the member, unique across all its customers. - `name` (string; required): The member's name. - `role` (string; required; one of `admin`, `user`, `auditor`): admin manages the company and sees every entity, user works within their entities, auditor reads. - `owner` (boolean; required): True for the one member who owns the customer. - `language` (string or null; required): The member's language: one of the language values the requests take, or null when none is set. - `timezone` (string or null; required): The member's IANA time zone, or null when none is set. - `active` (boolean; required): False while the member is deactivated. - `joinedAt` (string · date-time; required): When the member joined the customer. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deactivatedAt` (string · date-time or null; required): When the member was deactivated, or null while active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `entityAccess` (one of 2 shapes; required): Which of the customer's entities the member works in: all of them, or a selection. An admin always has all. A deactivated member shows the selection that reactivating them restores. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required): The entity ids of the selection, sorted. - `tokens` (object; required) - `active` (integer; required; at least `0`): How many of the member's tokens are active and unexpired, at most 20. Example, built from the schema: ```json { "members": [ { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "name": "string", "role": "admin", "owner": true, "language": "string", "timezone": "string", "active": true, "joinedAt": "2026-01-15T09:30:00.000Z", "deactivatedAt": "2026-01-15T09:30:00.000Z", "entityAccess": { "mode": "all" }, "tokens": { "active": 0 } } ] } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 404 `id` names nothing this caller can see. `application/json`: the `Error` object, as in 401. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/list-members/ · Overview: https://booksbyinstant.com/docs/index.md # Add a member `POST https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/members` A member reference is unique across all the integrator's customers: a person in two customers is two members. operationId `createMember`; tag Members. ## Example request cURL: ```bash curl -X POST 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "reference": "string", "name": "string", "role": "admin", "language": "en", "timezone": "Europe/Copenhagen", "entityAccess": { "mode": "all" } }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members", { method: "POST", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "reference": "string", "name": "string", "role": "admin", "language": "en", "timezone": "Europe/Copenhagen", "entityAccess": { "mode": "all" } }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.post( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "reference": "string", "name": "string", "role": "admin", "language": "en", "timezone": "Europe/Copenhagen", "entityAccess": { "mode": "all", }, }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. ## Request body At most 32768 bytes. `application/json`, required: object; no other fields An admin has access to all entities, so role admin with a selection is refused, and a selection names entities of this customer only. A member can be added while the customer is paused. - `reference` (string; required; 1 to 1000 characters): The integrator's own reference: 1 to 200 characters after spaces at either end are trimmed. Any other whitespace at an end (a tab, a newline, a no-break space) is refused, never trimmed. - `name` (string; required; at least 1 character): The member's name: 1 to 120 characters after leading and trailing whitespace is removed. With two or more words, the last is the last name. - `role` (string; required; one of `admin`, `user`, `auditor`) - `language` (string; required; one of `en`, `de`, `sv`, `nb`, `da`, `fr`, `es`, `pl`, `pt-BR`, `it`, `hr`, `tr`, `he`, `ar`, `ro`): One of Instant's languages. - `timezone` (string; 1 to 100 characters): An IANA time zone. - `entityAccess` (one of 2 shapes): all: every entity of the customer, and it clears a selection. selected: the entities entityIds names. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required; at most 500 items; no repeated items): Up to 500 of the customer's entity ids, each at most once: the same id in upper and lower case counts as twice. An empty selection reaches no entity until one is added, so a restricted member can be created before the customer has an entity. Example, built from the schema: ```json { "reference": "string", "name": "string", "role": "admin", "language": "en", "timezone": "Europe/Copenhagen", "entityAccess": { "mode": "all" } } ``` ## Responses ### 201 The member. `application/json`: object - `member` (object; required): A person in a customer, with a role and entity access. - `id` (string · uuid; required): The member's id. - `reference` (string; required): The integrator's own reference for the member, unique across all its customers. - `name` (string; required): The member's name. - `role` (string; required; one of `admin`, `user`, `auditor`): admin manages the company and sees every entity, user works within their entities, auditor reads. - `owner` (boolean; required): True for the one member who owns the customer. - `language` (string or null; required): The member's language: one of the language values the requests take, or null when none is set. - `timezone` (string or null; required): The member's IANA time zone, or null when none is set. - `active` (boolean; required): False while the member is deactivated. - `joinedAt` (string · date-time; required): When the member joined the customer. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deactivatedAt` (string · date-time or null; required): When the member was deactivated, or null while active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `entityAccess` (one of 2 shapes; required): Which of the customer's entities the member works in: all of them, or a selection. An admin always has all. A deactivated member shows the selection that reactivating them restores. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required): The entity ids of the selection, sorted. - `tokens` (object; required) - `active` (integer; required; at least `0`): How many of the member's tokens are active and unexpired, at most 20. Example, built from the schema: ```json { "member": { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "name": "string", "role": "admin", "owner": true, "language": "string", "timezone": "string", "active": true, "joinedAt": "2026-01-15T09:30:00.000Z", "deactivatedAt": "2026-01-15T09:30:00.000Z", "entityAccess": { "mode": "all" }, "tokens": { "active": 0 } } } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. Also when `role` is admin with a selected entity access, or an entity id is not the customer's. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 404 `id` names nothing this caller can see. `application/json`: the `Error` object, as in 400. ### 409 A member with that reference already exists in one of the integrator's customers; the answer has no id. `application/json`: the `Error` object, as in 400. ### 413 The body is over 32768 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/create-member/ · Overview: https://booksbyinstant.com/docs/index.md # Read a member `GET https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/members/{memberId}` operationId `readMember`; tag Members. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. - `memberId` (string · uuid; required): The member's id. ## Responses ### 200 The member. `application/json`: object - `member` (object; required): A person in a customer, with a role and entity access. - `id` (string · uuid; required): The member's id. - `reference` (string; required): The integrator's own reference for the member, unique across all its customers. - `name` (string; required): The member's name. - `role` (string; required; one of `admin`, `user`, `auditor`): admin manages the company and sees every entity, user works within their entities, auditor reads. - `owner` (boolean; required): True for the one member who owns the customer. - `language` (string or null; required): The member's language: one of the language values the requests take, or null when none is set. - `timezone` (string or null; required): The member's IANA time zone, or null when none is set. - `active` (boolean; required): False while the member is deactivated. - `joinedAt` (string · date-time; required): When the member joined the customer. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deactivatedAt` (string · date-time or null; required): When the member was deactivated, or null while active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `entityAccess` (one of 2 shapes; required): Which of the customer's entities the member works in: all of them, or a selection. An admin always has all. A deactivated member shows the selection that reactivating them restores. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required): The entity ids of the selection, sorted. - `tokens` (object; required) - `active` (integer; required; at least `0`): How many of the member's tokens are active and unexpired, at most 20. Example, built from the schema: ```json { "member": { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "name": "string", "role": "admin", "owner": true, "language": "string", "timezone": "string", "active": true, "joinedAt": "2026-01-15T09:30:00.000Z", "deactivatedAt": "2026-01-15T09:30:00.000Z", "entityAccess": { "mode": "all" }, "tokens": { "active": 0 } } } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 404 `id` or `memberId` name nothing this caller can see. `application/json`: the `Error` object, as in 401. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/read-member/ · Overview: https://booksbyinstant.com/docs/index.md # Change, deactivate or reactivate a member `PATCH https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/members/{memberId}` A change of role or entity access takes effect on the member's next request; a chat turn already running ends. `active: false` deactivates the member and revokes their tokens for good; `active: true` reactivates them with their role and access, and new tokens must be issued. operationId `updateMember`; tag Members. ## Example request cURL: ```bash curl -X PATCH 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "name": "string", "language": "en", "timezone": "Europe/Copenhagen", "role": "admin", "entityAccess": { "mode": "all" }, "active": true }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000", { method: "PATCH", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "name": "string", "language": "en", "timezone": "Europe/Copenhagen", "role": "admin", "entityAccess": { "mode": "all" }, "active": true }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.patch( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "name": "string", "language": "en", "timezone": "Europe/Copenhagen", "role": "admin", "entityAccess": { "mode": "all", }, "active": True, }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. - `memberId` (string · uuid; required): The member's id. ## Request body At most 32768 bytes. `application/json`, required: object; send at least 1 field; no other fields Send active alone (false deactivates the member, true reactivates them), or at least one of the other fields; the same values again change nothing. An admin has access to all entities, so role admin with a selection is refused, and a selection names entities of this customer only. A deactivated member's role and entity access change only after active: true; their name, language and time zone can still change. The owner stays an admin and is never deactivated, and the company keeps at least one admin. - `name` (string; at least 1 character): The member's name: 1 to 120 characters after leading and trailing whitespace is removed. With two or more words, the last is the last name. - `language` (string; one of `en`, `de`, `sv`, `nb`, `da`, `fr`, `es`, `pl`, `pt-BR`, `it`, `hr`, `tr`, `he`, `ar`, `ro`): One of Instant's languages. - `timezone` (string; 1 to 100 characters): An IANA time zone. - `role` (string; one of `admin`, `user`, `auditor`) - `entityAccess` (one of 2 shapes): all: every entity of the customer, and it clears a selection. selected: the entities entityIds names. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required; at most 500 items; no repeated items): Up to 500 of the customer's entity ids, each at most once: the same id in upper and lower case counts as twice. An empty selection reaches no entity until one is added, so a restricted member can be created before the customer has an entity. - `active` (boolean) Example, built from the schema: ```json { "name": "string", "language": "en", "timezone": "Europe/Copenhagen", "role": "admin", "entityAccess": { "mode": "all" }, "active": true } ``` ## Responses ### 200 The member. `application/json`: object - `member` (object; required): A person in a customer, with a role and entity access. - `id` (string · uuid; required): The member's id. - `reference` (string; required): The integrator's own reference for the member, unique across all its customers. - `name` (string; required): The member's name. - `role` (string; required; one of `admin`, `user`, `auditor`): admin manages the company and sees every entity, user works within their entities, auditor reads. - `owner` (boolean; required): True for the one member who owns the customer. - `language` (string or null; required): The member's language: one of the language values the requests take, or null when none is set. - `timezone` (string or null; required): The member's IANA time zone, or null when none is set. - `active` (boolean; required): False while the member is deactivated. - `joinedAt` (string · date-time; required): When the member joined the customer. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deactivatedAt` (string · date-time or null; required): When the member was deactivated, or null while active. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `entityAccess` (one of 2 shapes; required): Which of the customer's entities the member works in: all of them, or a selection. An admin always has all. A deactivated member shows the selection that reactivating them restores. - either object - `mode` (string; required; always `all`) - or object - `mode` (string; required; always `selected`) - `entityIds` (array of string · uuid; required): The entity ids of the selection, sorted. - `tokens` (object; required) - `active` (integer; required; at least `0`): How many of the member's tokens are active and unexpired, at most 20. Example, built from the schema: ```json { "member": { "id": "01900000-0000-7000-8000-000000000000", "reference": "string", "name": "string", "role": "admin", "owner": true, "language": "string", "timezone": "string", "active": true, "joinedAt": "2026-01-15T09:30:00.000Z", "deactivatedAt": "2026-01-15T09:30:00.000Z", "entityAccess": { "mode": "all" }, "tokens": { "active": 0 } } } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. Also when `active` comes with another field, nothing is to change, `role` is admin with a selected entity access, or an entity id is not the customer's. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 404 `id` or `memberId` name nothing this caller can see. `application/json`: the `Error` object, as in 400. ### 409 The member is deactivated and must be reactivated first; the owner would stop being an admin or be deactivated; the company would have no admin left; or it changed meanwhile. `application/json`: the `Error` object, as in 400. ### 413 The body is over 32768 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/update-member/ · Overview: https://booksbyinstant.com/docs/index.md # List a member's tokens `GET https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/members/{memberId}/tokens` Revoked and expired tokens included; never a secret. operationId `listMemberTokens`; tag Member tokens. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. - `memberId` (string · uuid; required): The member's id. ## Responses ### 200 The tokens, newest first. `application/json`: object - `tokens` (array of object; required) - `id` (string · uuid; required): The token's id. - `hint` (string; required; matches `^[a-z]+_m_…[0-9a-f]{4}$`): The secret's prefix, … and its last four hex characters, to tell tokens apart. - `status` (string; required; one of `active`, `expired`, `revoked`): active until the token expires or is revoked; neither one works again. - `createdAt` (string · date-time; required): When the token was issued. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `expiresAt` (string · date-time or null; required): When the token stops working, or null when it works until it is revoked. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `revokedAt` (string · date-time or null; required): When the token was revoked, or null. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `revokedReason` (string or null; required; one of `integrator`, `deactivated`, `operator`): Why it was revoked: integrator through this API, deactivated when the member was deactivated, operator by the people running Instant. Null unless revoked. - `lastUsedAt` (string · date-time or null; required): When the token was last used, accurate to 5 minutes, or null when it never was. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. Example, built from the schema: ```json { "tokens": [ { "id": "01900000-0000-7000-8000-000000000000", "hint": "string", "status": "active", "createdAt": "2026-01-15T09:30:00.000Z", "expiresAt": "2026-01-15T09:30:00.000Z", "revokedAt": "2026-01-15T09:30:00.000Z", "revokedReason": "integrator", "lastUsedAt": "2026-01-15T09:30:00.000Z" } ] } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 404 `id` or `memberId` name nothing this caller can see. `application/json`: the `Error` object, as in 401. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/list-member-tokens/ · Overview: https://booksbyinstant.com/docs/index.md # Issue a member token `POST https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/members/{memberId}/tokens` Not idempotent: each call issues a new token. The secret is in this answer only. A token whose answer was lost is never shown again and counts toward the 20 until it is revoked or expires: list the member's tokens and revoke what nobody holds. operationId `issueMemberToken`; tag Member tokens. ## Example request cURL: ```bash curl -X POST 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "expiresAt": "2026-01-15T09:30:00.000Z" }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens", { method: "POST", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "expiresAt": "2026-01-15T09:30:00.000Z" }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.post( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "expiresAt": "2026-01-15T09:30:00.000Z", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. - `memberId` (string · uuid; required): The member's id. ## Request body At most 4096 bytes. `application/json`, required: object; no other fields A JSON object, {} at least: a request without one is refused. A token is issued only to an active member, who has at most 20 active tokens. - `expiresAt` (string · date-time): When the token stops working: an ISO 8601 date and time with its offset, such as 2027-01-31T12:00:00Z, in the future. Without one the token works until it is revoked. Example, built from the schema: ```json { "expiresAt": "2026-01-15T09:30:00.000Z" } ``` ## Responses ### 201 The token and its secret. `application/json`: object - `token` (object; required): The token just issued. - `id` (string · uuid; required): The token's id. - `hint` (string; required; matches `^[a-z]+_m_…[0-9a-f]{4}$`): The secret's prefix, … and its last four hex characters, to tell tokens apart. - `createdAt` (string · date-time; required): When the token was issued. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `expiresAt` (string · date-time or null; required): When the token stops working, or null when it works until it is revoked. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `secret` (string; required; matches `^[a-z]+_m_[0-9a-f]{100}$`): The member token, shown this once. Keep it on your servers, in a secret manager. Example, built from the schema: ```json { "token": { "id": "01900000-0000-7000-8000-000000000000", "hint": "string", "createdAt": "2026-01-15T09:30:00.000Z", "expiresAt": "2026-01-15T09:30:00.000Z" }, "secret": "string" } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. Also when `expiresAt` is not in the future. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 404 `id` or `memberId` name nothing this caller can see. `application/json`: the `Error` object, as in 400. ### 409 The member is deactivated, or already has 20 active tokens: revoke one first. `application/json`: the `Error` object, as in 400. ### 413 The body is over 4096 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/issue-member-token/ · Overview: https://booksbyinstant.com/docs/index.md # Revoke a member token `DELETE https://app.booksbyinstant.com/api/integrator/v1/customers/{id}/members/{memberId}/tokens/{tokenId}` Revokes the token for good; it stays in the list with `status` revoked. operationId `revokeMemberToken`; tag Member tokens. ## Example request cURL: ```bash curl -X DELETE 'https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens/01900000-0000-7000-8000-000000000000' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens/01900000-0000-7000-8000-000000000000", { method: "DELETE", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.delete( "https://app.booksbyinstant.com/api/integrator/v1/customers/01900000-0000-7000-8000-000000000000/members/01900000-0000-7000-8000-000000000000/tokens/01900000-0000-7000-8000-000000000000", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Path parameters - `id` (string · uuid; required): The customer's id. - `memberId` (string · uuid; required): The member's id. - `tokenId` (string · uuid; required): The token's id. ## Responses ### 200 The revoked token. `application/json`: object - `token` (object; required): A member token, never its secret. - `id` (string · uuid; required): The token's id. - `hint` (string; required; matches `^[a-z]+_m_…[0-9a-f]{4}$`): The secret's prefix, … and its last four hex characters, to tell tokens apart. - `status` (string; required; one of `active`, `expired`, `revoked`): active until the token expires or is revoked; neither one works again. - `createdAt` (string · date-time; required): When the token was issued. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `expiresAt` (string · date-time or null; required): When the token stops working, or null when it works until it is revoked. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `revokedAt` (string · date-time or null; required): When the token was revoked, or null. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `revokedReason` (string or null; required; one of `integrator`, `deactivated`, `operator`): Why it was revoked: integrator through this API, deactivated when the member was deactivated, operator by the people running Instant. Null unless revoked. - `lastUsedAt` (string · date-time or null; required): When the token was last used, accurate to 5 minutes, or null when it never was. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. Example, built from the schema: ```json { "token": { "id": "01900000-0000-7000-8000-000000000000", "hint": "string", "status": "active", "createdAt": "2026-01-15T09:30:00.000Z", "expiresAt": "2026-01-15T09:30:00.000Z", "revokedAt": "2026-01-15T09:30:00.000Z", "revokedReason": "integrator", "lastUsedAt": "2026-01-15T09:30:00.000Z" } } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 404 `id` or `memberId` or `tokenId` name nothing this caller can see. `application/json`: the `Error` object, as in 401. ### 409 The token is no longer active: it was revoked or has expired. `application/json`: the `Error` object, as in 401. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/revoke-member-token/ · Overview: https://booksbyinstant.com/docs/index.md # Read the webhook `GET https://app.booksbyinstant.com/api/integrator/v1/webhook` operationId `readWebhook`; tag Webhook. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/webhook' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/webhook", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/webhook", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Responses ### 200 The webhook, never its secret, and how many deliveries are pending and failed. `application/json`: object - `webhook` (object or null; required): Null when no webhook is set. - `url` (string; required): Where Instant posts the deliveries. - `hint` (string; required; matches `^[a-z]+_w_…[0-9a-f]{4}$`): The signing secret's prefix, … and its last four hex characters. - `setAt` (string · date-time; required): When the webhook was set, and its secret minted. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deliveries` (object; required) - `pending` (integer; required; at least `0`): How many deliveries wait to be sent or retried. - `failed` (integer; required; at least `0`): How many deliveries failed and will not be sent again. Example, built from the schema: ```json { "webhook": { "url": "string", "hint": "string", "setAt": "2026-01-15T09:30:00.000Z" }, "deliveries": { "pending": 0, "failed": 0 } } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/read-webhook/ · Overview: https://booksbyinstant.com/docs/index.md # Set the webhook `PUT https://app.booksbyinstant.com/api/integrator/v1/webhook` The credential is checked before the URL, so Instant resolves no name for an unknown caller. Every call mints a new signing secret, also for the same URL, and shows it this once; the previous secret stops at once. Pending deliveries are kept and go to the new URL, signed with the new secret. When Instant cannot mint a secret right now, the answer is 503. operationId `setWebhook`; tag Webhook. ## Example request cURL: ```bash curl -X PUT 'https://app.booksbyinstant.com/api/integrator/v1/webhook' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/" }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/webhook", { method: "PUT", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/" }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.put( "https://app.booksbyinstant.com/api/integrator/v1/webhook", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "url": "https://example.com/", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Request body At most 4096 bytes. `application/json`, required: object; no other fields - `url` (string; required; at most 2000 characters; matches `^https://`): Where Instant sends the webhook deliveries: an https URL without credentials, on port 443, with a host name (never an IP address) that resolves to public addresses only. Every call mints a new signing secret, also for the same URL. Example, built from the schema: ```json { "url": "https://example.com/" } ``` ## Responses ### 200 The webhook and its new signing secret. `application/json`: object - `webhook` (object; required): The integrator's webhook, never its secret. - `url` (string; required): Where Instant posts the deliveries. - `hint` (string; required; matches `^[a-z]+_w_…[0-9a-f]{4}$`): The signing secret's prefix, … and its last four hex characters. - `setAt` (string · date-time; required): When the webhook was set, and its secret minted. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `secret` (string; required; matches `^[a-z]+_w_[0-9a-f]{64}$`): The signing secret, shown this once. Keep it on your servers, in a secret manager. Example, built from the schema: ```json { "webhook": { "url": "string", "hint": "string", "setAt": "2026-01-15T09:30:00.000Z" }, "secret": "string" } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. Also when the URL is not a public https URL. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 413 The body is over 4096 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/set-webhook/ · Overview: https://booksbyinstant.com/docs/index.md # Remove the webhook `DELETE https://app.booksbyinstant.com/api/integrator/v1/webhook` Removes the webhook and its secret. Its pending deliveries fail with `webhook_removed`; the history stays 30 days. Removing when none is set is also a 200. operationId `clearWebhook`; tag Webhook. ## Example request cURL: ```bash curl -X DELETE 'https://app.booksbyinstant.com/api/integrator/v1/webhook' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/webhook", { method: "DELETE", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.delete( "https://app.booksbyinstant.com/api/integrator/v1/webhook", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Responses ### 200 No webhook. `application/json`: object - `webhook` (null; required) Example, built from the schema: ```json { "webhook": null } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/clear-webhook/ · Overview: https://booksbyinstant.com/docs/index.md # List webhook deliveries `GET https://app.booksbyinstant.com/api/integrator/v1/webhook/deliveries` The integrator's deliveries, newest first, a page at a time. There is no replay: a failed delivery is not sent again, so read what it was about through the customer API. operationId `listDeliveries`; tag Webhook. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/webhook/deliveries' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/webhook/deliveries", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/webhook/deliveries", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Query parameters - `limit` (integer; from `1` to `200`; default `50`): How many to answer: a whole number from 1 to 200, without a leading zero. - `cursor` (string · uuid): The nextCursor of the previous page. - `status` (string; one of `pending`, `delivered`, `failed`): Only the deliveries in this state. ## Responses ### 200 A page of deliveries. `application/json`: object - `items` (array of object; required) - `id` (string · uuid; required): The delivery's id, which is its payload's id and Instant-Event-Id. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`, `docs.updated`) - `customerId` (string · uuid or null; required): The customer it is about, or null for docs.updated. - `customerReference` (string or null; required): The integrator's reference for the customer, or null for docs.updated. - `memberId` (string · uuid or null; required): The member it is for, or null for connection.expired, connection.synced, link.finished, customer.paused, customer.resumed and docs.updated. - `item` (one of 4 shapes; required): What it is about, or null for docs.updated. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `status` (string; required; one of `pending`, `delivered`, `failed`): pending until a receiver answers 2xx (delivered), or until the 7th attempt fails, the webhook is removed or 30 days pass (failed). - `attempts` (integer; required; at least `0`): How many attempts were made, at most 7. - `lastError` (string or null; required; matches `^(http_[0-9]{3}|timeout|network|redirect|url_refused|webhook_removed|expired)$`): Why the last attempt failed: http_<status>, timeout, network, redirect, url_refused, webhook_removed or expired; null when none did. - `createdAt` (string · date-time; required): When the delivery was created. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `deliveredAt` (string · date-time or null; required): When a receiver answered 2xx, or null. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `nextAttemptAt` (string · date-time or null; required): When the next attempt is due while pending; otherwise null. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `nextCursor` (string · uuid or null; required): The cursor of the next page, or null on the last page. Example, built from the schema: ```json { "items": [ { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "status": "pending", "attempts": 0, "lastError": "string", "createdAt": "2026-01-15T09:30:00.000Z", "deliveredAt": "2026-01-15T09:30:00.000Z", "nextAttemptAt": "2026-01-15T09:30:00.000Z" } ], "nextCursor": "01900000-0000-7000-8000-000000000000" } ``` ### 400 A query parameter is unknown or invalid. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/list-deliveries/ · Overview: https://booksbyinstant.com/docs/index.md # Read the return origins `GET https://app.booksbyinstant.com/api/integrator/v1/return-origins` The return URL's own origin counts as registered without being listed. operationId `readReturnOrigins`; tag Return URL. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/return-origins' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/return-origins", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/return-origins", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Responses ### 200 The return origins, sorted; [] when none is listed. `application/json`: object - `returnOrigins` (array of string; required): Each origin as a browser writes it. Example, built from the schema: ```json { "returnOrigins": [ "string" ] } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/read-return-origins/ · Overview: https://booksbyinstant.com/docs/index.md # Set the return origins `PUT https://app.booksbyinstant.com/api/integrator/v1/return-origins` Replaces the list of return origins; [] clears it. The same origins again, in any order, are a 200 that changes nothing. operationId `setReturnOrigins`; tag Return URL. ## Example request cURL: ```bash curl -X PUT 'https://app.booksbyinstant.com/api/integrator/v1/return-origins' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "origins": [ "string" ] }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/return-origins", { method: "PUT", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "origins": [ "string" ] }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.put( "https://app.booksbyinstant.com/api/integrator/v1/return-origins", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "origins": [ "string", ], }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Request body At most 4096 bytes. `application/json`, required: object; no other fields - `origins` (array of string; required; at most 10 items; no repeated items): Up to ten origins your return URLs may be on, none twice, each exactly as a browser writes it: the scheme, the host in lower case, and the port only when it is not the scheme's default, with no path and no trailing slash. https, or http on a loopback address on your own machine. The return URL's own origin counts as registered without being listed. [] clears the list. Example, built from the schema: ```json { "origins": [ "string" ] } ``` ## Responses ### 200 The return origins, sorted. `application/json`: object - `returnOrigins` (array of string; required): Each origin as a browser writes it. Example, built from the schema: ```json { "returnOrigins": [ "string" ] } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 413 The body is over 4096 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/set-return-origins/ · Overview: https://booksbyinstant.com/docs/index.md # Read the return URL `GET https://app.booksbyinstant.com/api/integrator/v1/return-url` operationId `readReturnUrl`; tag Return URL. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/return-url' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/return-url", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/return-url", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Responses ### 200 The return URL, or null when none is set. `application/json`: object - `returnUrl` (string or null; required) Example, built from the schema: ```json { "returnUrl": "string" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/read-return-url/ · Overview: https://booksbyinstant.com/docs/index.md # Set the return URL `PUT https://app.booksbyinstant.com/api/integrator/v1/return-url` Setting the same URL again is a 200 that changes nothing. operationId `setReturnUrl`; tag Return URL. ## Example request cURL: ```bash curl -X PUT 'https://app.booksbyinstant.com/api/integrator/v1/return-url' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/" }' ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/return-url", { method: "PUT", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, "Content-Type": "application/json", }, body: JSON.stringify({ "url": "https://example.com/" }), }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.put( "https://app.booksbyinstant.com/api/integrator/v1/return-url", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, json={ "url": "https://example.com/", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Request body At most 4096 bytes. `application/json`, required: object; no other fields - `url` (string; required; at most 2000 characters; matches `^https://`): Where a member's browser comes back after a connection: an https URL without credentials. Instant never fetches it, so only its syntax is checked. Example, built from the schema: ```json { "url": "https://example.com/" } ``` ## Responses ### 200 The return URL. `application/json`: object - `returnUrl` (string; required) Example, built from the schema: ```json { "returnUrl": "string" } ``` ### 400 The body is not one JSON object, or a field is invalid; `error` says which. Also when the URL is not an https URL without credentials. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 413 The body is over 4096 bytes. `application/json`: the `Error` object, as in 400. ### 415 The body is not sent as `application/json`. `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/set-return-url/ · Overview: https://booksbyinstant.com/docs/index.md # Clear the return URL `DELETE https://app.booksbyinstant.com/api/integrator/v1/return-url` A connection then ends on Instant's own result page. Clearing when none is set is also a 200. operationId `clearReturnUrl`; tag Return URL. ## Example request cURL: ```bash curl -X DELETE 'https://app.booksbyinstant.com/api/integrator/v1/return-url' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/return-url", { method: "DELETE", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.delete( "https://app.booksbyinstant.com/api/integrator/v1/return-url", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Responses ### 200 No return URL. `application/json`: object - `returnUrl` (null; required) Example, built from the schema: ```json { "returnUrl": null } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 401. --- Page: https://booksbyinstant.com/docs/clear-return-url/ · Overview: https://booksbyinstant.com/docs/index.md # Read a guide `GET https://app.booksbyinstant.com/api/integrator/v1/docs/guide.md` The guide to this API, or to the customer API with api=customer, as Instant serves it now: what the reference does not say, such as the conventions, authentication, errors and limits. It is GitHub Flavored Markdown, sent as `text/markdown; charset=utf-8; variant=GFM`. A fetch is a use of the credential, authenticated like any other request. Check at most once an hour, with If-None-Match. operationId `readGuide`; tag Docs. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/docs/guide.md' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/docs/guide.md", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const text = await res.text(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/docs/guide.md", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) text = res.text ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Query parameters - `api` (string; default `integrator`; one of `integrator`, `customer`): Whose docs: integrator (the default), or customer for the customer API's, fetched with the same integrator credential. ## Headers - `If-None-Match` (string): The ETag of the copy you have. While it is current, the answer is 304, without a body. ## Responses ### 200 The guide. Headers: - `Cache-Control` (string): private, no-cache: keep the copy, and ask again with If-None-Match before you use it. - `ETag` (string): The SHA-256 of the file, in hex and in double quotes: the version of these docs. It changes when the file changes, and only then. - `X-Content-Type-Options` (string): nosniff `text/markdown`: string The guide, in GitHub Flavored Markdown. ### 304 The copy with that ETag is current. Headers: - `Cache-Control` (string): private, no-cache: keep the copy, and ask again with If-None-Match before you use it. - `ETag` (string): The SHA-256 of the file, in hex and in double quotes: the version of these docs. It changes when the file changes, and only then. - `X-Content-Type-Options` (string): nosniff No body. ### 400 A query parameter is unknown or invalid. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/read-guide/ · Overview: https://booksbyinstant.com/docs/index.md # Read an OpenAPI reference `GET https://app.booksbyinstant.com/api/integrator/v1/docs/openapi.json` This API's OpenAPI 3.1 reference, or the customer API's with api=customer, exactly as Instant serves it now. A fetch is a use of the credential, authenticated like any other request. Check at most once an hour, with If-None-Match. operationId `readOpenApi`; tag Docs. ## Example request cURL: ```bash curl -X GET 'https://app.booksbyinstant.com/api/integrator/v1/docs/openapi.json' \ -H "Authorization: Bearer $INTEGRATOR_CREDENTIAL" ``` JavaScript: ```javascript // Node 18 or later, in an ES module (.mjs), which allows the top-level await. const res = await fetch("https://app.booksbyinstant.com/api/integrator/v1/docs/openapi.json", { method: "GET", headers: { Authorization: `Bearer ${process.env.INTEGRATOR_CREDENTIAL}`, }, }); const data = await res.json(); ``` Python: ```python import os import requests res = requests.get( "https://app.booksbyinstant.com/api/integrator/v1/docs/openapi.json", headers={ "Authorization": f"Bearer {os.environ['INTEGRATOR_CREDENTIAL']}", }, ) data = res.json() ``` ## Authorization - Bearer token `live_<100 hex>`: `Authorization: Bearer `. A 401 answers `WWW-Authenticate: Bearer realm="instant-integrator-api"`. ## Query parameters - `api` (string; default `integrator`; one of `integrator`, `customer`): Whose docs: integrator (the default), or customer for the customer API's, fetched with the same integrator credential. ## Headers - `If-None-Match` (string): The ETag of the copy you have. While it is current, the answer is 304, without a body. ## Responses ### 200 The reference. Headers: - `Cache-Control` (string): private, no-cache: keep the copy, and ask again with If-None-Match before you use it. - `ETag` (string): The SHA-256 of the file, in hex and in double quotes: the version of these docs. It changes when the file changes, and only then. - `X-Content-Type-Options` (string): nosniff `application/json`: object An OpenAPI 3.1 document. - `openapi` (string; required; always `3.1.0`) - `info` (object; required) - `title` (string; required) - `version` (string; required) - `description` (string; required) - any other field (any): The rest of the OpenAPI document: paths, webhooks and components. Example, built from the schema: ```json { "openapi": "3.1.0", "info": { "title": "string", "version": "string", "description": "string" } } ``` ### 304 The copy with that ETag is current. Headers: - `Cache-Control` (string): private, no-cache: keep the copy, and ask again with If-None-Match before you use it. - `ETag` (string): The SHA-256 of the file, in hex and in double quotes: the version of these docs. It changes when the file changes, and only then. - `X-Content-Type-Options` (string): nosniff No body. ### 400 A query parameter is unknown or invalid. `application/json`: object; `Error` Every answer that is not a success. - `error` (string; required): Instant's sentence for people. A 4xx keeps the refusal's own sentence; a 5xx always says "Instant is temporarily unavailable. Please try again shortly." - `code` (string; required): Stable, and what a caller branches on: VALIDATION_ERROR (400), UNAUTHENTICATED (401), FORBIDDEN (403), NOT_FOUND (404), CONFLICT (409), LIMIT_EXCEEDED (413), UNSUPPORTED_MEDIA_TYPE (415), UNREADABLE_FILE (422), RATE_LIMITED (429) and UNAVAILABLE (5xx). More codes may be added; treat one you do not know by its status. - `retryAfter` (integer; at least `1`): Seconds to wait before retrying, also sent as the `Retry-After` header. Present only when there is a wait, as on a 429. - `existingId` (string · uuid): On a 409 that names the object already there, such as a customer with that reference: its id. Example, built from the schema: ```json { "error": "string", "code": "VALIDATION_ERROR", "retryAfter": 1, "existingId": "01900000-0000-7000-8000-000000000000" } ``` ### 401 The credential is missing, malformed, unknown, revoked or rotated, or its integrator is disabled. All of these answer the same way. Headers: - `WWW-Authenticate` (string): Bearer realm="instant-integrator-api" `application/json`: the `Error` object, as in 400. ### 5XX Instant is temporarily unavailable. Retry later, with backoff. `application/json`: the `Error` object, as in 400. --- Page: https://booksbyinstant.com/docs/read-open-api/ · Overview: https://booksbyinstant.com/docs/index.md # Webhooks Instant posts each event to the integrator's webhook as a `POST`. Each kind has its headers, payload and answer. ## Kinds ### `approval.due` A member's turn to approve It is a member's turn in an approval round, or a scheduled run waits for its owner's approval. item is the subject's, usually a document, partner, payment or run. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: approval.due` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `approval.due`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `browser.takeover_needed` Reserved: not sent yet Reserved for a later use: Instant does not send this kind yet. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: browser.takeover_needed` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `browser.takeover_needed`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `connection.expired` A bank consent ran out A bank consent ran out. item is the bank_connection; there is no member. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: connection.expired` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `connection.expired`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `connection.synced` A bank backfill or asked read ended A bank connection's read ended: from its first day after the consent, again when a new or rediscovered account or an earlier first day needs a first-day read, or a read the member asked for. item is the bank_connection with outcome completed or failed; there is no member. Routine reads send nothing. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: connection.synced` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `connection.synced`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `customer.paused` A customer was paused The integrator paused the customer. item is the customer; there is no member. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: customer.paused` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `customer.paused`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `customer.resumed` A customer was resumed The integrator resumed the customer. item is the customer; there is no member. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: customer.resumed` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `customer.resumed`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `docs.updated` The docs changed A production release changed a reference or a guide: this API's or the customer API's. Sent to every active integrator with a webhook, at most once an hour; changes in the meantime go out together. changed names each part that changed, its new version (its ETag without the quotes) and the URL to fetch it with the integrator credential. Like every kind it is delivered at least once: deduplicate on Instant-Event-Id. A rollback that changes what Instant serves is announced like any other change, so a version can be announced again. It concerns no customer. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: docs.updated` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `docs.updated`): The kind of the event. #### Payload `application/json`, required: object; `DocsUpdatedPayload` What a docs.updated delivery posts: the docs that changed, each with its new version and where to fetch it. It concerns no customer. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; always `docs.updated`): docs.updated, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When Instant announced the change. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `changed` (array of object; required; 1 to 4 items): Each part that changed: one to four, and no api and doc twice. - `api` (string; required; one of `integrator`, `customer`): Whose docs: integrator for this API's, customer for the customer API's. - `doc` (string; required; one of `openapi`, `guide`): openapi for the OpenAPI reference, guide for the guide. - `version` (string; required; matches `^[0-9a-f]{64}$`): The part's new version: the SHA-256 of the file in hex, which is its ETag without the quotes. - `url` (string; required): Where to fetch it with the integrator credential: readOpenApi or readGuide, with api=customer for the customer API's. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "docs.updated", "occurredAt": "2026-01-15T09:30:00.000Z", "changed": [ { "api": "integrator", "doc": "openapi", "version": "string", "url": "string" } ] } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `link.finished` A bank link ended A bank connection link ended, once for each link: its consent gave a connection, the person cancelled, the bank or Instant could not complete it, or it expired. item is the bank_link with its outcome; there is no member. Like every kind it can arrive late, or after a later delivery. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: link.finished` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `link.finished`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `ping.raised` A notice to a member Any other notice to a member. item is its subject, or ping. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: ping.raised` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `ping.raised`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `reply.ready` A chat reply is ready A member's chat reply is recorded: one per reply, with the reply's message id as the delivery's id. item is the thread. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: reply.ready` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `reply.ready`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `run.finished` Background work finished Background work or a recurring action finished for its owner. item is the run. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: run.finished` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `run.finished`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. ### `task.input_needed` A task needs its owner A follow-up task stopped for its owner. item is the task. A receiver ignores an event kind it does not know: kinds are added over time. `Instant-Event-Kind: task.input_needed` #### Headers - `Instant-Signature` (string; required): `t=,v1=`: t is when this attempt was sent, so each retry is signed again, and v1 is the HMAC-SHA256 of `.`, keyed with the webhook secret string as sent to you (not hex-decoded). Reject a t more than 5 minutes off. - `Instant-Event-Id` (string · uuid; required): The same on every attempt of one event: delivery is at least once. - `Instant-Event-Kind` (string; required; always `task.input_needed`): The kind of the event. #### Payload `application/json`, required: object; `WebhookPayload` What a delivery posts: ids and the integrator's own references, never a text, a title, a path, an amount or an approval code. At most 2048 bytes. - `id` (string · uuid; required): The event's id, the same on every attempt and in Instant-Event-Id: deduplicate on it. - `kind` (string; required; one of `reply.ready`, `run.finished`, `approval.due`, `task.input_needed`, `ping.raised`, `browser.takeover_needed`, `connection.expired`, `customer.paused`, `customer.resumed`, `connection.synced`, `link.finished`): The kind, also in Instant-Event-Kind. - `occurredAt` (string · date-time; required): When it happened. ISO 8601 in UTC with milliseconds, such as 2026-11-06T10:00:00.000Z. - `customerId` (string · uuid; required): The customer it is about. - `customerReference` (string; required; 1 to 200 characters): The integrator's reference for the customer. - `memberId` (string · uuid): The member it is for; absent for connection.expired, connection.synced, link.finished, customer.paused and customer.resumed. - `memberReference` (string; 1 to 200 characters): The integrator's reference for the member; absent when memberId is. - `item` (one of 4 shapes; required): What the event is about. Read it through the customer API, as the member. - either object - `kind` (string; required; always `run`) - `actionId` (string · uuid; required): The recurring action or background work. - `runId` (string · uuid; required): The run. - or object - `kind` (string; required; one of `approval`, `task`, `ping`, `document`, `partner`, `payment`, `thread`, `customer`, `bank_connection`) - `id` (string · uuid): The subject's id; absent when it is not a UUID. - or object - `kind` (string; required; always `bank_connection`) - `id` (string · uuid; required): The bank connection. - `outcome` (string; required; one of `completed`, `failed`): connection.synced only: completed when every account was read (from the first day through yesterday for a backfill); failed when the consent ran out first, or a read asked for failed. - or object - `kind` (string; required; always `bank_link`) - `id` (string · uuid; required): The bank connection link. - `outcome` (string; required; one of `connected`, `cancelled`, `failed`, `expired`): link.finished only: connected when the consent gave a connection; cancelled when the person cancelled; failed when the bank or its provider refused, or Instant could not complete the consent; expired when nobody opened the link in time, or its consent never came back. - `pingId` (string · uuid): The notice that made it; only for approval.due, run.finished, task.input_needed and ping.raised. Example, built from the schema: ```json { "id": "01900000-0000-7000-8000-000000000000", "kind": "reply.ready", "occurredAt": "2026-01-15T09:30:00.000Z", "customerId": "01900000-0000-7000-8000-000000000000", "customerReference": "string", "memberId": "01900000-0000-7000-8000-000000000000", "memberReference": "string", "item": { "kind": "run", "actionId": "01900000-0000-7000-8000-000000000000", "runId": "01900000-0000-7000-8000-000000000000" }, "pingId": "01900000-0000-7000-8000-000000000000" } ``` #### Answer ##### 2XX Received. Any other answer, or none within 10 s, is retried; 7 attempts. No body. --- Page: https://booksbyinstant.com/docs/webhooks/ · Overview: https://booksbyinstant.com/docs/index.md