Skip to main content
Changes to /api/preview/* that affect API callers, newest first. Dates are UTC. The API is in preview and carries no compatibility guarantee: Breaking marks a change that can make an existing integration fail, and each one says what to change.
Group counts stop after 10 seconds
Behavior change: counting who a group’s rule matches now stops after about 10 seconds. This applies to POST /api/preview/segments, POST /api/preview/segments/preview and GET /api/preview/segments/{id}. A very heavy rule now returns 503 SERVICE_UNAVAILABLE with retryable: true. Simplify the rule (fewer or lighter conditions) or try again. When a create times out, nothing is created and the same Idempotency-Key can be sent again.
Create and read groups
New: you can now create and read groups through the API. POST /api/preview/segments creates a group from a rule and needs an Idempotency-Key and the new segments:write scope. POST /api/preview/segments/preview counts who a rule would match without saving anything, and GET /api/preview/segments/{id} returns one group with its rule and member count; both need only automations:read. They return counts, never contact data. Keys you created earlier do not have segments:write: add it with Edit scopes in Settings → Developers. GET /api/preview/segments is unchanged. See Create a group and Group conditions.
Create a tag
New: POST /api/preview/tags creates a tag by name. It needs the contacts:tag scope and no Idempotency-Key: calling again with the same name returns the existing tag (created: false), and a name that differs only by letter case or surrounding spaces is refused with 409 TAG_ALREADY_EXISTS. See Create a tag.
Request limits
Behavior change: the limit is now 60 requests per minute per account across /api/preview/*, up from 30. An account can also have at most 10 requests running at the same moment; the eleventh is refused with 429 TOO_MANY_CONCURRENT_REQUESTS and Retry-After: 1, and can be retried as is. See Errors.
Products report a pricing model
New field: each item of GET /api/preview/products now carries pricingModel, fixed or phased. A phased product changes price on a schedule, so it has no single price to report: its priceMinor is only the base price and is 0 when none is set. Read pricingModel before using priceMinor. Every existing field is unchanged.
Stricter input checks
Breaking: these requests used to be accepted, ignored or answered with a 500, and are now 400 VALIDATION_ERROR naming the field.
  • A NUL character (\u0000) in a property name of a POST /documents or POST /instagram/rules body.
  • An unknown key inside a leadFormQuestions item on POST /documents with kind: form.
  • A repeated query parameter on GET /tags and GET /segments, and, on GET /instagram/rules, any repeated parameter other than status.
  • A NUL character in the q search parameter of any list endpoint.
Behavior change:
  • q is trimmed and matched as plain text: % and _ are no longer wildcards.
  • GET /instagram/rules: a limit above 100 is treated as 100 instead of a 400, like the other lists.
  • PATCH /documents/{id}: the ETag header value from GET may be sent as the revision as is.
Document revision moves to the request body
Breaking: PATCH /api/preview/documents/{id} now takes the document’s revision in the revision field of the JSON body, not in the If-Match header. Send the revision from GET /api/preview/documents/{id} (or from the previous PATCH response). A request that carries If-Match or If-Unmodified-Since is refused with 400 VALIDATION_ERROR: remove the header.Behavior change: POST /api/preview/documents with kind: post and status: live (the default) now runs the same content checks as publishing a draft. A post with no content is 422 EMPTY_BODY, and one containing an email variable such as {recipient_name} is 422 UNSUPPORTED_VARIABLE. Create it with status: draft to skip the checks.
Create an Instagram rule paused
POST /api/preview/instagram/rules accepts status: active | paused (default active). status: paused together with schedule.batchSendAt is 422 BATCH_RULE_NOT_PAUSABLE.
Smaller surface: one documents resource, status via PATCH
Breaking. The API goes from 28 operations to 22.
  • Removed: POST /posts and POST /forms. Use POST /documents with kind: notion | post | form.
  • Removed: GET and PATCH /documents/{id}/settings. GET /documents/{id} now returns the expiry, protection settings and revision, and PATCH /documents/{id} takes the former settings fields and returns the same shape as GET.
  • Replaced: isDraft on create is replaced by status (draft | live, default live; a Notion document accepts live). status: inactive at create time is 422 STATUS_NOT_SUPPORTED. Reusing an Idempotency-Key for a different kind is 409 IDEMPOTENCY_KEY_CONFLICT.
  • Removed: POST /instagram/rules/{id}/pause and .../resume. Send PATCH /instagram/rules/{id} with status: paused or status: active instead, on its own: status combined with other fields is 422 STATUS_CHANGE_MUST_BE_ALONE.
  • Removed: DELETE /instagram/rules/{id} (now 405).
Trimmed responses and lowercase Instagram values
Breaking.
  • GET /documents and GET /documents/{id}: viewCount and leadCount removed. Use the analytics endpoints.
  • 403 DOCUMENT_LIMIT_REACHED no longer carries details.
  • 422 PROTECTION_RULE_CONFLICT returns the rule that refused the change in details.rule.
  • GET /products: sales, usageCount and the archived query parameter removed (archived is now a 400; filter with status).
  • GET /automations: triggerType is a documented list; a trigger outside it is other.
  • GET /documents/{id}/analytics/channels: sources outside the documented channels are grouped as other, so channel views add up to the total.
  • Instagram rules use lowercase values: status is waiting_for_post, active, scheduled, expired or paused; type is standard and target.type is next_post (both now optional). The old uppercase values are a 400.
  • Instagram error codes renamed: PRESET_RULE_EXISTS is now NEXT_POST_RULE_EXISTS, RULE_PARKED is now BATCH_SEND_MISSED and PLAN_UPGRADE_REQUIRED is now PLAN_REQUIRED.
Publish drafts, protection settings, more analytics
  • Publish a draft post or form by setting status: live on PATCH /documents/{id}.
  • Email protection fields on the same endpoint: requireEmail, requireEmailVerification, allowedEmails, allowedDomains. A change that conflicts with the document’s setup is 422 PROTECTION_RULE_CONFLICT.
  • Analytics: compare=previous on document analytics, plus GET /documents/{id}/analytics/channels, GET /documents/{id}/analytics/funnel (forms) and GET /analytics/documents (rank your documents by views, unique visitors or leads).
  • Breaking: GET /whoami returns only { "scopes": [...] }.
  • Date questions on forms are always allowed; 403 LEAD_FORM_DATE_QUESTION_DISABLED is no longer returned.
Read endpoints and contact tags
  • Ten read endpoints: documents (list and detail), document analytics, folders and courses, products, tags, groups, email broadcasts and their insights, and automations. Lists use cursor paging (limit default 20, up to 100).
  • PUT and DELETE /contacts/{contactId}/tags/{tagName} add or remove one existing tag on a contact (new scope contacts:tag).
Scopes, whoami and Instagram rules
  • New scopes documents:read, email:read, automations:read, products:read and contacts:tag. Existing keys can gain scopes with Edit scopes in Settings → Developers.
  • GET /whoami shows the scopes of the key you call with.
  • An account whose payment is past due gets 403 PAST_DUE_RESTRICTED from every route until the payment method is updated.
  • Instagram DM rules: create, list, read and edit the account’s next-post rule (scopes instagram:write and instagram:read).
Stricter request bodies, idempotency across key rotation
  • Breaking: create requests reject unknown body fields with 400 VALIDATION_ERROR instead of ignoring them.
  • Idempotency-Key values belong to the account, not to one API key, so a retry sent with a newly rotated key still replays the original response.
Preview launch
POST /api/preview/documents creates a document from a public Notion page, with a required Idempotency-Key and a per-account rate limit. API keys are managed in Settings → Developers.