{"openapi":"3.1.0","info":{"title":"Labeeq API","version":"1.0.0","summary":"Read and write the conversations, contacts and deals in a Labeeq workspace.","description":"The Labeeq API lets you build on top of your own workspace: read contacts and\nconversations, send a real message on any connected channel, and open deals in\nyour pipeline. It is a JSON REST API over HTTPS, included in every plan.\n\nRather click around first? Import the [Postman collection](https://labeeq.com/developers/postman_collection.json) — every\nendpoint below, with example bodies and the auth header already pointed at a\n`token` variable. It is generated from this document, so the two cannot disagree.\n\n## Authentication\n\nEvery request carries a personal access token as a bearer token:\n\n```\nAuthorization: Bearer YOUR_TOKEN\n```\n\nCreate tokens in **Settings → Integrations → Developer API**. The plain token is\nshown once, at creation — only its hash is stored, so a lost token is replaced,\nnever recovered.\n\nA token belongs in the header and nowhere else. Requests carrying a `token` or\n`api_token` **query parameter are refused with `400`**, because a token in a URL\nis copied into access logs, proxy caches and browser history. Requests over plain\nHTTP are refused with `403`; every call must be TLS.\n\nCall `GET /me` first: it answers with the workspace the token belongs to and the\nabilities it carries, which is the quickest way to confirm your setup.\n\nA token can also be **pinned to the addresses it may be used from** — an exact\naddress or a CIDR range, set when you create it. Used from anywhere else it\nanswers `403`, which makes a leaked token far less useful to whoever found it.\nEvery write your tokens make is recorded with its token, address and result, and\nthe trail is visible in the same settings page.\n\n## Abilities\n\nA token carries a fixed set of abilities, chosen when you create it. **An ability\ncan only narrow what its owner may already do** — the call must pass *both* the\ntoken's abilities and the owning teammate's own role permissions. Revoking a\nteammate's access therefore revokes their tokens' reach at the same time.\n\n| Ability | Grants |\n| --- | --- |\n| `contacts:read` | قراءة جهات الاتصال |\n| `contacts:write` | إنشاء وتعديل جهات الاتصال |\n| `conversations:read` | قراءة المحادثات |\n| `messages:send` | إرسال الرسائل |\n| `leads:read` | قراءة العملاء المحتملين |\n| `leads:write` | إنشاء وتعديل العملاء المحتملين |\n| `webhooks:manage` | إدارة اشتراكات الويب هوك |\n\n## Workspaces\n\nA token is bound to the workspace of the teammate who created it. Every response is\nscoped to that workspace: a record belonging to another one answers `404`, never\nanother company's data.\n\n## Pagination\n\nCollections are cursor-paginated. Follow `meta.next_cursor` and pass it back as\n`?cursor=`; `per_page` defaults to 50 and caps at 100. Cursors are opaque — treat\nthem as strings and do not construct them yourself.\n\n## Rate limits\n\n60 requests per minute per token. Every response carries `X-RateLimit-Limit` and\n`X-RateLimit-Remaining`, so you can slow down before you are cut off; exceeding\nthe limit answers `429` with a `Retry-After` header saying how many seconds to\nwait. Back off and retry rather than hammering — the counter is per token, so a\nrunaway script starves your other integrations too.\n\n## Retrying a write safely\n\nA timeout tells you nothing about whether the work happened. Send an\n`Idempotency-Key` header on any `POST` — any unique string of your own, an order\nid or a UUID — and retrying with the same key returns the **first** response\ninstead of sending a second message or opening a second deal.\n\n```\nIdempotency-Key: order-4821-shipped\n```\n\nA replayed response carries `Idempotent-Replay: true`. Keys are remembered for 24\nhours and are scoped to your workspace, so they cannot collide with another\ncustomer's. Reusing a key with a *different* body answers `422` — that is a bug\non your side, and returning the earlier result would hide it. A request that\nfailed is not recorded, so you can fix the body and retry with the same key.\nSending no key keeps the old behaviour: every call does the work.\n\n## Errors\n\nEvery error is JSON of the same shape — a `message`, plus an `errors` map when a\nbody failed validation — so one handler covers them all. Internal details are\nnever returned: an unexpected failure is a plain `500`, with nothing about the\nframework or the database in it.\n\n`400` the request itself was malformed (a token in the URL, for instance), `401`\nno or bad token, `403` the token or the teammate lacks permission — or the call\nwas not over HTTPS, `404` the record does not exist in this workspace, `422` the\nbody failed validation, `429` rate limited.","contact":{"name":"Labeeq support","url":"https://labeeq.com/contact"}},"servers":[{"url":"https://labeeq.com/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Account","description":"Who the token belongs to."},{"name":"Contacts","description":"The people who talk to you — one record per person, across every channel."},{"name":"Conversations","description":"Threads with a contact on a channel."},{"name":"Messages","description":"Reading a thread, and sending into it."},{"name":"Leads","description":"Deals on the pipeline, attached to a contact."},{"name":"Webhooks","description":"Subscribe your own URL to events, so a trigger fires the moment something happens instead of polling for it."}],"paths":{"/me":{"get":{"tags":["Account"],"operationId":"getMe","summary":"Who am I","description":"The token's teammate, their workspace, and the abilities the token carries. Costs nothing and touches no data — the call to make first.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Me"}}},"example":{"data":{"user":{"id":7,"name":"Mona Zaki","email":"mona@hadayek.com"},"company":{"id":3,"name":"Hadayek Clinics"},"abilities":["contacts:read","messages:send"]}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/contacts":{"get":{"tags":["Contacts"],"operationId":"listContacts","summary":"List contacts","description":"Contacts in the workspace, newest first. `search` matches name and email; it also matches phone numbers when the token's teammate may see them.\n\n**Required ability:** `contacts:read`","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"meta":{"$ref":"#/components/schemas/CursorMeta"}}},"example":{"data":[{"id":42,"name":"Mona Zaki","phone":"+201001234567","email":"mona@example.com","lifecycle_stage_id":3,"blocked":false,"created_at":"2026-07-26T09:41:00+00:00","updated_at":"2026-07-26T09:41:00+00:00"}],"meta":{"next_cursor":null,"per_page":50}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/Search"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"tags":["Contacts"],"operationId":"createContact","summary":"Create a contact","description":"Adds a person to the workspace. A contact needs a name; give a phone or an email so you can reach them.\n\n**Required ability:** `contacts:write`","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}},"example":{"data":{"id":42,"name":"Mona Zaki","phone":"+201001234567","email":"mona@example.com","lifecycle_stage_id":3,"blocked":false,"created_at":"2026-07-26T09:41:00+00:00","updated_at":"2026-07-26T09:41:00+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/IdempotencyConflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":255,"examples":["Mona Zaki"]},"email":{"type":["string","null"],"format":"email","examples":["mona@example.com"]},"phone":{"type":["string","null"],"maxLength":32,"examples":["+201001234567"]},"lifecycle_stage_id":{"type":["integer","null"],"description":"A stage from Settings → Lifecycle."}}}}}}}},"/contacts/{id}":{"get":{"tags":["Contacts"],"operationId":"getContact","summary":"Get a contact","description":"One contact by id. A contact in another workspace answers `404`.\n\n**Required ability:** `contacts:read`","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}},"example":{"data":{"id":42,"name":"Mona Zaki","phone":"+201001234567","email":"mona@example.com","lifecycle_stage_id":3,"blocked":false,"created_at":"2026-07-26T09:41:00+00:00","updated_at":"2026-07-26T09:41:00+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/Id"}]}},"/conversations":{"get":{"tags":["Conversations"],"operationId":"listConversations","summary":"List conversations","description":"Threads in the workspace, newest first, each with the channel it runs on.\n\n**Required ability:** `conversations:read`","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}},"meta":{"$ref":"#/components/schemas/CursorMeta"}}},"example":{"data":[{"id":1024,"contact_id":42,"channel":{"id":2,"name":"Clinic WhatsApp","type":"whatsapp"},"status":"open","subject":null,"assignee":{"type":"user","id":7},"last_message_at":"2026-07-26T09:41:00+00:00","closed_at":null,"created_at":"2026-07-26T09:12:00+00:00"}],"meta":{"next_cursor":null,"per_page":50}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"status","in":"query","required":false,"description":"Only threads in this status.","schema":{"type":"string","enum":["open","pending","snoozed","closed"]}},{"name":"contact_id","in":"query","required":false,"schema":{"type":"integer"}},{"name":"channel_id","in":"query","required":false,"schema":{"type":"integer"}},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]}},"/conversations/{id}":{"get":{"tags":["Conversations"],"operationId":"getConversation","summary":"Get a conversation","description":"One thread with its channel and current assignee.\n\n**Required ability:** `conversations:read`","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Conversation"}}},"example":{"data":{"id":1024,"contact_id":42,"channel":{"id":2,"name":"Clinic WhatsApp","type":"whatsapp"},"status":"open","subject":null,"assignee":{"type":"user","id":7},"last_message_at":"2026-07-26T09:41:00+00:00","closed_at":null,"created_at":"2026-07-26T09:12:00+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/Id"}]}},"/conversations/{id}/messages":{"get":{"tags":["Messages"],"operationId":"listMessages","summary":"List messages","description":"A thread's messages, newest first.\n\n**Required ability:** `conversations:read`","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"meta":{"$ref":"#/components/schemas/CursorMeta"}}},"example":{"data":[{"id":9001,"conversation_id":1024,"type":"message","direction":"inbound","sender_type":"contact","user_id":null,"body":"Do you open on Friday?","content_type":"text","status":null,"created_at":"2026-07-26T09:41:00+00:00"}],"meta":{"next_cursor":null,"per_page":50}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/Id"},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"tags":["Messages"],"operationId":"sendMessage","summary":"Send a message","description":"Sends an outbound message into the thread, on whichever channel it runs on,\nattributed to the token's teammate. This is a real send: it takes the same\npath as the inbox composer, so delivery, automation and reporting all behave\nidentically.\n\nWhatsApp applies Meta's rules — outside the 24-hour customer service window\na free-form message is refused by Meta and arrives back as a failed message.\n\n**Required ability:** `messages:send`","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Message"}}},"example":{"data":{"id":9001,"conversation_id":1024,"type":"message","direction":"outbound","sender_type":"contact","user_id":null,"body":"Your order is on its way!","content_type":"text","status":null,"created_at":"2026-07-26T09:41:00+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/IdempotencyConflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/Id"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body"],"properties":{"body":{"type":"string","maxLength":4096,"examples":["Your order is on its way!"]}}}}}}}},"/leads":{"get":{"tags":["Leads"],"operationId":"listLeads","summary":"List leads","description":"Deals in the pipeline, newest first.\n\n**Required ability:** `leads:read`","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Lead"}},"meta":{"$ref":"#/components/schemas/CursorMeta"}}},"example":{"data":[{"id":88,"contact_id":42,"name":"Clinic fit-out","value":"25000.00","source":"website","outcome":null,"assigned_to":7,"closed_at":null,"created_at":"2026-07-26T09:41:00+00:00"}],"meta":{"next_cursor":null,"per_page":50}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"name":"outcome","in":"query","required":false,"description":"`open` for deals still in play, or a closed outcome.","schema":{"type":"string","enum":["open","won","lost"]}},{"name":"contact_id","in":"query","required":false,"schema":{"type":"integer"}},{"$ref":"#/components/parameters/PerPage"},{"$ref":"#/components/parameters/Cursor"}]},"post":{"tags":["Leads"],"operationId":"createLead","summary":"Create a lead","description":"Opens a deal against a contact. The contact must belong to this workspace, or the call answers `422`.\n\n**Required ability:** `leads:write`","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Lead"}}},"example":{"data":{"id":88,"contact_id":42,"name":"Clinic fit-out","value":"25000.00","source":"website","outcome":null,"assigned_to":7,"closed_at":null,"created_at":"2026-07-26T09:41:00+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/IdempotencyConflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contact_id","name"],"properties":{"contact_id":{"type":"integer","examples":[42]},"name":{"type":"string","maxLength":255,"examples":["Clinic fit-out"]},"value":{"type":["number","null"],"minimum":0,"examples":[25000]},"source":{"type":["string","null"],"description":"Where the deal came from. Defaults to `other`.","examples":["website"]}}}}}}}},"/webhooks":{"get":{"tags":["Webhooks"],"operationId":"listWebhooks","summary":"List subscriptions","description":"Every webhook subscription in the workspace, however it was created — this endpoint, or the Webhooks screen in the panel.\n\n**Required ability:** `webhooks:manage`","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"meta":{"$ref":"#/components/schemas/CursorMeta"}}},"example":{"data":[{"id":12,"name":"Zapier","target_url":"https://hooks.zapier.com/hooks/catch/1/abcdef/","events":["message.received"],"is_active":true,"consecutive_failures":0,"disabled_at":null,"created_at":"2026-07-26T09:41:00+00:00"}],"meta":{"next_cursor":null,"per_page":50}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Webhooks"],"operationId":"createWebhook","summary":"Subscribe to events","description":"Registers a URL to receive the events you name. Build a trigger on this rather than polling a list endpoint.\n\nThe signing secret is returned **once**, in `meta.secret` — store it, and verify every delivery against the `X-Labeeq-Signature` header. The target must be a public `https` address, re-checked at delivery time. A workspace may hold 25 subscriptions.\n\n**Required ability:** `webhooks:manage`","responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Webhook"}}},"example":{"data":{"id":12,"name":"Zapier","target_url":"https://hooks.zapier.com/hooks/catch/1/abcdef/","events":["message.received"],"is_active":true,"consecutive_failures":0,"disabled_at":null,"created_at":"2026-07-26T09:41:00+00:00"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/IdempotencyConflict"},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_url","events"],"properties":{"target_url":{"type":"string","format":"uri","description":"Public https address to POST to.","examples":["https://hooks.zapier.com/hooks/catch/1/abcdef/"]},"events":{"type":"array","items":{"type":"string","enum":["message.received","message.sent","conversation.created","conversation.opened","conversation.closed","conversation.assigned","contact.created","contact.updated","note.created","contact.lifecycle_changed","lead.created","lead.won","lead.lost"]},"description":"One or more event names.","examples":[["message.received","conversation.closed"]]},"name":{"type":["string","null"],"description":"Shown in the panel. Defaults to the token's name.","examples":["Zapier"]}}}}}}}},"/webhooks/{id}":{"delete":{"tags":["Webhooks"],"operationId":"deleteWebhook","summary":"Unsubscribe","description":"Removes the subscription and stops delivery. A subscription that is already gone answers `404`.\n\n**Required ability:** `webhooks:manage`","responses":{"204":{"description":"No content"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"parameters":[{"$ref":"#/components/parameters/Id"}]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A personal access token from Settings → Integrations → Developer API."}},"schemas":{"Me":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"email":{"type":"string","format":"email"}}},"company":{"type":"object","properties":{"id":{"type":["integer","null"]},"name":{"type":["string","null"]}}},"abilities":{"type":"array","items":{"type":"string","enum":["contacts:read","contacts:write","conversations:read","messages:send","leads:read","leads:write","webhooks:manage"]}}}},"Contact":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":["string","null"]},"phone":{"type":["string","null"],"description":"Masked (`+201•••••••67`) when the token's teammate lacks the view-phone permission."},"email":{"type":["string","null"],"format":"email"},"lifecycle_stage_id":{"type":["integer","null"]},"blocked":{"type":"boolean","description":"Blocked contacts stop reaching your inbox."},"created_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]},"updated_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]}}},"Conversation":{"type":"object","properties":{"id":{"type":"integer"},"contact_id":{"type":"integer"},"channel":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"type":{"type":"string","examples":["whatsapp"]}}},"status":{"type":"string","enum":["open","pending","snoozed","closed"]},"subject":{"type":["string","null"]},"assignee":{"type":["object","null"],"description":"Who holds the thread — a teammate or an AI agent. `null` when unassigned.","properties":{"type":{"type":"string","enum":["user","ai"]},"id":{"type":"integer"}}},"last_message_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]},"closed_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]},"created_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]}}},"Message":{"type":"object","properties":{"id":{"type":"integer"},"conversation_id":{"type":"integer"},"type":{"type":"string","enum":["message","note","event"]},"direction":{"type":["string","null"],"enum":["inbound","outbound",null]},"sender_type":{"type":"string","enum":["contact","user","system"]},"user_id":{"type":["integer","null"],"description":"The teammate who sent it, when a human did."},"body":{"type":["string","null"]},"content_type":{"type":"string","examples":["text"]},"status":{"type":["string","null"],"description":"Delivery state of an outbound message.","examples":["sent"]},"created_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]}}},"Lead":{"type":"object","properties":{"id":{"type":"integer"},"contact_id":{"type":["integer","null"]},"name":{"type":["string","null"]},"value":{"type":["string","null"],"description":"Deal value, as a decimal string.","examples":["25000.00"]},"source":{"type":"string","examples":["website"]},"outcome":{"type":["string","null"],"enum":["won","lost",null],"description":"`null` while the deal is still open."},"assigned_to":{"type":["integer","null"]},"closed_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]},"created_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]}}},"Webhook":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"target_url":{"type":"string","format":"uri","examples":["https://hooks.zapier.com/hooks/catch/1/abcdef/"]},"events":{"type":"array","items":{"type":"string"},"examples":[["message.received"]]},"is_active":{"type":"boolean"},"consecutive_failures":{"type":"integer","description":"Resets on the first success. At 10 the subscription is disabled and the workspace owners are emailed."},"disabled_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]},"created_at":{"type":["string","null"],"format":"date-time","examples":["2026-07-26T09:41:00+00:00"]}}},"CursorMeta":{"type":"object","properties":{"next_cursor":{"type":["string","null"],"description":"Pass back as `?cursor=`. `null` on the last page."},"per_page":{"type":"integer"}}},"Error":{"type":"object","properties":{"message":{"type":"string"}}},"ValidationError":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"object","description":"Field name to the list of things wrong with it.","additionalProperties":{"type":"array","items":{"type":"string"}}}}}},"parameters":{"Id":{"name":"id","in":"path","required":true,"schema":{"type":"integer"},"examples":{"default":{"value":42}}},"Search":{"name":"search","in":"query","required":false,"description":"Matches name and email (and phone, when the token's teammate may see phone numbers).","schema":{"type":"string"}},"PerPage":{"name":"per_page","in":"query","required":false,"description":"Rows per page. Defaults to 50, capped at 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string of your own. Retrying with the same key returns the first response instead of repeating the work. Remembered for 24 hours.","schema":{"type":"string","maxLength":191},"examples":{"default":{"value":"order-4821-shipped"}}},"Cursor":{"name":"cursor","in":"query","required":false,"description":"The `meta.next_cursor` from the previous page. Opaque — pass it back unchanged.","schema":{"type":"string"}}},"responses":{"Unauthorized":{"description":"No token, or the token has been revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"message":"Unauthenticated."}}}},"Forbidden":{"description":"The token lacks the required ability, or its teammate lacks the permission — both must allow the call.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"message":"This action is unauthorized."}}}},"NotFound":{"description":"No such record in this workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"message":"Not found."}}}},"ValidationFailed":{"description":"The body failed validation. `errors` lists every field that failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"},"example":{"message":"The body field is required.","errors":{"body":["The body field is required."]}}}}},"IdempotencyConflict":{"description":"A request with this Idempotency-Key is still in flight. Retry in a moment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"message":"A request with this Idempotency-Key is still in progress."}}}},"RateLimited":{"description":"More than 60 requests in a minute on this token. `Retry-After` says how many seconds to wait.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the limit resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"message":"Too Many Attempts."}}}}}}}