Skip to main content
Every ConveYour API endpoint follows the same handful of conventions. Learn them once here and the whole API Reference reads predictably — no per-endpoint surprises.
New to the API? Start with Authentication to create a key and make your first request, then come back here for the shared behavior.

Base URL

All requests go to your organization’s subdomain:
Replace <your-subdomain> with your organization’s slug — the subdomain you sign in on. For example, if you sign in at acme.conveyour.com, your slug is acme. Every request carries the x-conveyour-token header — see Authentication.

Team scoping

If your org has Teams enabled, most endpoints accept a teams parameter that scopes the request to one or more teams. Teams control which contacts and resources are visible, so sending the wrong scope — or none at all — changes which records you get back. Pass teams as a query parameter on GET requests:
On requests that send a JSON body, you can include teams in the body instead:
string | array
One or more team IDs. Accepts a single value or an array. Read from the query string first, then from the JSON body.
Invalid team IDs are silently ignored. Every value must be a valid 24-character ObjectId — anything else is dropped without an error, and the request behaves as if that team had not been sent. A mistyped team ID therefore looks like a permissions or “missing data” bug rather than a bad request. Log the teams values you send and verify them against GET /api/teams.
Teams is a standard feature on ConveYour-enabled orgs. If your org is on a legacy program that does not use Teams, omit this parameter entirely. See Teams Introduction in the Help Center for how teams affect contact and resource visibility.

Response envelope

Every response — success or failure — uses the same three-field envelope:
Always branch on the status field, not just the HTTP code.

Errors

Errors use the same envelope with status: "failed", a message, and often a data object carrying field-level validation details.
HTTP status codes:
The HTTP code is not a reliable success signal. Error handling is inconsistent across the API: some endpoints return 400/404 on failure, but many return 200 with "status": "failed" in the body.Around a third of the documented endpoints return HTTP 200 on a failed request — 67 endpoints at the last full measurement — spanning Groups, Campaigns, Contacts, Custom Object Records, Fields, Files, Lessons, Messages, Notes, Org, Reports, Activity, Links, Snippets, Triggers and Users.

Pagination

There is no shared pagination model. Of the 57 list endpoints, 8 return a paginated envelope and 29 ignore page entirely, returning a flat array. The rest return a single object rather than a collection.Do not assume page works. Check the endpoint’s reference page.

Endpoints that paginate

Three return the full envelope, and they honour per_page — but only when you send page. Omit it and you get a bare flat array with no envelope keys at all ($page defaults to 0, and the envelope is built only if ($page > 0)): Four return a reduced envelope — no per_page, no has_more/has_less: And one returns results with no page metadata at all:
results does not imply pagination. GET /api/campaigns, GET /api/campaigns/default and GET /api/triggers return an object containing results alongside types and schemas — a composite payload, not a page. There is no page or count, and sending page changes nothing.

Everything else returns a flat array

29 list endpoints — including Tags, Teams, Snippets, Fields, Messages, Email templates, Groups, Lessons, Reports, Custom Objects, Links and Form submission collections — return the full set as an array whether or not you send page:

Contacts is limit-driven, not page-driven

GET /api/contacts decides its shape from limit, and the maximum page size is 50:
  • limit omitted, or limit >= 50 -> paginated. data has count, page, pages, results; message is "N contacts found".
  • limit below 50 -> not paginated. data has only results; message is "success".
Contacts always wraps its records in data.results — it never returns a bare array.
Because data carries an array on some endpoints and an object on others, check the type before iterating. Code that assumes one shape will break when it moves to another endpoint.

CSV export

Five endpoint families accept format=csv and return a CSV file instead of JSON. These are the only ones that implement it — sending format=csv anywhere else is ignored and you get the normal JSON envelope:
  • Contacts — GET /api/contacts
  • Custom Object Records — GET /api/custom/records
  • Reports — GET /api/reports
  • Message events — GET /api/messages/events (not GET /api/messages, which has no CSV support)
  • Shared lesson items — GET /api/lessons/{id}/shared/{item_uuid} (not GET /api/lessons)
One endpoint returns CSV whether or not you ask: GET /metrics/export always responds with a CSV file and never a JSON envelope.
The response is a file download (Content-Disposition: attachment), not the JSON envelope. CSV export is unpaginated — it returns the full matching set.

Usage limits

Some write endpoints are metered against your plan’s quotas (contacts, teams, and similar). When a quota is exceeded, the request returns 429 with an explanatory message:
This is a plan usage quota, not a per-second rate limit — retrying immediately won’t help. Upgrade the plan or free up capacity (e.g. archive contacts), then retry.
429 has three distinct causes, and they need different handling. The response tells you which one you hit:
The per-IP limit is applied before the request is processed, which is why its envelope is the odd one out — Failed with a capital F and no data key. If you branch on status === 'failed' with a lowercase comparison, this response will slip through your error handling.
Message sends are metered separately: POST /api/messages returns 429 against the sms or emails quota. That check happens after validation rather than up front, because the limit depends on how many contacts the message targets.

Dates and IDs

  • IDs are not all the same type. Most resources use an internal ID: a 24-character hex string, e.g. 64a1b2c3d4e5f6a7b8c9d0e1 — Tags, Snippets, Groups, Lessons, Campaigns, Triggers, Custom Objects, Custom Object Records and Form submission collections all do. These do not: Type your client’s ID fields accordingly — code that assumes a 24-character string will break on these, and code that assumes an integer will break everywhere else.
  • Some resources also expose a shorter public ID (pid) used for portal-facing and shareable links — see the public Exports and shared Reports endpoints, which are reachable with the pid alone and no token.
  • Timestamps are typically Unix seconds (integers) on stored records; some endpoints return ISO-8601 strings. The reference page notes the format per field.

Next steps

Authentication

Create a key and make your first request.

Liquid Syntax

Personalize messages and query data inside templates.