/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 aPOST /documentsorPOST /instagram/rulesbody. - An unknown key inside a
leadFormQuestionsitem onPOST /documentswithkind: form. - A repeated query parameter on
GET /tagsandGET /segments, and, onGET /instagram/rules, any repeated parameter other thanstatus. - A NUL character in the
qsearch parameter of any list endpoint.
qis trimmed and matched as plain text:%and_are no longer wildcards.GET /instagram/rules: alimitabove 100 is treated as 100 instead of a400, like the other lists.PATCH /documents/{id}: theETagheader value fromGETmay be sent as therevisionas 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 /postsandPOST /forms. UsePOST /documentswithkind: notion | post | form. - Removed:
GETandPATCH /documents/{id}/settings.GET /documents/{id}now returns the expiry, protection settings andrevision, andPATCH /documents/{id}takes the former settings fields and returns the same shape asGET. - Replaced:
isDrafton create is replaced bystatus(draft | live, defaultlive; a Notion document acceptslive).status: inactiveat create time is422 STATUS_NOT_SUPPORTED. Reusing anIdempotency-Keyfor a differentkindis409 IDEMPOTENCY_KEY_CONFLICT. - Removed:
POST /instagram/rules/{id}/pauseand.../resume. SendPATCH /instagram/rules/{id}withstatus: pausedorstatus: activeinstead, on its own:statuscombined with other fields is422 STATUS_CHANGE_MUST_BE_ALONE. - Removed:
DELETE /instagram/rules/{id}(now405).
Trimmed responses and lowercase Instagram values
Breaking.
GET /documentsandGET /documents/{id}:viewCountandleadCountremoved. Use the analytics endpoints.403 DOCUMENT_LIMIT_REACHEDno longer carriesdetails.422 PROTECTION_RULE_CONFLICTreturns the rule that refused the change indetails.rule.GET /products:sales,usageCountand thearchivedquery parameter removed (archivedis now a400; filter withstatus).GET /automations:triggerTypeis a documented list; a trigger outside it isother.GET /documents/{id}/analytics/channels: sources outside the documented channels are grouped asother, so channel views add up to the total.- Instagram rules use lowercase values:
statusiswaiting_for_post,active,scheduled,expiredorpaused;typeisstandardandtarget.typeisnext_post(both now optional). The old uppercase values are a400. - Instagram error codes renamed:
PRESET_RULE_EXISTSis nowNEXT_POST_RULE_EXISTS,RULE_PARKEDis nowBATCH_SEND_MISSEDandPLAN_UPGRADE_REQUIREDis nowPLAN_REQUIRED.
Publish drafts, protection settings, more analytics
- Publish a draft post or form by setting
status: liveonPATCH /documents/{id}. - Email protection fields on the same endpoint:
requireEmail,requireEmailVerification,allowedEmails,allowedDomains. A change that conflicts with the document’s setup is422 PROTECTION_RULE_CONFLICT. - Analytics:
compare=previouson document analytics, plusGET /documents/{id}/analytics/channels,GET /documents/{id}/analytics/funnel(forms) andGET /analytics/documents(rank your documents by views, unique visitors or leads). - Breaking:
GET /whoamireturns only{ "scopes": [...] }. - Date questions on forms are always allowed;
403 LEAD_FORM_DATE_QUESTION_DISABLEDis 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 (
limitdefault 20, up to 100). PUTandDELETE /contacts/{contactId}/tags/{tagName}add or remove one existing tag on a contact (new scopecontacts:tag).
Scopes, whoami and Instagram rules
- New scopes
documents:read,email:read,automations:read,products:readandcontacts:tag. Existing keys can gain scopes with Edit scopes in Settings → Developers. GET /whoamishows the scopes of the key you call with.- An account whose payment is past due gets
403 PAST_DUE_RESTRICTEDfrom every route until the payment method is updated. - Instagram DM rules: create, list, read and edit the account’s next-post rule (scopes
instagram:writeandinstagram:read).
Stricter request bodies, idempotency across key rotation
- Breaking: create requests reject unknown body fields with
400 VALIDATION_ERRORinstead of ignoring them. Idempotency-Keyvalues 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.