oToK REST API Reference
The oToK REST API (/v1) gives programmatic access to your workspace: contacts (including per-channel consent), tags and groups, WhatsApp campaigns and templates, deals and pipelines, the product catalog, payments, orders, transactional email, broadcast email campaigns, newsletters, email suppressions, outbound webhooks, and bookings.
- Base URL:
https://app.otok.io/api/v1/ - Auth:
Authorization: Bearer otok_live_…API keys (created in Settings → Developers) - Plan: requires a plan with API access (Growth or higher); deals/pipelines, payments (incl. contact documents), payment requests, orders, campaigns, email campaigns + suppressions (
email_marketing), newsletters, and bookings/meeting-types additionally require the matching plan feature — see feature-gated resource groups - Interactive docs: Swagger UI at
https://app.otok.io/api/v1/docs
Start with Getting Started — authentication, error envelopes, rate limits, and list/filter conventions shared by all endpoints.
Guides
| Page | Covers |
|---|---|
| Getting Started | API keys, auth, base URL, errors, rate limits, pagination & filtering |
| Contacts | Contact upsert & update, merge-conflict contract, notes |
| Tags & Contact Groups | Tag / group CRUD and membership management |
| Campaigns | WhatsApp campaigns: create, schedule, execute |
| Templates | WhatsApp templates: read + send template messages |
| Deals & Pipelines | Pipelines, deal CRUD, stage moves, win/lose, idempotent upsert |
| Products | The product catalog shared by deals and payments: idempotent upsert via external_id, deactivation instead of delete |
| Payments | One-time / recurring / installment payments, entries, refunds, VAT, metadata |
| Payment Requests | Hosted pay-links through the workspace's own provider: mint, list, cancel |
| Orders | E-commerce orders: line items, refunds, mark-paid/cancel, idempotent upsert |
| Transactional Emails | POST /v1/emails: idempotent raw sends, tracking opt-in |
| Email Campaigns | Broadcast email campaigns: the shared content contract (markdown / blocks / design_json), compile feedback, estimate, send/schedule lifecycle, idempotent upsert |
| Newsletters | Smart newsletters and their sequenced issues: idempotent issue upsert, publish-time numbering, publish/schedule lifecycle |
| Consent & Suppressions | Per-channel consent read/write on contacts + the email suppression list — two independent layers that compose at send time |
| Webhooks | Nine event families — email, order, payment-request, contact, message, deal, booking, attendance, form: registration, signatures, retries |
| Bookings & Meeting Types | Availability slots, booking lifecycle, host reassignment |
Endpoint summary
| Resource | Endpoints |
|---|---|
| Contacts | GET /v1/contacts · GET /v1/contacts/:id · POST /v1/contacts (upsert) · PATCH /v1/contacts/:id · GET /v1/contacts/:id/documents |
| Contact consent | GET /v1/contacts/:id/consent · PUT /v1/contacts/:id/consent/:channel |
| Contact notes | GET /v1/contacts/:id/notes · POST /v1/contacts/:id/notes · PATCH /v1/notes/:id · DELETE /v1/notes/:id |
| Tags | GET /v1/tags · GET /v1/tags/:id · POST /v1/tags · PATCH /v1/tags/:id |
| Contact groups | GET /v1/contact-groups · GET /v1/contact-groups/:id · POST /v1/contact-groups · PATCH /v1/contact-groups/:id |
| Campaigns (WhatsApp) | GET /v1/campaigns · GET /v1/campaigns/:id · POST /v1/campaigns · PATCH /v1/campaigns/:id · POST /v1/campaigns/:id/execute |
| Templates (WhatsApp) | GET /v1/templates · GET /v1/templates/:id · POST /v1/templates/:id/send |
| Pipelines | GET /v1/pipelines |
| Deals | GET /v1/deals · GET /v1/deals/:id · POST /v1/deals (upsert) · PATCH /v1/deals/:id · POST /v1/deals/:id/stage · POST /v1/deals/:id/status |
| Products | GET /v1/products · GET /v1/products/:id · POST /v1/products (upsert) · PATCH /v1/products/:id |
| Payments | GET /v1/payments · GET /v1/payments/:id · POST /v1/payments (upsert) · PATCH /v1/payments/:id · POST /v1/payments/:id/cancel · POST /v1/payments/:id/entries/:entryId/mark · POST /v1/payments/:id/refund |
| Payment requests | GET /v1/payment-requests · GET /v1/payment-requests/:id · POST /v1/payment-requests (not idempotent) · POST /v1/payment-requests/:id/cancel |
| Orders | GET /v1/orders · GET /v1/orders/:id · POST /v1/orders (upsert) · POST /v1/orders/:id/refunds · POST /v1/orders/:id/mark-paid · POST /v1/orders/:id/cancel |
| Emails | POST /v1/emails |
| Email campaigns | GET /v1/email-campaigns · GET /v1/email-campaigns/:id · POST /v1/email-campaigns (upsert) · PATCH /v1/email-campaigns/:id · GET /v1/email-campaigns/:id/estimate · POST /v1/email-campaigns/:id/send · POST /v1/email-campaigns/:id/schedule · POST /v1/email-campaigns/:id/unschedule |
| Newsletters | GET /v1/newsletters · GET /v1/newsletters/:id · POST /v1/newsletters · GET /v1/newsletters/:id/issues · POST /v1/newsletters/:id/issues (upsert) |
| Newsletter issues | GET /v1/newsletter-issues/:id · PATCH /v1/newsletter-issues/:id · DELETE /v1/newsletter-issues/:id · POST /v1/newsletter-issues/:id/publish · POST /v1/newsletter-issues/:id/schedule · POST /v1/newsletter-issues/:id/unschedule |
| Suppressions | GET /v1/suppressions · POST /v1/suppressions (idempotent add) · DELETE /v1/suppressions/:id |
| Webhook endpoints | GET /v1/webhook-endpoints · POST /v1/webhook-endpoints · DELETE /v1/webhook-endpoints/:id |
| Meeting types | GET /v1/meeting-types · GET /v1/meeting-types/:id · GET /v1/meeting-types/:id/slots · GET /v1/meeting-types/:id/embed |
| Bookings | GET /v1/bookings · GET /v1/bookings/:id · POST /v1/bookings · POST /v1/bookings/:id/cancel · POST /v1/bookings/:id/reschedule · POST /v1/bookings/:id/reassign |
Conventions at a glance
- Success codes:
GET/PUT/PATCH→ 200;POST→ 201 (including action routes);POST /v1/campaigns/:id/executeand the email-campaign/newsletter-issue lifecycle routes (send/schedule/unschedule/publish) → 200;DELETE /v1/webhook-endpoints/:idandDELETE /v1/suppressions/:id→ 204;DELETE /v1/newsletter-issues/:id→ 200 with{"success": true}.POST /v1/emailsreturns 200 on an idempotent replay. - Errors: two body shapes — a structured
{"error": {"code", "message"}}envelope on the email/email-campaign/newsletter/webhook/consent/suppression/product APIs (and the campaign execute route), and the standard{"statusCode", "message", "error"}shape elsewhere, sometimes extended with anerror_codefield. See error responses. - Pagination:
{ "data", "total", "limit", "offset" }— default limit 50 (cap 500) on most lists; deals, payments, payment requests, orders, and the email-campaign/newsletter lists use default 25 (cap 100). All of those except orders reject malformedlimit/offsetwith 400; orders silently defaults/clamps them instead. The email-campaign and newsletter-issue lists reject an unknownstatusvalue with 400. - Rate limits: 100 requests/min per key (300/min for
POST /v1/emails); HTTP 429 withRetry-Afteron excess. - Idempotency: contacts upsert by phone/email; deals, payments, orders, email campaigns, and newsletter issues upsert by
external_reference(a campaign/issue replay updates content/fields while the record is still editable and never touchesstatus,scheduled_at, or an issue's number); products upsert byexternal_id; order refunds byexternal_refund_id; suppression adds are idempotent per address; emails require an explicitidempotency_key; booking creation is idempotent per slot+contact. Idempotent create responses carry a top-level booleanduplicate(falseon a fresh create,trueon an upsert/replay) — exceptPOST /v1/orders, which returns the same full-order body for both outcomes with noduplicatefield (see Orders).POST /v1/payment-requestsis not idempotent at all — a repeat POST mints a second payable link (see Payment Requests). - Deletion: the API never deletes customer data — contacts, deals, products, payments, orders, campaigns, tags, and contact groups have no DELETE routes (deactivate a product with
is_active: false). Only API-owned resources can be deleted: notes (DELETE /v1/notes/:id), webhook endpoints (DELETE /v1/webhook-endpoints/:id), suppressions (DELETE /v1/suppressions/:id— lifts a send-time block; deletes no contact data, resubscribes no one), and never-published newsletter issues (DELETE /v1/newsletter-issues/:id— published issues are never deletable).