{"openapi":"3.1.0","info":{"title":"Sending.dev API","version":"1.0.0","description":"Public REST API of Sending.dev (MCP-native orchestrator for email + WhatsApp + Telegram).\n\n## Authentication\nEvery request requires `Authorization: Bearer sk_...` (workspace API key). The `tenantId` is always derived from the key.\n\n## Idempotency\nSends require an `idempotencyKey` (min 8 characters) to prevent duplicates on retries.","contact":{"name":"Sending.dev","url":"https://sending.dev"}},"servers":[{"url":"https://sending.dev/api/v1","description":"Production"},{"url":"http://localhost:3000/api/v1","description":"Local development"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Emails","description":"Transactional email sending."},{"name":"Messages","description":"Multi-channel transactional sending (email, WhatsApp, Telegram)."},{"name":"Campaigns","description":"Broadcast campaigns to lists and segments."},{"name":"Contacts","description":"Contacts and per-channel identities."},{"name":"Lists","description":"Static contact lists."},{"name":"Tags","description":"Contact tags."},{"name":"Custom Fields","description":"Custom contact fields."},{"name":"Segments","description":"Dynamic segments (rule tree)."},{"name":"Events","description":"Behavioral event ingestion."},{"name":"Domains","description":"Sending domain onboarding and verification."},{"name":"Inboxes","description":"Email inboxes for AI agents."},{"name":"Email Rules","description":"Allow/block rules for inbound mail."},{"name":"Automations","description":"Automations (journey DAG)."},{"name":"Webhooks","description":"Signed webhooks for email events."},{"name":"UTM","description":"UTM touches, conversions and attribution."},{"name":"Integrations","description":"External connectors (PostHog, ...)."},{"name":"Imports","description":"Data import and migration (ActiveCampaign)."},{"name":"Usage","description":"Usage snapshot against the plan."}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Workspace API key in the `sk_...` format, passed as `Authorization: Bearer sk_...`. The `tenantId` is always derived from the key, never from a request parameter."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","example":"not_found"},"message":{"type":"string"}},"required":["error"],"description":"Generic error: snake_case code in `error`."},"ForbiddenError":{"type":"object","properties":{"error":{"type":"string","enum":["forbidden"]},"need":{"type":"string","example":"contacts:write"}},"required":["error"],"description":"Insufficient scope; `need` names the missing scope."},"ValidationError":{"type":"object","properties":{"error":{"type":"object","properties":{"formErrors":{"type":"array","items":{"type":"string"}},"fieldErrors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}},"required":["formErrors","fieldErrors"]}},"required":["error"],"description":"Zod validation failed: shape of `ZodError.flatten()`."},"QuotaError":{"type":"object","properties":{"error":{"type":"string","example":"quota_exceeded"},"message":{"type":"string"},"resource":{"type":"string"},"limit":{"type":"number"},"used":{"type":"number"},"remaining":{"type":"number"},"plan":{"type":"string"}},"required":["error"],"description":"Plan limit exceeded (entitlement)."},"Ok":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]},"Created":{"type":"object","properties":{"id":{"type":"string","format":"uuid"}},"required":["id"]},"SendResult":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","example":"queued"},"idempotencyKey":{"type":"string"}},"required":["status"]},"BatchItemResult":{"type":"object","properties":{"index":{"type":"integer","description":"Position in the request's `emails` array."},"status":{"type":"string","enum":["accepted","failed"]},"id":{"type":"string"},"duplicate":{"type":"boolean","description":"Already accepted with this idempotencyKey: not an error."},"droppedRecipients":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"reason":{"type":"string"}},"required":["address","reason"]},"description":"Copies excluded because they are suppressed."},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code"]}},"required":["index","status"]},"SendEmailBatchResult":{"type":"object","properties":{"accepted":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/BatchItemResult"}}},"required":["accepted","failed","results"]},"Attachment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"filename":{"type":"string","example":"invoice-2026-07.pdf"},"contentType":{"type":"string","example":"application/pdf"},"size":{"type":"integer","description":"File size in bytes."},"status":{"type":"string","enum":["pending","ready"],"description":"`pending` until the signed upload is confirmed."},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","filename","contentType","size","status","createdAt"]},"AttachmentEnvelope":{"type":"object","properties":{"attachment":{"$ref":"#/components/schemas/Attachment"}},"required":["attachment"]},"AttachmentList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Attachment"}}},"required":["data"]},"AttachmentUpload":{"type":"object","properties":{"attachment":{"$ref":"#/components/schemas/Attachment"},"uploadUrl":{"type":"string","description":"Signed URL to PUT the file to, with the same declared Content-Type and Content-Length."},"expiresIn":{"type":"integer","description":"Validity of the uploadUrl, in seconds."}},"required":["attachment","uploadUrl","expiresIn"]},"AttachmentDownload":{"type":"object","properties":{"attachment":{"$ref":"#/components/schemas/Attachment"},"downloadUrl":{"type":"string","description":"Signed download URL (15 minutes)."}},"required":["attachment","downloadUrl"]},"AttachmentDeleted":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"}},"required":["deleted","id"]},"MessageEvent":{"type":"object","properties":{"type":{"type":"string","example":"delivered"},"classification":{"type":["string","null"],"description":"human | machine | prefetch | bot: only `human` counts as engagement."},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"linkUrl":{"type":["string","null"],"description":"Clicks only: the original destination."},"linkId":{"type":["string","null"],"description":"Link id inside the email (block id, or positional `l0`, `l1`...)."},"linkRole":{"type":["string","null"],"description":"Role of the clicked link: logo | image | cta | text | social | video | chrome. `null` if not classified."}},"required":["type"]},"MessageEngagement":{"type":"object","properties":{"opensHuman":{"type":"integer"},"opensMachine":{"type":"integer","description":"Non-human opens (Apple MPP, Gmail proxy, scanners): never a KPI."},"clicks":{"type":"integer","description":"Human clicks, on any link."},"contentClicks":{"type":"integer","description":"Human clicks on content: excludes logo, images, domain chrome and social links."},"lastLinkUrl":{"type":["string","null"]},"lastLinkRole":{"type":["string","null"]},"links":{"type":"array","items":{"type":"string"},"description":"Distinct clicked URLs (raw)."},"unsubscribed":{"type":"boolean"},"bounced":{"type":"boolean"},"lastEventAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["opensHuman","opensMachine","clicks","contentClicks","lastLinkUrl","lastLinkRole","links","unsubscribed","bounced","lastEventAt"]},"EmailClickedLink":{"type":"object","properties":{"url":{"type":"string"},"canonicalUrl":{"type":"string","description":"Without utm_* and trailing slash: the grouping key."},"role":{"type":["string","null"]},"isContent":{"type":"boolean","description":"`false` for logo, images, header/footer and social links: not interest in the text."},"count":{"type":"integer"},"lastAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["url","canonicalUrl","role","isContent","count","lastAt"]},"MessageStatus":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","example":"sent"},"channel":{"type":"string"},"to":{"type":["string","null"]},"toAddresses":{"type":"array","items":{"type":"string"}},"from":{"type":["string","null"]},"subject":{"type":["string","null"]},"provider":{"type":["string","null"]},"providerMessageId":{"type":["string","null"]},"idempotencyKey":{"type":"string"},"kind":{"type":"string","enum":["transactional","campaign","automation"],"description":"Origin of the send."},"campaignId":{"type":["string","null"],"format":"uuid"},"enrollmentId":{"type":["string","null"],"format":"uuid"},"contactId":{"type":["string","null"],"format":"uuid"},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"filename":{"type":"string"},"contentType":{"type":"string"},"size":{"type":"integer"}},"required":["id","filename","contentType","size"]}},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"engagement":{"$ref":"#/components/schemas/MessageEngagement"},"links":{"type":"array","items":{"$ref":"#/components/schemas/EmailClickedLink"},"description":"Clicked links (human clicks), grouped by canonical URL."},"events":{"type":"array","items":{"$ref":"#/components/schemas/MessageEvent"}}},"required":["id","status"]},"EmailListRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"to":{"type":["string","null"]},"from":{"type":["string","null"]},"subject":{"type":["string","null"]},"kind":{"type":"string","enum":["transactional","campaign","automation"],"description":"Origin of the send."},"campaignId":{"type":["string","null"],"format":"uuid"},"enrollmentId":{"type":["string","null"],"format":"uuid"},"contactId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"engagement":{"$ref":"#/components/schemas/MessageEngagement"}},"required":["id","status","to","from","subject","createdAt","engagement"]},"EmailList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailListRow"}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["data","total","limit","offset"]},"LinkStat":{"type":"object","properties":{"url":{"type":"string","description":"The most clicked raw variant, the recognizable one."},"canonicalUrl":{"type":"string"},"role":{"type":["string","null"],"description":"logo | image | cta | text | social | video | chrome, or null if not classified."},"isContent":{"type":"boolean"},"uniqueClicks":{"type":"integer","description":"Distinct messages with a human click."},"totalClicks":{"type":"integer"},"machineClicks":{"type":"integer","description":"Scanner and proxy clicks: reported, not counted."},"firstClickAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"lastClickAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"share":{"type":["number","null"],"description":"Share 0-100 of the scope's unique human clicks."}},"required":["url","canonicalUrl","role","isContent","uniqueClicks","totalClicks","machineClicks","firstClickAt","lastClickAt","share"]},"ConversionRow":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"source":{"type":"string"},"valueCents":{"type":"integer"},"currency":{"type":"string"},"occurredAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"contactId":{"type":["string","null"],"format":"uuid"},"contactEmail":{"type":["string","null"]},"touchUrl":{"type":["string","null"],"description":"Clicked link (canonical) it is attributed to."},"touchAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"nodeId":{"type":["string","null"]},"secondsFromTouch":{"type":["integer","null"]}},"required":["id","name","source","valueCents","currency","occurredAt","contactId","contactEmail","touchUrl","touchAt","nodeId","secondsFromTouch"]},"EntityConversions":{"type":"object","properties":{"attribution":{"type":"string","enum":["first","last"]},"lookbackDays":{"type":"integer"},"total":{"type":"integer"},"contacts":{"type":"integer"},"revenueCents":{"type":"integer"},"currency":{"type":["string","null"],"description":"`null` with mixed currencies: the total cannot be summed."},"byName":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"conversions":{"type":"integer"},"revenueCents":{"type":"integer"}},"required":["name","conversions","revenueCents"]}},"byLink":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"conversions":{"type":"integer"},"contacts":{"type":"integer"},"revenueCents":{"type":"integer"}},"required":["url","conversions","contacts","revenueCents"]}},"recent":{"type":"array","items":{"$ref":"#/components/schemas/ConversionRow"},"description":"The latest 50."}},"required":["attribution","lookbackDays","total","contacts","revenueCents","currency","byName","byLink","recent"]},"RevenueSummary":{"type":"object","properties":{"orders":{"type":"integer","description":"Attributed orders, cancelled excluded. A count across all currencies."},"revenue":{"type":["number","null"],"description":"Gross total of the attributed orders; `null` with more than one currency (never summed)."},"refunded":{"type":["number","null"],"description":"Refunds on those orders, declared apart and never subtracted from `revenue`."},"currency":{"type":["string","null"],"description":"The only currency involved; `null` with zero orders or more than one currency."},"averageOrderValue":{"type":["number","null"]},"revenuePerRecipient":{"type":["number","null"],"description":"`revenue` / `delivered`; `null` with no orders, no deliveries or more than one currency."},"byCurrency":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string"},"revenue":{"type":"number"},"refunded":{"type":"number"},"orders":{"type":"integer"},"averageOrderValue":{"type":["number","null"]}},"required":["currency","revenue","refunded","orders","averageOrderValue"]},"description":"One row per currency, highest revenue first: the numbers to read when there is more than one."}},"required":["orders","revenue","refunded","currency","averageOrderValue","revenuePerRecipient","byCurrency"]},"RevenueReport":{"allOf":[{"$ref":"#/components/schemas/RevenueSummary"},{"type":"object","properties":{"attribution":{"type":"object","properties":{"model":{"type":"string","enum":["last_content_click"]},"windowDays":{"type":"integer","description":"Workspace attribution window: the last content click within these days before the order."}},"required":["model","windowDays"]}},"required":["attribution"]}],"description":"Store and API orders attributed to the messages: the last click on the content (not the logo, never an open) within `attribution.windowDays` days before the order. Test runs and cancelled orders excluded."},"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"attributes":{"type":"object","additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id"]},"ContactList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}},"required":["data","total","page","pageSize"]},"ContactIdentity":{"type":"object","properties":{"channel":{"type":"string","example":"email"},"address":{"type":"string"},"consent":{"type":"string","example":"opted_in"},"verified":{"type":"boolean"},"isPrimary":{"type":"boolean"}},"required":["channel","address","consent"]},"ContactDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"attributes":{"type":"object","additionalProperties":{}},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"identities":{"type":"array","items":{"$ref":"#/components/schemas/ContactIdentity"}},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]}},"lists":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]}}},"required":["id","identities","tags","lists"]},"ContactUpserted":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"created":{"type":"boolean"},"identitiesAdded":{"type":"integer"},"warnings":{"type":"array","items":{"type":"string"}}},"required":["id","created","identitiesAdded"]},"NamedUpserted":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"created":{"type":"boolean"}},"required":["id","name","created"]},"Tag":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"contacts":{"type":"integer"}},"required":["id","name"]},"TagList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}}},"required":["data"]},"TemplateSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"channel":{"type":"string","enum":["email","whatsapp","telegram"],"description":"Derived primary channel (email wins when enabled)."},"channels":{"type":"array","items":{"type":"string","enum":["email","whatsapp","telegram"]}},"format":{"type":"string","enum":["markdown","html","text","blocks"]},"subject":{"type":["string","null"]},"variables":{"type":"array","items":{"type":"string"},"description":"{{...}} variables found in the content. Derived, not declared."},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","name","channel","channels","format","subject","variables"]},"Template":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"channel":{"type":"string","enum":["email","whatsapp","telegram"],"description":"Derived primary channel (email wins when enabled)."},"channels":{"type":"array","items":{"type":"string","enum":["email","whatsapp","telegram"]}},"format":{"type":"string","enum":["markdown","html","text","blocks"]},"subject":{"type":["string","null"]},"variables":{"type":"array","items":{"type":"string"},"description":"{{...}} variables found in the content. Derived, not declared."},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"updatedAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"body":{"type":"string"},"channelText":{"type":["object","null"],"properties":{"whatsapp":{"type":"string"},"telegram":{"type":"string"}},"description":"Text overrides for chat channels."}},"required":["id","name","channel","channels","format","subject","variables","body","channelText"]},"TemplateList":{"type":"object","properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/TemplateSummary"}}},"required":["templates"]},"List":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"contacts":{"type":"integer"}},"required":["id","name"]},"ListList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/List"}}},"required":["data"]},"CustomField":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"options":{"type":["array","null"],"items":{"type":"string"}},"groupName":{"type":["string","null"]},"isSystem":{"type":"boolean"},"archived":{"type":"boolean"}},"required":["id","key","label","type"]},"CustomFieldList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomField"}}},"required":["data"]},"Segment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"kind":{"type":"string"},"definition":{},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","name"]},"SegmentList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Segment"}}},"required":["data"]},"SegmentPreview":{"type":"object","properties":{"count":{"type":"integer"},"sample":{"type":"array","items":{"type":"object","properties":{"name":{"type":["string","null"]},"email":{"type":["string","null"]}},"required":["name","email"]}}},"required":["count","sample"]},"CampaignMetricsSummary":{"type":"object","properties":{"recipients":{"type":"integer"},"delivered":{"type":"integer"},"uniqueOpens":{"type":"integer","description":"Messages with at least one human open."},"uniqueClicks":{"type":"integer"},"contentClicks":{"type":"integer"},"unsubscribes":{"type":"integer"},"hardBounces":{"type":"integer"},"softBounces":{"type":"integer"},"openRate":{"type":["number","null"]},"clickRate":{"type":["number","null"]},"clickToOpenRate":{"type":["number","null"]},"unsubscribeRate":{"type":["number","null"]},"bounceRate":{"type":["number","null"]}},"required":["recipients","delivered","uniqueOpens","uniqueClicks","contentClicks","unsubscribes","hardBounces","softBounces","openRate","clickRate","clickToOpenRate","unsubscribeRate","bounceRate"]},"Campaign":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"listId":{"type":["string","null"],"format":"uuid"},"segmentId":{"type":["string","null"],"format":"uuid"},"scheduledAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"completedAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"recipientCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"metrics":{"allOf":[{"$ref":"#/components/schemas/CampaignMetricsSummary"},{"type":["object","null"],"description":"Only with `?metrics=1`; `null` for campaigns without messages."}]}},"required":["id","name","status"]},"CampaignList":{"type":"object","properties":{"campaigns":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}}},"required":["campaigns"]},"CampaignEstimate":{"type":"object","properties":{"estimate":{"type":"object","properties":{"listMembers":{"type":"integer","description":"Members of the list or segment."},"recipients":{"type":"integer","description":"Actual recipients (excluding suppressed/unsubscribed)."},"excluded":{"type":"integer"},"sample":{"type":"array","items":{"type":"string"},"description":"Up to 5 sample addresses."}},"required":["listMembers","recipients","excluded","sample"]},"confirmationToken":{"type":"string","description":"Only present on POST /campaigns/:id/estimate: pass it to send for an immediate send or one within 5 minutes."}},"required":["estimate"]},"CampaignSendResult":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"scheduledAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"recipients":{"type":"integer"}},"required":["id","status"]},"DnsRecord":{"type":"object","properties":{"type":{"type":"string"},"name":{"type":"string"},"value":{"type":"string"}},"required":["type","name","value"]},"Domain":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"region":{"type":"string"},"inboundEnabled":{"type":"boolean"},"defaultFromName":{"type":["string","null"]},"defaultFromAddress":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","name","status"]},"DomainList":{"type":"object","properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}}},"required":["domains"]},"DomainCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"dnsRecords":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}},"required":["id","status","dnsRecords"]},"DomainVerify":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"detail":{"type":"string"}},"required":["id","status"]},"DomainInbound":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"inboundEnabled":{"type":"boolean"},"mx":{"type":"string"}},"required":["id","inboundEnabled"]},"Inbox":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"localPart":{"type":"string"},"address":{"type":"string"},"displayName":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id"]},"InboxList":{"type":"object","properties":{"inboxes":{"type":"array","items":{"$ref":"#/components/schemas/Inbox"}}},"required":["inboxes"]},"InboxEnvelope":{"type":"object","properties":{"inbox":{"$ref":"#/components/schemas/Inbox"}},"required":["inbox"]},"EmailMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"direction":{"type":"string"},"subject":{"type":"string"},"from":{"type":"string"},"to":{"type":"array","items":{"type":"string"}},"html":{"type":"string"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id"]},"Thread":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"subject":{"type":"string"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id"]},"ThreadList":{"type":"object","properties":{"folder":{"type":"string"},"threads":{"type":"array","items":{"$ref":"#/components/schemas/Thread"}}},"required":["folder","threads"]},"ThreadDetail":{"type":"object","properties":{"thread":{"$ref":"#/components/schemas/Thread"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/EmailMessage"}}},"required":["thread","messages"]},"DraftCreated":{"type":"object","properties":{"draftId":{"type":"string","format":"uuid"},"threadId":{"type":"string","format":"uuid"}},"required":["draftId","threadId"]},"InboxMetrics":{"type":"object","properties":{"kpis":{"type":"object","additionalProperties":{}},"daily":{"type":"array","items":{}},"perInbox":{"type":"array","items":{}}}},"EmailRule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"action":{"type":"string"},"matchType":{"type":"string"},"value":{"type":"string"},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","action","matchType","value"]},"EmailRuleList":{"type":"object","properties":{"rules":{"type":"array","items":{"$ref":"#/components/schemas/EmailRule"}}},"required":["rules"]},"EmailRuleEnvelope":{"type":"object","properties":{"rule":{"$ref":"#/components/schemas/EmailRule"}},"required":["rule"]},"AutomationCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"versionId":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","versionId","status"]},"AutomationStatus":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]},"AutomationSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string"},"trigger":{"type":["object","null"],"properties":{"event":{"type":"string"},"match":{"type":"object","additionalProperties":{"type":"string"}}},"required":["event"]},"triggers":{"type":"array","items":{"type":"object","properties":{"event":{"type":"string"},"match":{"type":"object","additionalProperties":{"type":"string"}}},"required":["event"]}},"version":{"type":["integer","null"]},"activeEnrollments":{"type":"integer"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","name","status"]},"AutomationList":{"type":"object","properties":{"automations":{"type":"array","items":{"$ref":"#/components/schemas/AutomationSummary"}}},"required":["automations"]},"AutomationEnrollRequest":{"type":"object","properties":{"listId":{"type":"string","format":"uuid"},"segmentId":{"type":"string","format":"uuid"},"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":1000}}},"AutomationEnrollQueued":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"queued":{"type":"boolean"},"audience":{"type":"string"}},"required":["id","queued","audience"]},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":["string","null"]},"events":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","url"]},"WebhookList":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}},"required":["webhooks"]},"WebhookEnvelope":{"type":"object","properties":{"webhook":{"$ref":"#/components/schemas/Webhook"}},"required":["webhook"]},"WebhookCreated":{"type":"object","properties":{"webhook":{"$ref":"#/components/schemas/Webhook"},"secret":{"type":"string"}},"required":["webhook","secret"]},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"event":{"type":"string"},"status":{"type":"string"},"statusCode":{"type":["integer","null"]},"createdAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id"]},"WebhookDeliveryList":{"type":"object","properties":{"deliveries":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}},"required":["deliveries"]},"UtmTouch":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":["string","null"]},"campaign":{"type":["string","null"]},"medium":{"type":["string","null"]},"contactId":{"type":["string","null"],"format":"uuid"},"occurredAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}}},"UtmTouchList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UtmTouch"}},"total":{"type":"integer"},"page":{"type":"integer"},"pageSize":{"type":"integer"}},"required":["data","total"]},"UtmSummary":{"type":"object","properties":{"attribution":{"type":"string"},"rows":{"type":"array","items":{}},"unattributed":{"type":"integer"}},"required":["attribution","rows"]},"UtmConversion":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"valueCents":{"type":["integer","null"]},"contactId":{"type":["string","null"],"format":"uuid"},"occurredAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}}},"UtmConversionList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/UtmConversion"}},"total":{"type":"integer"}},"required":["data","total"]},"ContactConversion":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"source":{"type":"string"},"valueCents":{"type":"integer"},"currency":{"type":"string"},"occurredAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"firstTouchAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"lastTouchAt":{"type":["string","null"],"format":"date-time","example":"2026-06-30T12:00:00.000Z"},"timeToConvertSeconds":{"type":["integer","null"],"description":"Seconds from first touch to conversion."},"touchpoints":{"type":"integer","description":"Touches in the lookback window before the conversion."},"utmSource":{"type":["string","null"]},"utmMedium":{"type":["string","null"]},"utmCampaign":{"type":["string","null"]},"attributedKind":{"type":["string","null"],"enum":["campaign","automation","transactional","event","posthog"],"description":"Type of the attributed touch: campaign/automation (marketing) vs transactional."}},"required":["id","name","source","valueCents","currency","occurredAt"]},"ContactConversionList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContactConversion"}},"totals":{"type":"object","properties":{"conversions":{"type":"integer"},"revenueCents":{"type":"integer"}},"required":["conversions","revenueCents"]},"lookbackDays":{"type":"integer"}},"required":["data","totals"]},"ContactJourneyMessageEvents":{"type":"object","properties":{"openedHuman":{"type":"integer"},"openedMachine":{"type":"integer","description":"Non-human opens (Apple MPP, Gmail proxy, scanners)."},"clicks":{"type":"integer"},"contentClicks":{"type":"integer","description":"Clicks on content: excludes logo, domain chrome and social links."},"links":{"type":"array","items":{"type":"string"},"description":"Clicked URLs, canonical (without utm_*) and deduplicated."},"lastLinkUrl":{"type":["string","null"]},"bounced":{"type":"boolean"},"unsubscribed":{"type":"boolean"}},"required":["openedHuman","openedMachine","clicks","contentClicks","links","lastLinkUrl","bounced","unsubscribed"]},"ContactJourneyEntry":{"type":"object","properties":{"type":{"type":"string","enum":["message_sent","email_received","touch","conversion","note","enrollment"],"description":"Timeline entry type."},"at":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"kind":{"type":"string","description":"Origin of messages and touches: transactional | campaign | automation | event | posthog."},"subject":{"type":["string","null"]},"to":{"type":"object","properties":{"address":{"type":"string"},"displayName":{"type":"string"},"domainKind":{"type":"string"}},"required":["address","displayName","domainKind"],"description":"Destination agent inbox (email_received only)."},"name":{"type":"string"},"valueCents":{"type":"integer"},"events":{"allOf":[{"$ref":"#/components/schemas/ContactJourneyMessageEvents"},{"description":"Summary of the message's events (message_sent via email only)."}]},"phase":{"type":"string","enum":["entered","exited","current"],"description":"Enrollment only: entry into the automation, exit, or the node the contact is currently on."},"automationId":{"type":"string","format":"uuid"},"automationName":{"type":"string"},"status":{"type":"string"},"nodeId":{"type":["string","null"]},"nodeLabel":{"type":["string","null"],"description":"Email subject for message steps, otherwise the action name."},"nodeType":{"type":["string","null"]},"exitReason":{"type":["string","null"]},"test":{"type":"boolean"}},"required":["type","at"]},"ContactJourney":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContactJourneyEntry"}}},"required":["data"]},"UtmConversionStats":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"conversions":{"type":"integer"},"contacts":{"type":"integer"},"revenueCents":{"type":"integer"},"avgTimeToConvertSeconds":{"type":["integer","null"]},"avgTouchpoints":{"type":["number","null"]},"firstAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"},"lastAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["name","conversions","contacts","revenueCents"]}}},"required":["data"]},"CommerceProduct":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"externalId":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"imageUrl":{"type":"string"},"price":{"type":["string","null"]},"currency":{"type":"string"},"url":{"type":"string"},"source":{"type":"string"},"updatedAt":{"type":"string","format":"date-time","example":"2026-06-30T12:00:00.000Z"}},"required":["id","externalId","title"]},"CommerceProductList":{"type":"object","properties":{"products":{"type":"array","items":{"$ref":"#/components/schemas/CommerceProduct"}}},"required":["products"]},"CommerceUpsertResult":{"type":"object","properties":{"upserted":{"type":"integer"}},"required":["upserted"]},"CommerceDeleteResult":{"type":"object","properties":{"deleted":{"type":"integer"}},"required":["deleted"]},"CommerceAccepted":{"type":"object","properties":{"status":{"type":"string","enum":["accepted"]}},"required":["status"]},"CommerceOrder":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"source":{"type":"string","enum":["store","api"],"description":"`store`: a connected store; `api`: `POST /commerce/orders`."},"connectionId":{"type":["string","null"],"format":"uuid"},"externalId":{"type":"string"},"contactId":{"type":["string","null"],"format":"uuid"},"status":{"type":"string","enum":["placed","fulfilled","cancelled"],"description":"API orders are always `placed`: the API knows no fulfillment or cancellation."},"total":{"type":"number"},"refunded":{"type":"number"},"currency":{"type":"string"},"placedAt":{"type":"string","format":"date-time"},"attributedMessageId":{"type":["string","null"],"description":"Marketing message with the last content click in the attribution window before the order; `null` if none."},"attributedTo":{"type":["object","null"],"properties":{"campaignId":{"type":["string","null"],"format":"uuid"},"automationId":{"type":["string","null"],"format":"uuid"}},"required":["campaignId","automationId"]},"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"quantity":{"type":"number"},"price":{"type":["number","null"]},"productId":{"type":["string","null"]}},"required":["title","quantity","price","productId"]}}},"required":["id","source","connectionId","externalId","contactId","status","total","refunded","currency","placedAt","attributedMessageId","attributedTo","items"]},"CommerceOrderList":{"type":"object","properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/CommerceOrder"}},"nextCursor":{"type":["string","null"]}},"required":["orders","nextCursor"]},"ContactCommerce":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"ordersCount":{"type":"integer","description":"Orders, cancelled excluded, all currencies."},"totalSpent":{"type":["number","null"],"description":"Gross spent; `null` with more than one currency (never summed)."},"currency":{"type":["string","null"]},"averageOrderValue":{"type":["number","null"]},"byCurrency":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string"},"revenue":{"type":"number"},"refunded":{"type":"number"},"orders":{"type":"integer"},"averageOrderValue":{"type":["number","null"]}},"required":["currency","revenue","refunded","orders","averageOrderValue"]},"description":"One row per currency, highest revenue first: the numbers to read when there is more than one."},"firstOrderAt":{"type":["string","null"],"format":"date-time"},"lastOrderAt":{"type":["string","null"],"format":"date-time"},"recentOrders":{"type":"array","items":{"$ref":"#/components/schemas/CommerceOrder"},"description":"Last 10 orders, cancelled included."}},"required":["contactId","ordersCount","totalSpent","currency","averageOrderValue","byCurrency","firstOrderAt","lastOrderAt","recentOrders"]},"PosthogSyncResult":{"type":"object","properties":{"imported":{"type":"integer"}}},"UsageSnapshot":{"type":"object","properties":{"plan":{"type":"string"},"messages":{"type":"object","additionalProperties":{}}}},"ImportJobResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string"},"status":{"type":"string","enum":["pending","running","completed","failed","canceled"]},"entities":{"type":"object","additionalProperties":{"type":"boolean"}},"options":{"type":"object","additionalProperties":{}},"phase":{"type":["string","null"]},"progress":{"type":"object","additionalProperties":{}},"error":{"type":["string","null"]},"startedAt":{"type":["string","null"],"format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","provider","status","entities","options","phase","progress","error","startedAt","finishedAt","createdAt"]},"ListImportJobsResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string"},"status":{"type":"string","enum":["pending","running","completed","failed","canceled"]},"entities":{"type":"object","additionalProperties":{"type":"boolean"}},"options":{"type":"object","additionalProperties":{}},"phase":{"type":["string","null"]},"progress":{"type":"object","additionalProperties":{}},"error":{"type":["string","null"]},"startedAt":{"type":["string","null"],"format":"date-time"},"finishedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","provider","status","entities","options","phase","progress","error","startedAt","finishedAt","createdAt"]}}},"required":["data"]},"SendEmailInput":{"type":"object","properties":{"to":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Email recipients (To header). One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"from":{"type":"string"},"subject":{"type":"string","minLength":1},"html":{"type":"string"},"text":{"type":"string","description":"Plain-text body. With html it is the multipart alternative; alone (no html, no templateId) it sends a text-only email: no open tracking, links left as written."},"replyTo":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10}],"description":"Reply-To: one or more addresses ('a@b.com', 'Name <a@b.com>', comma-separated or an array, at most 10). A plain \"Reply\" goes to all of them."},"cc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Visible copies (Cc header). One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"bcc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Hidden copies, in no header. One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"templateId":{"type":"string","minLength":1},"variables":{"type":"object","additionalProperties":{}},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Id of an attachment already uploaded with POST /v1/attachments."},"filename":{"type":"string","minLength":1,"maxLength":255,"description":"File name shown to the recipient. Required with `content` or `url`."},"content":{"type":"string","minLength":1,"description":"File content in base64, without the `data:` prefix."},"url":{"type":"string","format":"uri","description":"Public https URL to download the file from (private hosts are blocked)."},"contentType":{"type":"string","minLength":3,"maxLength":255,"description":"Content-Type override; when absent, it is inferred from the file name."},"contentId":{"type":"string","minLength":1,"maxLength":200,"description":"Content-ID for inline images referenced in the HTML as `cid:<value>`: the attachment becomes `inline` instead of appearing at the end of the message."}}},"maxItems":20,"description":"Email attachments (max 20, 10 MB each, 25 MB in total). For each item provide exactly one source: `id`, `content` (base64) or `url`."},"idempotencyKey":{"type":"string","minLength":8},"disableTracking":{"type":"boolean","default":false},"disableUtm":{"type":"boolean","default":false}},"required":["to","from","idempotencyKey"]},"SendEmailBatchInput":{"type":"object","properties":{"emails":{"type":"array","items":{"type":"object","properties":{"to":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Email recipients (To header). One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"from":{"type":"string"},"subject":{"type":"string","minLength":1},"html":{"type":"string"},"text":{"type":"string","description":"Plain-text body. With html it is the multipart alternative; alone (no html, no templateId) it sends a text-only email: no open tracking, links left as written."},"replyTo":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10}],"description":"Reply-To: one or more addresses ('a@b.com', 'Name <a@b.com>', comma-separated or an array, at most 10). A plain \"Reply\" goes to all of them."},"cc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Visible copies (Cc header). One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"bcc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Hidden copies, in no header. One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"templateId":{"type":"string","minLength":1},"variables":{"type":"object","additionalProperties":{}},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Id of an attachment already uploaded with POST /v1/attachments."},"filename":{"type":"string","minLength":1,"maxLength":255,"description":"File name shown to the recipient. Required with `content` or `url`."},"content":{"type":"string","minLength":1,"description":"File content in base64, without the `data:` prefix."},"url":{"type":"string","format":"uri","description":"Public https URL to download the file from (private hosts are blocked)."},"contentType":{"type":"string","minLength":3,"maxLength":255,"description":"Content-Type override; when absent, it is inferred from the file name."},"contentId":{"type":"string","minLength":1,"maxLength":200,"description":"Content-ID for inline images referenced in the HTML as `cid:<value>`: the attachment becomes `inline` instead of appearing at the end of the message."}}},"maxItems":20,"description":"Email attachments (max 20, 10 MB each, 25 MB in total). For each item provide exactly one source: `id`, `content` (base64) or `url`."},"idempotencyKey":{"type":"string","minLength":8},"disableTracking":{"type":"boolean","default":false},"disableUtm":{"type":"boolean","default":false}},"required":["to","from","idempotencyKey"]},"minItems":1,"maxItems":100,"description":"From 1 to 100 sends. Each item is a complete SendEmailInput."}},"required":["emails"]},"CreateAttachmentInput":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255,"description":"File name shown to the recipient."},"contentType":{"type":"string","minLength":3,"maxLength":255,"description":"When absent, it is inferred from the file name."},"size":{"type":"integer","exclusiveMinimum":0,"maximum":10485760,"description":"File size in bytes: required in signed upload mode (without `content`)."},"content":{"type":"string","minLength":1,"description":"Base64 content for an immediate upload, without the `data:` prefix."}},"required":["filename"]},"SendMessageInput":{"oneOf":[{"type":"object","properties":{"channel":{"type":"string","enum":["email"]},"to":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"Email recipients (To header). One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"from":{"type":"string"},"subject":{"type":"string","minLength":1},"html":{"type":"string"},"text":{"type":"string"},"replyTo":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10}],"description":"Reply-To: one or more addresses ('a@b.com', 'Name <a@b.com>', comma-separated or an array, at most 10). A plain \"Reply\" goes to all of them."},"cc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"bcc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"templateId":{"type":"string","minLength":1},"variables":{"type":"object","additionalProperties":{}},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Id of an attachment already uploaded with POST /v1/attachments."},"filename":{"type":"string","minLength":1,"maxLength":255,"description":"File name shown to the recipient. Required with `content` or `url`."},"content":{"type":"string","minLength":1,"description":"File content in base64, without the `data:` prefix."},"url":{"type":"string","format":"uri","description":"Public https URL to download the file from (private hosts are blocked)."},"contentType":{"type":"string","minLength":3,"maxLength":255,"description":"Content-Type override; when absent, it is inferred from the file name."},"contentId":{"type":"string","minLength":1,"maxLength":200,"description":"Content-ID for inline images referenced in the HTML as `cid:<value>`: the attachment becomes `inline` instead of appearing at the end of the message."}}},"maxItems":20,"description":"Email attachments (max 20, 10 MB each, 25 MB in total). For each item provide exactly one source: `id`, `content` (base64) or `url`."},"idempotencyKey":{"type":"string","minLength":8},"disableTracking":{"type":"boolean","default":false},"disableUtm":{"type":"boolean","default":false}},"required":["channel","to","from","idempotencyKey"]},{"type":"object","properties":{"channel":{"type":"string","enum":["whatsapp"]},"to":{"type":"string","pattern":"^\\+?\\d{6,15}$"},"text":{"type":"string","minLength":1},"templateId":{"type":"string","minLength":1},"variables":{"type":"object","additionalProperties":{}},"metaTemplate":{"type":"object","properties":{"name":{"type":"string","minLength":1},"params":{"type":"array","items":{"type":"string"},"default":[]},"language":{"type":"string","minLength":2}},"required":["name"]},"idempotencyKey":{"type":"string","minLength":8}},"required":["channel","to","idempotencyKey"]},{"type":"object","properties":{"channel":{"type":"string","enum":["telegram"]},"to":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"templateId":{"type":"string","minLength":1},"variables":{"type":"object","additionalProperties":{}},"idempotencyKey":{"type":"string","minLength":8}},"required":["channel","to","idempotencyKey"]}]},"CreateCampaignInput":{"type":"object","properties":{"name":{"type":"string","minLength":1},"fromAddress":{"type":"string"},"listId":{"type":"string","format":"uuid"},"segmentId":{"type":"string","format":"uuid"},"templateId":{"type":"string","format":"uuid"},"subject":{"type":"string","minLength":1},"html":{"type":"string","minLength":1},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Id of an attachment already uploaded with POST /v1/attachments."},"filename":{"type":"string","minLength":1,"maxLength":255,"description":"File name shown to the recipient. Required with `content` or `url`."},"content":{"type":"string","minLength":1,"description":"File content in base64, without the `data:` prefix."},"url":{"type":"string","format":"uri","description":"Public https URL to download the file from (private hosts are blocked)."},"contentType":{"type":"string","minLength":3,"maxLength":255,"description":"Content-Type override; when absent, it is inferred from the file name."},"contentId":{"type":"string","minLength":1,"maxLength":200,"description":"Content-ID for inline images referenced in the HTML as `cid:<value>`: the attachment becomes `inline` instead of appearing at the end of the message."}}},"maxItems":20,"description":"Email attachments (max 20, 10 MB each, 25 MB in total). For each item provide exactly one source: `id`, `content` (base64) or `url`."},"disableTracking":{"type":"boolean"},"disableClickTracking":{"type":"boolean"},"disableUtm":{"type":"boolean"}},"required":["name","fromAddress"]},"CreateInboxInput":{"type":"object","properties":{"localPart":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[a-z0-9][a-z0-9._-]*$"},"displayName":{"type":"string","minLength":1,"maxLength":120},"domainKind":{"type":"string","enum":["shared","tenant"],"default":"shared"},"domainName":{"type":"string"},"avatarColor":{"type":"string"}},"required":["localPart","displayName"]},"SendFromInboxInput":{"type":"object","properties":{"to":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"cc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"bcc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"subject":{"type":"string","minLength":1},"html":{"type":"string","minLength":1},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Id of an attachment already uploaded with POST /v1/attachments."},"filename":{"type":"string","minLength":1,"maxLength":255,"description":"File name shown to the recipient. Required with `content` or `url`."},"content":{"type":"string","minLength":1,"description":"File content in base64, without the `data:` prefix."},"url":{"type":"string","format":"uri","description":"Public https URL to download the file from (private hosts are blocked)."},"contentType":{"type":"string","minLength":3,"maxLength":255,"description":"Content-Type override; when absent, it is inferred from the file name."},"contentId":{"type":"string","minLength":1,"maxLength":200,"description":"Content-ID for inline images referenced in the HTML as `cid:<value>`: the attachment becomes `inline` instead of appearing at the end of the message."}}},"maxItems":20,"description":"Email attachments (max 20, 10 MB each, 25 MB in total). For each item provide exactly one source: `id`, `content` (base64) or `url`."},"idempotencyKey":{"type":"string","minLength":8}},"required":["to","subject","html"]},"ReplyInput":{"type":"object","properties":{"html":{"type":"string","minLength":1},"cc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"bcc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"attachments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Id of an attachment already uploaded with POST /v1/attachments."},"filename":{"type":"string","minLength":1,"maxLength":255,"description":"File name shown to the recipient. Required with `content` or `url`."},"content":{"type":"string","minLength":1,"description":"File content in base64, without the `data:` prefix."},"url":{"type":"string","format":"uri","description":"Public https URL to download the file from (private hosts are blocked)."},"contentType":{"type":"string","minLength":3,"maxLength":255,"description":"Content-Type override; when absent, it is inferred from the file name."},"contentId":{"type":"string","minLength":1,"maxLength":200,"description":"Content-ID for inline images referenced in the HTML as `cid:<value>`: the attachment becomes `inline` instead of appearing at the end of the message."}}},"maxItems":20,"description":"Email attachments (max 20, 10 MB each, 25 MB in total). For each item provide exactly one source: `id`, `content` (base64) or `url`."},"idempotencyKey":{"type":"string","minLength":8}},"required":["html"]},"CreateDraftInput":{"type":"object","properties":{"to":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"cc":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"},"maxItems":50}],"description":"One or more recipients: 'a@b.com', 'Name <a@b.com>', several comma-separated addresses, or an array."},"subject":{"type":"string","default":""},"html":{"type":"string","default":""},"threadId":{"type":"string","format":"uuid"}}},"CreateEmailRuleInput":{"type":"object","properties":{"action":{"type":"string","enum":["allow","block"]},"matchType":{"type":"string","enum":["email","domain"]},"value":{"type":"string","minLength":1,"maxLength":320},"note":{"type":"string","maxLength":200}},"required":["action","matchType","value"]},"CreateWebhookInput":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"description":{"type":"string","maxLength":200},"events":{"type":"array","items":{"type":"string","enum":["email.received","email.sent","email.delivered","email.bounced","email.complained"]},"minItems":1}},"required":["url","events"]},"UpdateWebhookInput":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"description":{"type":"string","maxLength":200},"events":{"type":"array","items":{"type":"string","enum":["email.received","email.sent","email.delivered","email.bounced","email.complained"]},"minItems":1},"enabled":{"type":"boolean"}}},"CreateTagInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["name"]},"CreateTemplateInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":200,"description":"Unique within the workspace."},"body":{"type":"string","minLength":1,"description":"Base content. With format 'blocks' it is the JSON of an EmailDoc (the visual editor document)."},"channels":{"type":"array","items":{"type":"string","enum":["email","whatsapp","telegram"]},"minItems":1,"description":"Channels the template can be used on. Default: ['email']."},"format":{"type":"string","enum":["markdown","html","text","blocks"],"description":"Email: markdown, html or blocks (default html). WhatsApp/Telegram: always text."},"subject":{"type":"string","minLength":1,"description":"Required if the template includes the email channel."},"channelText":{"type":"object","properties":{"whatsapp":{"type":"string"},"telegram":{"type":"string"}},"description":"Alternative text for WhatsApp/Telegram: without an override the base body is degraded to plain text."}},"required":["name","body"]},"UpdateTemplateInput":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":200,"description":"Unique within the workspace."},"body":{"type":"string","minLength":1,"description":"Base content. With format 'blocks' it is the JSON of an EmailDoc (the visual editor document)."},"channels":{"type":"array","items":{"type":"string","enum":["email","whatsapp","telegram"]},"minItems":1,"description":"Channels the template can be used on. Default: ['email']."},"format":{"type":"string","enum":["markdown","html","text","blocks"],"description":"Email: markdown, html or blocks (default html). WhatsApp/Telegram: always text."},"subject":{"type":"string","minLength":1,"description":"Required if the template includes the email channel."},"channelText":{"type":"object","properties":{"whatsapp":{"type":"string"},"telegram":{"type":"string"}},"description":"Alternative text for WhatsApp/Telegram: without an override the base body is degraded to plain text."}}},"CreateCustomFieldInput":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":80},"type":{"type":"string","enum":["text","number","date","select","multiselect","boolean","url"]},"options":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":100},"groupName":{"type":"string","minLength":1,"maxLength":80}},"required":["label","type"]},"Journey":{"type":"object","properties":{"name":{"type":"string","minLength":1},"entry":{"type":"string","minLength":1},"nodes":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["trigger"]},"event":{"type":"string","minLength":1},"match":{"type":"object","additionalProperties":{"type":"string"}},"filter":{"type":"string","minLength":1},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","event","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["message"]},"preferredChannel":{"type":"string","enum":["email","whatsapp","telegram"]},"fallbackChain":{"type":"array","items":{"type":"string","enum":["email","whatsapp","telegram"]},"minItems":1},"templateByChannel":{"type":"object","properties":{"email":{"type":"string"},"whatsapp":{"type":"string"},"telegram":{"type":"string"}}},"inline":{"type":"object","properties":{"subject":{"type":"string","minLength":1},"doc":{"type":"object","properties":{"version":{"type":"number","enum":[1]},"settings":{"type":"object","properties":{"contentWidth":{"type":"integer","minimum":320,"maximum":900,"default":600},"backgroundColor":{"type":"string","default":"#FAFAF8"},"canvasColor":{"type":"string","default":"#ffffff"},"fontFamily":{"type":"string","default":"Arial, Helvetica, sans-serif"},"textColor":{"type":"string","default":"#292827"},"linkColor":{"type":"string","default":"#5B47C9"},"preheader":{"type":"string","default":""}}},"blocks":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["text"]},"html":{"type":"string"}},"required":["id","type","html"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["heading"]},"level":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]}]},"html":{"type":"string"}},"required":["id","type","level","html"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["image"]},"src":{"type":"string"},"alt":{"type":"string","default":""},"href":{"type":"string"},"width":{"type":"integer","exclusiveMinimum":0},"align":{"type":"string","enum":["left","center","right"],"default":"center"}},"required":["id","type","src"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["button"]},"text":{"type":"string"},"href":{"type":"string"},"bg":{"type":"string","default":"#1B1938"},"color":{"type":"string","default":"#FFFFFF"},"radius":{"type":"integer","minimum":0,"maximum":40,"default":6},"align":{"type":"string","enum":["left","center","right"],"default":"center"},"fullWidth":{"type":"boolean","default":false}},"required":["id","type","text","href"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["divider"]},"color":{"type":"string","default":"#e5e7eb"},"thickness":{"type":"integer","minimum":1,"maximum":10,"default":1}},"required":["id","type"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["spacer"]},"height":{"type":"integer","minimum":1,"maximum":200,"default":24}},"required":["id","type"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["social"]},"links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["x","facebook","instagram","linkedin","youtube","tiktok"]},"href":{"type":"string"}},"required":["platform","href"]}},"iconStyle":{"type":"string","enum":["color","mono"],"default":"color"},"align":{"type":"string","enum":["left","center","right"],"default":"center"}},"required":["id","type","links"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["html"]},"code":{"type":"string"}},"required":["id","type","code"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["video"]},"href":{"type":"string"},"thumbnail":{"type":"string","default":""},"alt":{"type":"string","default":""},"width":{"type":"integer","exclusiveMinimum":0},"align":{"type":"string","enum":["left","center","right"],"default":"center"}},"required":["id","type","href"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["timer"]},"deadline":{"type":"string","minLength":1},"label":{"type":"string","default":""},"bg":{"type":"string","default":"#1B1938"},"color":{"type":"string","default":"#ffffff"},"align":{"type":"string","enum":["left","center","right"],"default":"center"}},"required":["id","type","deadline"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["products"]},"layout":{"type":"string","enum":["grid2","grid3","list"],"default":"grid2"},"items":{"type":"array","items":{"type":"object","properties":{"productId":{"type":"string"},"title":{"type":"string"},"imageUrl":{"type":"string","default":""},"price":{"type":"string","default":""},"url":{"type":"string","default":""}},"required":["title"]},"default":[]},"showPrice":{"type":"boolean","default":true},"buttonText":{"type":"string","default":"Vedi prodotto"},"buttonBg":{"type":"string","default":"#1B1938"},"buttonColor":{"type":"string","default":"#FFFFFF"}},"required":["id","type"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["cart"]},"title":{"type":"string","default":"Il tuo carrello ti aspetta"},"showImages":{"type":"boolean","default":true},"showPrices":{"type":"boolean","default":true},"buttonText":{"type":"string","default":"Completa l'ordine"},"buttonBg":{"type":"string","default":"#1B1938"},"buttonColor":{"type":"string","default":"#FFFFFF"}},"required":["id","type"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["columns"]},"columns":{"type":"array","items":{"type":"object","properties":{"width":{"type":"number","minimum":1,"maximum":100},"blocks":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["text"]},"html":{"type":"string"}},"required":["id","type","html"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["heading"]},"level":{"anyOf":[{"type":"number","enum":[1]},{"type":"number","enum":[2]},{"type":"number","enum":[3]}]},"html":{"type":"string"}},"required":["id","type","level","html"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["image"]},"src":{"type":"string"},"alt":{"type":"string","default":""},"href":{"type":"string"},"width":{"type":"integer","exclusiveMinimum":0},"align":{"type":"string","enum":["left","center","right"],"default":"center"}},"required":["id","type","src"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["button"]},"text":{"type":"string"},"href":{"type":"string"},"bg":{"type":"string","default":"#1B1938"},"color":{"type":"string","default":"#FFFFFF"},"radius":{"type":"integer","minimum":0,"maximum":40,"default":6},"align":{"type":"string","enum":["left","center","right"],"default":"center"},"fullWidth":{"type":"boolean","default":false}},"required":["id","type","text","href"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["divider"]},"color":{"type":"string","default":"#e5e7eb"},"thickness":{"type":"integer","minimum":1,"maximum":10,"default":1}},"required":["id","type"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["spacer"]},"height":{"type":"integer","minimum":1,"maximum":200,"default":24}},"required":["id","type"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["social"]},"links":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["x","facebook","instagram","linkedin","youtube","tiktok"]},"href":{"type":"string"}},"required":["platform","href"]}},"iconStyle":{"type":"string","enum":["color","mono"],"default":"color"},"align":{"type":"string","enum":["left","center","right"],"default":"center"}},"required":["id","type","links"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["html"]},"code":{"type":"string"}},"required":["id","type","code"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"style":{"type":"object","properties":{"paddingX":{"type":"integer","minimum":0,"maximum":80},"paddingY":{"type":"integer","minimum":0,"maximum":80},"backgroundColor":{"type":"string"},"align":{"type":"string","enum":["left","center","right"]},"radius":{"type":"integer","minimum":0,"maximum":40}}},"type":{"type":"string","enum":["video"]},"href":{"type":"string"},"thumbnail":{"type":"string","default":""},"alt":{"type":"string","default":""},"width":{"type":"integer","exclusiveMinimum":0},"align":{"type":"string","enum":["left","center","right"],"default":"center"}},"required":["id","type","href"]}]}}},"required":["width","blocks"]},"minItems":2,"maxItems":3}},"required":["id","type","columns"]}]}}},"required":["version","settings","blocks"]}},"required":["subject","doc"]},"attachmentIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":20},"ai":{"type":"object","properties":{"model":{"type":"string","minLength":1},"prompt":{"type":"string","minLength":1,"maxLength":4000},"mode":{"type":"string","enum":["section","full"]}},"required":["model","prompt","mode"]},"filter":{"type":"string","minLength":1},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","preferredChannel","fallbackChain","templateByChannel","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["notify"]},"to":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10},"subject":{"type":"string","minLength":1,"maxLength":200},"body":{"type":"string","minLength":1,"maxLength":10000},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","to","subject","body","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["wait"]},"duration":{"type":"string","minLength":2},"until":{"type":"string","format":"date-time"},"untilCondition":{"type":"string","minLength":1},"checkTimeout":{"type":"string","minLength":2},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["wait_for_event"]},"event":{"type":"string","minLength":1},"match":{"type":"object","additionalProperties":{"type":"string"}},"timeout":{"type":"string","minLength":2},"note":{"type":"string","maxLength":2000},"onEvent":{"type":["string","null"],"minLength":1},"onTimeout":{"type":["string","null"],"minLength":1}},"required":["id","type","event","timeout","onEvent","onTimeout"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["branch"]},"condition":{"type":"string","minLength":1},"label":{"type":"string","maxLength":400},"note":{"type":"string","maxLength":2000},"onTrue":{"type":["string","null"],"minLength":1},"onFalse":{"type":["string","null"],"minLength":1}},"required":["id","type","condition","onTrue","onFalse"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["split"]},"weights":{"type":"array","items":{"type":"integer","minimum":0,"maximum":100},"minItems":2,"maxItems":4},"paths":{"type":"array","items":{"type":["string","null"],"minLength":1},"minItems":2,"maxItems":4},"note":{"type":"string","maxLength":2000}},"required":["id","type","weights","paths"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["goto"]},"target":{"type":"string","minLength":1},"note":{"type":"string","maxLength":2000}},"required":["id","type","target"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["webhook"]},"url":{"type":"string","format":"uri"},"method":{"type":"string","enum":["POST","GET","PUT"]},"headers":{"type":"object","additionalProperties":{"type":"string"}},"bodyTemplate":{"type":"string"},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","url","method","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["add_tag"]},"tagIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":20},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","tagIds","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["remove_tag"]},"tagIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":20},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","tagIds","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["subscribe"]},"listIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":20},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","listIds","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["unsubscribe"]},"listIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":20},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","listIds","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["update_contact"]},"updates":{"type":"object","additionalProperties":{"type":["string","null"],"maxLength":1000}},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","updates","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["add_note"]},"text":{"type":"string","minLength":1,"maxLength":4000},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","text","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["score"]},"op":{"type":"string","enum":["add","subtract","set"]},"points":{"type":"integer","minimum":-100000,"maximum":100000},"field":{"type":"string","minLength":1,"maxLength":64,"default":"score"},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","op","points","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["conversion"]},"name":{"type":"string","minLength":1,"maxLength":120},"valueCents":{"type":"integer","minimum":0,"maximum":100000000},"currency":{"type":"string","minLength":3,"maxLength":3},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","name","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["start_automation"]},"automationId":{"type":"string","format":"uuid"},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","automationId","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["end_automation"]},"automationId":{"type":"string","format":"uuid"},"note":{"type":"string","maxLength":2000},"next":{"type":["string","null"],"minLength":1}},"required":["id","type","automationId","next"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["goal"]},"event":{"type":"string","minLength":1},"note":{"type":"string","maxLength":2000}},"required":["id","type","event"]},{"type":"object","properties":{"id":{"type":"string","minLength":1},"type":{"type":"string","enum":["exit"]},"reason":{"type":"string"},"note":{"type":"string","maxLength":2000}},"required":["id","type"]}]},"minItems":1},"flowFilter":{"type":"string","minLength":1}},"required":["name","entry","nodes"]},"UpdateAutomationInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"Automation name. Internal label: no recipient sees it."},"description":{"type":["string","null"],"maxLength":1000,"description":"Internal note about the automation. `null` clears it."},"enrollSegmentId":{"type":["string","null"],"format":"uuid","description":"Segment that enrolls on its own: whoever starts matching its conditions enters the flow, without waiting for an event. Only applies to active automations; `null` turns off auto-enrollment without touching contacts already inside."}}},"CommerceProductInput":{"type":"object","properties":{"externalId":{"type":"string","minLength":1},"title":{"type":"string","minLength":1},"description":{"type":"string","default":""},"imageUrl":{"type":"string","default":""},"price":{"type":"number","minimum":0},"currency":{"type":"string","default":"EUR"},"url":{"type":"string","default":""}},"required":["externalId","title"]},"CommerceCartInput":{"type":"object","properties":{"externalId":{"type":"string","minLength":1},"email":{"type":"string","format":"email"},"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1},"quantity":{"type":"integer","minimum":1,"default":1},"price":{"type":"number","minimum":0},"imageUrl":{"type":"string"},"url":{"type":"string"},"productId":{"type":"string"}},"required":["title"]},"minItems":1},"total":{"type":"number","minimum":0},"currency":{"type":"string","default":"EUR"},"cartUrl":{"type":"string"}},"required":["externalId","email","items"]},"CommerceOrderInput":{"type":"object","properties":{"externalId":{"type":"string","minLength":1},"email":{"type":"string","format":"email"},"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1},"quantity":{"type":"integer","minimum":1,"default":1},"price":{"type":"number","minimum":0},"imageUrl":{"type":"string"},"url":{"type":"string"},"productId":{"type":"string"}},"required":["title"]},"default":[]},"total":{"type":"number","minimum":0},"currency":{"type":"string","default":"EUR"},"cartExternalId":{"type":"string"}},"required":["externalId","email","total"]},"StartAcImportBody":{"type":"object","properties":{"apiUrl":{"type":"string","description":"E.g. https://<account>.api-us1.com"},"apiKey":{"type":"string","description":"ActiveCampaign API key (Settings › Developer)."},"entities":{"type":"object","properties":{"fields":{"type":"boolean"},"tags":{"type":"boolean"},"lists":{"type":"boolean"},"contacts":{"type":"boolean"},"suppressions":{"type":"boolean"},"campaigns":{"type":"boolean","description":"Campaigns: email content as a reusable template plus the history. Imported campaigns are never scheduled."},"automations":{"type":"boolean","description":"Automations: always imported as DRAFTS to review, never active. The AC structure cannot be exported reliably, so the report lists for each automation what was not converted."}}},"options":{"type":"object","properties":{"overwriteExisting":{"type":"boolean","description":"Overwrites existing contacts' attributes with the AC values (default: non-destructive merge)."},"convertAutomationsWithAi":{"type":"boolean","description":"Uses AI to translate automation blocks into our DAG (default true, consumes the plan's AI credits). With false only the deterministic mapping of known blocks is used."}}}}},"CreateContact":{"type":"object","properties":{"attributes":{"type":"object","additionalProperties":{},"default":{}},"identities":{"type":"array","items":{"type":"object","properties":{"channel":{"type":"string","enum":["email","whatsapp","telegram"]},"address":{"type":"string","minLength":1},"consent":{"type":"string","enum":["unknown","opted_in","opted_out","not_subscribed"]}},"required":["channel","address"]},"default":[]}}},"TagBody":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid"}},"required":["tagId"]},"CreateListBody":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":80}},"required":["name"]},"ListMembersBody":{"type":"object","properties":{"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":100}},"required":["contactIds"]},"CreateSegment":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"rules":{"type":"object","properties":{"combinator":{"type":"string","enum":["and","or"]},"rules":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["attribute"]},"field":{"type":"string","minLength":1,"maxLength":64},"op":{"type":"string","enum":["eq","neq","contains","gt","lt","gte","lte","exists","not_exists"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["type","field","op"]},{"type":"object","properties":{"type":{"type":"string","enum":["tag"]},"op":{"type":"string","enum":["has","not_has"]},"tagId":{"type":"string","format":"uuid"}},"required":["type","op","tagId"]},{"type":"object","properties":{"type":{"type":"string","enum":["list"]},"op":{"type":"string","enum":["in","not_in"]},"listId":{"type":"string","format":"uuid"}},"required":["type","op","listId"]},{"type":"object","properties":{"type":{"type":"string","enum":["consent"]},"channel":{"type":"string","enum":["email","whatsapp","telegram"]},"status":{"type":"string","enum":["unknown","opted_in","opted_out","not_subscribed"]}},"required":["type","channel","status"]},{"type":"object","properties":{"type":{"type":"string","enum":["activity"]},"kind":{"type":"string","enum":["opened","clicked","sent","not_opened","not_clicked","never_sent","placed_order","not_placed_order"]},"withinDays":{"type":"integer","minimum":1,"maximum":365}},"required":["type","kind","withinDays"]},{"type":"object","properties":{"type":{"type":"string","enum":["commerce"]},"metric":{"type":"string","enum":["orders_count","total_spent","days_since_last_order"]},"op":{"type":"string","enum":[">",">=","<","<=","=="]},"value":{"type":"number"}},"required":["type","metric","op","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["group"]},"combinator":{"type":"string","enum":["and","or"]},"rules":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["attribute"]},"field":{"type":"string","minLength":1,"maxLength":64},"op":{"type":"string","enum":["eq","neq","contains","gt","lt","gte","lte","exists","not_exists"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["type","field","op"]},{"type":"object","properties":{"type":{"type":"string","enum":["tag"]},"op":{"type":"string","enum":["has","not_has"]},"tagId":{"type":"string","format":"uuid"}},"required":["type","op","tagId"]},{"type":"object","properties":{"type":{"type":"string","enum":["list"]},"op":{"type":"string","enum":["in","not_in"]},"listId":{"type":"string","format":"uuid"}},"required":["type","op","listId"]},{"type":"object","properties":{"type":{"type":"string","enum":["consent"]},"channel":{"type":"string","enum":["email","whatsapp","telegram"]},"status":{"type":"string","enum":["unknown","opted_in","opted_out","not_subscribed"]}},"required":["type","channel","status"]},{"type":"object","properties":{"type":{"type":"string","enum":["activity"]},"kind":{"type":"string","enum":["opened","clicked","sent","not_opened","not_clicked","never_sent","placed_order","not_placed_order"]},"withinDays":{"type":"integer","minimum":1,"maximum":365}},"required":["type","kind","withinDays"]},{"type":"object","properties":{"type":{"type":"string","enum":["commerce"]},"metric":{"type":"string","enum":["orders_count","total_spent","days_since_last_order"]},"op":{"type":"string","enum":[">",">=","<","<=","=="]},"value":{"type":"number"}},"required":["type","metric","op","value"]}]},"minItems":1,"maxItems":20}},"required":["type","combinator","rules"]}]},"minItems":1,"maxItems":20}},"required":["combinator","rules"]}},"required":["name","rules"]},"PatchSegment":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"rules":{"type":"object","properties":{"combinator":{"type":"string","enum":["and","or"]},"rules":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["attribute"]},"field":{"type":"string","minLength":1,"maxLength":64},"op":{"type":"string","enum":["eq","neq","contains","gt","lt","gte","lte","exists","not_exists"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["type","field","op"]},{"type":"object","properties":{"type":{"type":"string","enum":["tag"]},"op":{"type":"string","enum":["has","not_has"]},"tagId":{"type":"string","format":"uuid"}},"required":["type","op","tagId"]},{"type":"object","properties":{"type":{"type":"string","enum":["list"]},"op":{"type":"string","enum":["in","not_in"]},"listId":{"type":"string","format":"uuid"}},"required":["type","op","listId"]},{"type":"object","properties":{"type":{"type":"string","enum":["consent"]},"channel":{"type":"string","enum":["email","whatsapp","telegram"]},"status":{"type":"string","enum":["unknown","opted_in","opted_out","not_subscribed"]}},"required":["type","channel","status"]},{"type":"object","properties":{"type":{"type":"string","enum":["activity"]},"kind":{"type":"string","enum":["opened","clicked","sent","not_opened","not_clicked","never_sent","placed_order","not_placed_order"]},"withinDays":{"type":"integer","minimum":1,"maximum":365}},"required":["type","kind","withinDays"]},{"type":"object","properties":{"type":{"type":"string","enum":["commerce"]},"metric":{"type":"string","enum":["orders_count","total_spent","days_since_last_order"]},"op":{"type":"string","enum":[">",">=","<","<=","=="]},"value":{"type":"number"}},"required":["type","metric","op","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["group"]},"combinator":{"type":"string","enum":["and","or"]},"rules":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["attribute"]},"field":{"type":"string","minLength":1,"maxLength":64},"op":{"type":"string","enum":["eq","neq","contains","gt","lt","gte","lte","exists","not_exists"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["type","field","op"]},{"type":"object","properties":{"type":{"type":"string","enum":["tag"]},"op":{"type":"string","enum":["has","not_has"]},"tagId":{"type":"string","format":"uuid"}},"required":["type","op","tagId"]},{"type":"object","properties":{"type":{"type":"string","enum":["list"]},"op":{"type":"string","enum":["in","not_in"]},"listId":{"type":"string","format":"uuid"}},"required":["type","op","listId"]},{"type":"object","properties":{"type":{"type":"string","enum":["consent"]},"channel":{"type":"string","enum":["email","whatsapp","telegram"]},"status":{"type":"string","enum":["unknown","opted_in","opted_out","not_subscribed"]}},"required":["type","channel","status"]},{"type":"object","properties":{"type":{"type":"string","enum":["activity"]},"kind":{"type":"string","enum":["opened","clicked","sent","not_opened","not_clicked","never_sent","placed_order","not_placed_order"]},"withinDays":{"type":"integer","minimum":1,"maximum":365}},"required":["type","kind","withinDays"]},{"type":"object","properties":{"type":{"type":"string","enum":["commerce"]},"metric":{"type":"string","enum":["orders_count","total_spent","days_since_last_order"]},"op":{"type":"string","enum":[">",">=","<","<=","=="]},"value":{"type":"number"}},"required":["type","metric","op","value"]}]},"minItems":1,"maxItems":20}},"required":["type","combinator","rules"]}]},"minItems":1,"maxItems":20}},"required":["combinator","rules"]}}},"SegmentPreviewBody":{"type":"object","properties":{"rules":{"type":"object","properties":{"combinator":{"type":"string","enum":["and","or"]},"rules":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["attribute"]},"field":{"type":"string","minLength":1,"maxLength":64},"op":{"type":"string","enum":["eq","neq","contains","gt","lt","gte","lte","exists","not_exists"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["type","field","op"]},{"type":"object","properties":{"type":{"type":"string","enum":["tag"]},"op":{"type":"string","enum":["has","not_has"]},"tagId":{"type":"string","format":"uuid"}},"required":["type","op","tagId"]},{"type":"object","properties":{"type":{"type":"string","enum":["list"]},"op":{"type":"string","enum":["in","not_in"]},"listId":{"type":"string","format":"uuid"}},"required":["type","op","listId"]},{"type":"object","properties":{"type":{"type":"string","enum":["consent"]},"channel":{"type":"string","enum":["email","whatsapp","telegram"]},"status":{"type":"string","enum":["unknown","opted_in","opted_out","not_subscribed"]}},"required":["type","channel","status"]},{"type":"object","properties":{"type":{"type":"string","enum":["activity"]},"kind":{"type":"string","enum":["opened","clicked","sent","not_opened","not_clicked","never_sent","placed_order","not_placed_order"]},"withinDays":{"type":"integer","minimum":1,"maximum":365}},"required":["type","kind","withinDays"]},{"type":"object","properties":{"type":{"type":"string","enum":["commerce"]},"metric":{"type":"string","enum":["orders_count","total_spent","days_since_last_order"]},"op":{"type":"string","enum":[">",">=","<","<=","=="]},"value":{"type":"number"}},"required":["type","metric","op","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["group"]},"combinator":{"type":"string","enum":["and","or"]},"rules":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["attribute"]},"field":{"type":"string","minLength":1,"maxLength":64},"op":{"type":"string","enum":["eq","neq","contains","gt","lt","gte","lte","exists","not_exists"]},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}},"required":["type","field","op"]},{"type":"object","properties":{"type":{"type":"string","enum":["tag"]},"op":{"type":"string","enum":["has","not_has"]},"tagId":{"type":"string","format":"uuid"}},"required":["type","op","tagId"]},{"type":"object","properties":{"type":{"type":"string","enum":["list"]},"op":{"type":"string","enum":["in","not_in"]},"listId":{"type":"string","format":"uuid"}},"required":["type","op","listId"]},{"type":"object","properties":{"type":{"type":"string","enum":["consent"]},"channel":{"type":"string","enum":["email","whatsapp","telegram"]},"status":{"type":"string","enum":["unknown","opted_in","opted_out","not_subscribed"]}},"required":["type","channel","status"]},{"type":"object","properties":{"type":{"type":"string","enum":["activity"]},"kind":{"type":"string","enum":["opened","clicked","sent","not_opened","not_clicked","never_sent","placed_order","not_placed_order"]},"withinDays":{"type":"integer","minimum":1,"maximum":365}},"required":["type","kind","withinDays"]},{"type":"object","properties":{"type":{"type":"string","enum":["commerce"]},"metric":{"type":"string","enum":["orders_count","total_spent","days_since_last_order"]},"op":{"type":"string","enum":[">",">=","<","<=","=="]},"value":{"type":"number"}},"required":["type","metric","op","value"]}]},"minItems":1,"maxItems":20}},"required":["type","combinator","rules"]}]},"minItems":1,"maxItems":20}},"required":["combinator","rules"]}},"required":["rules"]},"CreateDomain":{"type":"object","properties":{"name":{"type":"string","minLength":3},"region":{"type":"string","default":"eu-west-1"}},"required":["name"]},"UpdateDomain":{"type":"object","properties":{"defaultFromName":{"type":["string","null"],"description":"Default sender name of the domain: display name applied to sends whose `from` is a bare address (hello@acme.com → Federico <hello@acme.com>). null or an empty string removes it.","example":"Federico"},"defaultFromAddress":{"type":["string","null"],"description":"Default sender mailbox: sends that do not declare one leave from here, i.e. automations, which otherwise use `no-reply@<domain>`. Must be an address on THIS domain (otherwise 422 `invalid_from_address`: from another domain the send would not pass the gate). null reverts to `no-reply@`.","example":"hello@acme.com"}}},"EventInput":{"type":"object","properties":{"name":{"type":"string","minLength":1},"contactId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"properties":{"type":"object","additionalProperties":{}},"idempotencyKey":{"type":"string","minLength":8,"maxLength":200}},"required":["name"]},"InboxPatch":{"type":"object","properties":{"displayName":{"type":"string"},"status":{"type":"string","enum":["active","archived"]}}},"ScheduleCampaignBody":{"type":"object","properties":{"sendAt":{"type":"string","format":"date-time","description":"Absent, in the past or less than 5 minutes from now = immediate send (requires confirmationToken)."},"confirmationToken":{"type":"string","minLength":1,"description":"From POST /campaigns/:id/estimate. Required only for an immediate send or one within 5 minutes; scheduling further ahead does not require it."}}},"UpdateCampaignDraft":{"type":"object","properties":{"name":{"type":"string","minLength":1},"fromAddress":{"type":"string","format":"email"},"listId":{"type":["string","null"],"format":"uuid"},"segmentId":{"type":["string","null"],"format":"uuid"},"templateId":{"type":["string","null"],"format":"uuid"},"subject":{"type":"string","minLength":1},"html":{"type":"string","minLength":1},"disableTracking":{"type":"boolean"},"disableClickTracking":{"type":"boolean"},"disableUtm":{"type":"boolean"}}},"Image":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"filename":{"type":"string"},"url":{"type":"string","description":"Public URL: this is what goes in the image block."},"contentType":{"type":"string"},"size":{"type":"integer"},"createdAt":{"type":"string"}},"required":["id","filename","url","contentType","size","createdAt"]},"ImageUpload":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":200},"content":{"type":"string"},"url":{"type":"string","format":"uri"},"contentType":{"type":"string"}},"required":["filename"]},"AutomationTestRequest":{"type":"object","properties":{"contactId":{"type":"string","format":"uuid"},"timeScale":{"type":"integer","minimum":1}},"required":["contactId"]},"AutomationDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string"},"version":{"type":["integer","null"]},"journey":{},"enrollSegmentId":{"type":["string","null"],"format":"uuid"},"enrollSegmentLastRunAt":{"type":["string","null"]}},"required":["id","name","description","status","version","enrollSegmentId","enrollSegmentLastRunAt"]},"AutomationNodeEmailMetrics":{"type":["object","null"],"properties":{"subject":{"type":["string","null"]},"sent":{"type":"integer"},"delivered":{"type":"integer"},"emailDelivered":{"type":"integer"},"queued":{"type":"integer"},"failed":{"type":"integer"},"openedHuman":{"type":"integer"},"openedAny":{"type":"integer"},"machineOpens":{"type":"integer"},"clicked":{"type":"integer"},"contentClicks":{"type":"integer"},"hardBounces":{"type":"integer"},"softBounces":{"type":"integer"},"unsubscribed":{"type":"integer"},"complained":{"type":"integer"},"openRate":{"type":["number","null"]},"clickRate":{"type":["number","null"]},"contentClickRate":{"type":["number","null"]},"clickToOpenRate":{"type":["number","null"]},"unsubscribeRate":{"type":["number","null"]},"bounceRate":{"type":["number","null"]},"complaintRate":{"type":["number","null"]}},"required":["subject","sent","delivered","emailDelivered","queued","failed","openedHuman","openedAny","machineOpens","clicked","contentClicks","hardBounces","softBounces","unsubscribed","complained","openRate","clickRate","contentClickRate","clickToOpenRate","unsubscribeRate","bounceRate","complaintRate"],"description":"Only for nodes that sent at least one message."},"AutomationStatsNode":{"type":"object","properties":{"nodeId":{"type":"string"},"nodeType":{"type":"string"},"done":{"type":"integer"},"skipped":{"type":"integer"},"failed":{"type":"integer"},"metrics":{"$ref":"#/components/schemas/AutomationNodeEmailMetrics"},"links":{"type":"array","items":{"$ref":"#/components/schemas/LinkStat"},"description":"The 5 most clicked links in the node's message, with role."},"conversions":{"type":["object","null"],"properties":{"conversions":{"type":"integer"},"contacts":{"type":"integer"},"revenueCents":{"type":"integer"}},"required":["conversions","contacts","revenueCents"],"description":"Conversions attributed to a click on this node."},"revenue":{"allOf":[{"$ref":"#/components/schemas/RevenueSummary"},{"type":["object","null"],"description":"Orders attributed to this node's messages; only for nodes that sent. The rule is in the top-level `revenue.attribution`."}]}},"required":["nodeId","nodeType","done","skipped","failed","metrics","links","conversions","revenue"]},"AutomationStats":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"since":{"type":["string","null"],"description":"Window applied to sent messages; null = all time."},"attribution":{"type":"string","enum":["first","last"]},"enrollments":{"type":"object","properties":{"total":{"type":"integer"},"byStatus":{"type":"object","additionalProperties":{"type":"integer"}}},"required":["total","byStatus"],"description":"Real enrollments: test runs do not count in the funnel."},"metrics":{"type":"object","properties":{"sent":{"type":"integer"},"delivered":{"type":"integer"},"emailDelivered":{"type":"integer"},"queued":{"type":"integer"},"failed":{"type":"integer"},"openedHuman":{"type":"integer"},"openedAny":{"type":"integer"},"machineOpens":{"type":"integer"},"clicked":{"type":"integer"},"contentClicks":{"type":"integer"},"hardBounces":{"type":"integer"},"softBounces":{"type":"integer"},"unsubscribed":{"type":"integer"},"complained":{"type":"integer"},"openRate":{"type":["number","null"]},"clickRate":{"type":["number","null"]},"contentClickRate":{"type":["number","null"]},"clickToOpenRate":{"type":["number","null"]},"unsubscribeRate":{"type":["number","null"]},"bounceRate":{"type":["number","null"]},"complaintRate":{"type":["number","null"]},"deliveryRate":{"type":["number","null"]},"readingEnvironment":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"n":{"type":"integer"},"pct":{"type":"number"}},"required":["label","n","pct"]}},"topClients":{"type":"array","items":{"type":"object","properties":{"client":{"type":"string"},"n":{"type":"integer"},"pct":{"type":"number"}},"required":["client","n","pct"]}}},"required":["sent","delivered","emailDelivered","queued","failed","openedHuman","openedAny","machineOpens","clicked","contentClicks","hardBounces","softBounces","unsubscribed","complained","openRate","clickRate","contentClickRate","clickToOpenRate","unsubscribeRate","bounceRate","complaintRate","deliveryRate","readingEnvironment","topClients"],"description":"Email totals of the automation; environment and client from human opens only."},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/AutomationStatsNode"}},"links":{"type":"array","items":{"$ref":"#/components/schemas/LinkStat"},"description":"The most clicked links across the whole automation."},"conversions":{"$ref":"#/components/schemas/EntityConversions"},"revenue":{"$ref":"#/components/schemas/RevenueReport"},"stuck":{"type":"array","items":{"type":"object","properties":{"enrollmentId":{"type":"string","format":"uuid"},"contactId":{"type":"string","format":"uuid"},"nodeId":{"type":"string"},"nodeType":{"type":["string","null"]},"since":{"type":"string"},"minutesStuck":{"type":"integer"}},"required":["enrollmentId","contactId","nodeId","nodeType","since","minutesStuck"]},"description":"Enrollments stuck on a node that is not waiting for anything."},"lastTestRun":{"description":"Latest test run, with the outcome of every step."}},"required":["id","name","status","since","attribution","enrollments","metrics","nodes","links","conversions","revenue","stuck"]},"AutomationRestartRequest":{"type":"object","properties":{"contactIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":1000},"confirm":{"type":"boolean","enum":[true],"description":"Explicit confirmation: contacts will see again the emails already received."}},"required":["contactIds","confirm"]},"CampaignMetrics":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"recipients":{"type":"integer"},"queued":{"type":"integer"},"delivered":{"type":"integer"},"sent":{"type":"integer"},"failed":{"type":"integer"},"uniqueOpens":{"type":"integer","description":"Distinct messages with at least one human open."},"rawOpens":{"type":"integer","description":"Open events of every class (human, proxy, scanner): never a KPI."},"openClassification":{"type":"object","properties":{"human":{"type":"integer"},"machine":{"type":"integer"},"prefetch":{"type":"integer"},"bot":{"type":"integer"}},"required":["human","machine","prefetch","bot"]},"uniqueClicks":{"type":"integer"},"contentClicks":{"type":"integer","description":"Messages with a human click on content: excludes logo, images, chrome and social links."},"unsubscribes":{"type":"integer"},"hardBounces":{"type":"integer"},"softBounces":{"type":"integer"},"complaints":{"type":"integer"},"openRate":{"type":["number","null"],"description":"Percentage 0-100 of delivered; null without deliveries."},"clickRate":{"type":["number","null"]},"contentClickRate":{"type":["number","null"]},"clickToOpenRate":{"type":["number","null"],"description":"Unique clicks / human opens, capped at 100."},"unsubscribeRate":{"type":["number","null"]},"bounceRate":{"type":["number","null"],"description":"Hard + soft, over recipients."},"complaintRate":{"type":["number","null"]},"timeseries":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","description":"`YYYY-MM-DD` for a daily bucket, `YYYY-MM-DDTHH:00:00Z` for an hourly one."},"bucket":{"type":"string","enum":["hour","day"]},"opens":{"type":"integer"},"machineOpens":{"type":"integer"},"clicks":{"type":"integer"},"unsubscribes":{"type":"integer"},"bounces":{"type":"integer"}},"required":["date","bucket","opens","machineOpens","clicks","unsubscribes","bounces"]},"description":"Only buckets with events: gaps are filled by whoever draws the chart."},"links":{"type":"array","items":{"$ref":"#/components/schemas/LinkStat"},"description":"With `?links=1`: clicks per link, most clicked first."},"conversions":{"allOf":[{"$ref":"#/components/schemas/EntityConversions"},{"description":"With `?conversions=1|last|first`."}]},"revenue":{"$ref":"#/components/schemas/RevenueReport"}},"required":["id","recipients","queued","delivered","sent","failed","uniqueOpens","rawOpens","openClassification","uniqueClicks","contentClicks","unsubscribes","hardBounces","softBounces","complaints","openRate","clickRate","contentClickRate","clickToOpenRate","unsubscribeRate","bounceRate","complaintRate","revenue"]},"ListUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80}},"required":["name"]},"TagUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"color":{"type":["string","null"]}}},"EventAccepted":{"type":"object","properties":{"status":{"type":"string","enum":["accepted","duplicate"]},"eventId":{"type":"string","format":"uuid"},"contactId":{"type":"string","format":"uuid"}},"required":["status","eventId","contactId"]},"FrequencyCap":{"type":"object","properties":{"max":{"type":["integer","null"],"description":"Maximum marketing messages per contact in the window; `null` = no cap."},"days":{"type":"integer","description":"Window size in days (1-90)."},"policy":{"type":"string","enum":["skip","defer"],"description":"`skip` drops the excess message, `defer` postpones it until the window frees up."}},"required":["max","days","policy"]},"FrequencyCapWithImpact":{"allOf":[{"$ref":"#/components/schemas/FrequencyCap"},{"type":"object","properties":{"impact":{"type":"object","properties":{"capped":{"type":"integer"},"deferred":{"type":"integer"},"contactsAffected":{"type":"integer"},"windowDays":{"type":"integer"}},"required":["capped","deferred","contactsAffected","windowDays"]}}}]},"FrequencyCapUpdate":{"type":"object","properties":{"max":{"type":["integer","null"],"description":"Maximum marketing messages per contact in the window; `null` = no cap."},"days":{"type":"integer","description":"Window size in days (1-90)."},"policy":{"type":"string","enum":["skip","defer"],"description":"`skip` drops the excess message, `defer` postpones it until the window frees up."}}}},"parameters":{}},"paths":{"/emails":{"post":{"tags":["Emails"],"summary":"Send a transactional email","description":"Queues a transactional email (idempotent on `idempotencyKey`). Every address field accepts both `a@b.com` and `Name <a@b.com>`; `to`, `cc` and `bcc` also accept multiple recipients, as an array or comma-separated in the same string (at most 50 per message, one quota unit each). Required scope: `email:send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailInput"}}}},"responses":{"200":{"description":"Send already processed for this idempotencyKey.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResult"}}}},"202":{"description":"Email queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"`templateId` does not exist for the tenant (`template_not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Recipient is suppressed: bounce/complaint/unsubscribe (`suppressed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"502":{"description":"Upstream provider error (e.g. SES).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Emails"],"summary":"List sends with engagement","description":"Emails sent by the workspace (service emails excluded), newest first, with the per-row engagement summary: human and proxy opens, clicks, content clicks, last link. Same filters as the dashboard list: `campaignId`, `contactId`, `status`, `engagement` (clicked, opened without clicking, not opened among delivered, bounced, unsubscribed), `q` on recipient and subject, `since`. Required scope: `emails:read` or `email:send`.","security":[{"bearerAuth":[]}],"x-required-scope":["emails:read","email:send"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":false,"name":"campaignId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"contactId","in":"query"},{"schema":{"type":"string","enum":["queued","sent","delivered","failed","bounced"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","enum":["clicked","opened_not_clicked","not_opened","bounced","unsubscribed"]},"required":false,"name":"engagement","in":"query"},{"schema":{"type":"string","description":"Search recipient and subject."},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","description":"ISO 8601: only sends from this date."},"required":false,"name":"since","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Default 25."},"required":false,"name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Send list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/emails/batch":{"post":{"tags":["Emails"],"summary":"Send up to 100 emails in one request","description":"Queues several transactional sends in a single request. The outcome is PARTIAL: the 207 response carries one result per item, aligned by index, and an invalid item does not block the others. Idempotency applies per item (`idempotencyKey`), so a retried batch does not produce duplicate sends. It counts as a single request for the rate limit. Required scope: `email:send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailBatchInput"}}}},"responses":{"207":{"description":"Per-item outcomes (accepted and failed together).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailBatchResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/emails/{id}":{"get":{"tags":["Emails"],"summary":"Status of a send","description":"Metadata, engagement summary, clicked links (by canonical URL, with role: logo, button, text...) and event timeline of a message. On clicks every event carries `linkUrl`, `linkId` and `linkRole`: three clicks on the logo are not interest in the content. Required scope: `emails:read` or `email:send`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Message ID (the `id` field of the send response)."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Message status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageStatus"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/attachments":{"get":{"tags":["Attachments"],"summary":"List workspace attachments","description":"Required scope: `email:send` or `inbox:send`. An attachment uploaded once is reused across sends: pass `attachments: [{ id }]` to `/emails`, `/messages`, `/campaigns` or `/inboxes/{id}/send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send","inbox:send"],"responses":{"200":{"description":"Workspace attachments, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Attachments"],"summary":"Upload a reusable attachment","description":"Two modes: with `content` (base64) the file is uploaded immediately and the attachment is born ready; with `size` the response carries a signed `uploadUrl` to PUT the file to (mandatory beyond the few MB accepted in the body). Executable extensions and files over 10 MB are rejected. Required scope: `email:send` or `inbox:send`. An attachment uploaded once is reused across sends: pass `attachments: [{ id }]` to `/emails`, `/messages`, `/campaigns` or `/inboxes/{id}/send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send","inbox:send"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAttachmentInput"}}}},"responses":{"201":{"description":"Attachment created: `attachment` alone with `content`, `attachment` + `uploadUrl` with `size`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentUpload"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/attachments/{id}":{"get":{"tags":["Attachments"],"summary":"Metadata and download URL","description":"Attachment metadata + signed download URL (15 minutes). Required scope: `email:send` or `inbox:send`. An attachment uploaded once is reused across sends: pass `attachments: [{ id }]` to `/emails`, `/messages`, `/campaigns` or `/inboxes/{id}/send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send","inbox:send"],"parameters":[{"schema":{"type":"string","description":"Attachment ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Attachment with signed download URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentDownload"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Attachments"],"summary":"Delete an attachment","description":"Removes the row and the object in storage. Already queued sends that reference it will go out without that file. Required scope: `email:send` or `inbox:send`. An attachment uploaded once is reused across sends: pass `attachments: [{ id }]` to `/emails`, `/messages`, `/campaigns` or `/inboxes/{id}/send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send","inbox:send"],"parameters":[{"schema":{"type":"string","description":"Attachment ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Attachment deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentDeleted"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/attachments/{id}/confirm":{"post":{"tags":["Attachments"],"summary":"Confirm a signed upload","description":"Marks as ready an attachment uploaded with `uploadUrl`, aligning actual size and Content-Type. Optional: the same check happens the first time the attachment is used in a send. Required scope: `email:send` or `inbox:send`. An attachment uploaded once is reused across sends: pass `attachments: [{ id }]` to `/emails`, `/messages`, `/campaigns` or `/inboxes/{id}/send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send","inbox:send"],"parameters":[{"schema":{"type":"string","description":"Attachment ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Attachment ready to use.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentEnvelope"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The file has not been uploaded yet (`attachment_not_uploaded`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/images":{"get":{"tags":["Images"],"summary":"List the workspace's public images","description":"Lets you reuse an already uploaded image instead of uploading it again for every campaign. Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Image list.","content":{"application/json":{"schema":{"type":"object","properties":{"images":{"type":"array","items":{"$ref":"#/components/schemas/Image"}}},"required":["images"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Images"],"summary":"Upload an image for emails","description":"Returns the public URL to use as the `src` of an image block or inside the html of a campaign. Source: base64 `content` or a public https `url`; png, jpeg, gif or webp, max 5 MB.\n\nDeliberately separate from attachments: an attachment travels inside the message and lives in a private prefix, an image is downloaded by the mail client and so must live at a public URL. An attachment id used as `src` would give a broken image in every inbox. Required scope: `campaigns:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["campaigns:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageUpload"}}}},"responses":{"201":{"description":"Image uploaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Image"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/messages":{"post":{"tags":["Messages"],"summary":"Send a multi-channel transactional message","description":"Unified transactional send over email, WhatsApp or Telegram (discriminated union on `channel`). Required scope: `email:send` or `messages:send`. `email:send` for the email channel, `messages:send` for WhatsApp/Telegram.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send","messages:send"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageInput"}}}},"responses":{"200":{"description":"Send already processed for this idempotencyKey.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResult"}}}},"202":{"description":"Message queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"409":{"description":"Recipient is suppressed for the channel (`suppressed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"502":{"description":"Upstream provider error (e.g. SES).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/templates":{"get":{"tags":["Templates"],"summary":"List templates","description":"Reusable content templates for campaigns, transactional sends and `message` nodes of automations: this is where you get a valid `templateId`. The body is not included, read it from the detail. Filterable by channel with `?channel=`. Required scope: `templates:read` or `templates:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["templates:read","templates:write"],"responses":{"200":{"description":"Template list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Templates"],"summary":"Create a template","description":"Email: `subject` is mandatory and `format` is one of markdown, html (default) and blocks; with `blocks` the `body` is the JSON of an EmailDoc, the same document as the visual editor. WhatsApp and Telegram: `format` is always text and there is no subject. `{{...}}` variables are derived from the content and are not declared. The name is unique in the workspace: on a duplicate the response is 409 `template_exists` with the existing `templateId`, to reuse or to fix with PATCH. Required scope: `templates:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["templates:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateInput"}}}},"responses":{"201":{"description":"Template created.","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/Template"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking warnings: present only when there is something to report, e.g. {{...}} variables that match no contact field."}},"required":["template"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/templates/{id}":{"get":{"tags":["Templates"],"summary":"Get a template","description":"Content included: use it to re-read a template before fixing it and to know which variables it expects before using it in a send. Required scope: `templates:read` or `templates:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["templates:read","templates:write"],"parameters":[{"schema":{"type":"string","description":"Template ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Template detail.","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/Template"}},"required":["template"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Templates"],"summary":"Update a template","description":"Updates only the fields present in the body. The rules still cross-check: changing only the `body` of a `blocks` template still requires a valid EmailDoc. Campaigns already sent do not change, they carry the content frozen at send time. Required scope: `templates:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["templates:write"],"parameters":[{"schema":{"type":"string","description":"Template ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTemplateInput"}}}},"responses":{"200":{"description":"Template updated.","content":{"application/json":{"schema":{"type":"object","properties":{"template":{"$ref":"#/components/schemas/Template"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking warnings: present only when there is something to report, e.g. {{...}} variables that match no contact field."}},"required":["template"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"delete":{"tags":["Templates"],"summary":"Delete a template","description":"Rejected with 409 `template_in_use` if a campaign still references it (the response lists the campaigns using it). Required scope: `templates:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["templates:write"],"parameters":[{"schema":{"type":"string","description":"Template ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Template deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations":{"get":{"tags":["Automations"],"summary":"List automations","description":"Status, published version, active enrollments and the event that triggers each journey. Useful before writing to lists and tags: those events can start real sends. Required scope: `automations:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:read"],"parameters":[{"schema":{"type":"string","enum":["draft","active","paused","archived"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Automation list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"post":{"tags":["Automations"],"summary":"Create an automation from a Journey DAG","description":"Creates a draft + version 1. The Journey is validated (schema + DAG). Required scope: `automations:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Journey"}}}},"responses":{"201":{"description":"Automation created as draft.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationCreated"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid journey.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_journey"]},"errors":{"type":"array","items":{"type":"string"}}},"required":["error"]}}}}}}},"/automations/{id}/activate":{"post":{"tags":["Automations"],"summary":"Activate an automation","description":"From then on, events that match the trigger enroll contacts. Rejected with 409 template_channel_mismatch if a step uses a template on a channel that the template has not enabled (at runtime that step would be silently skipped). Required scope: `automations:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:write"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Automation activated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationStatus"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations/{id}/enroll":{"post":{"tags":["Automations"],"summary":"Enroll contacts in an active automation","description":"Adds contacts to an automation without waiting for the trigger: they enter at the start of the flow and the steps that send really send. Provide ONE audience among `listId`, `segmentId` and `contactIds`. Works only on `active` automations (409 on drafts and paused automations). Enrollment is asynchronous: the 202 says it was queued, per-contact outcomes are in the step log. A contact who is already enrolled is ignored (once-per-contact). Required scope: `automations:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:write"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationEnrollRequest"}}}},"responses":{"202":{"description":"Enrollment queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationEnrollQueued"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/automations/{id}/test":{"post":{"tags":["Automations"],"summary":"Time-compressed test run","description":"Runs ONE contact through the automation with waits divided by `timeScale` (1440 by default: one day becomes one minute), using the latest written version and working on drafts TOO: testing before activating is the point. **The messages are really sent** to that contact, so use an address of your own: a test that does not send would not tell whether the flow sends what it should. The test run does not take the 'one enrollment per contact' slot, so it can be repeated and does not stop the person from really entering when the automation goes live. Step-by-step outcomes are in the log. Required scope: `automations:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:write"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationTestRequest"}}}},"responses":{"202":{"description":"Test run queued.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"queued":{"type":"boolean"},"contactId":{"type":"string","format":"uuid"},"timeScale":{"type":"integer"}},"required":["id","queued","contactId","timeScale"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/automations/{id}":{"get":{"tags":["Automations"],"summary":"Get an automation","description":"Includes the DAG of the published version. Required scope: `automations:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:read"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Automation detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationDetail"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Automations"],"summary":"Metadata and segment auto-enrollment","description":"Updates only the fields present in the body. `name` and `description` are internal labels (no recipient sees them) and change WITHOUT creating a new version: a name fix must not leave contacts already inside on an older version. The name is not taken from the `journey`, or rewriting the DAG would bring back the name the automation was created with over a fix already made.\n\n`enrollSegmentId` sets (or removes, with `null`) the segment that enrolls on its own: whoever matches its conditions enters the flow, without waiting for an event. It is how to run reactivation and win-back, which start from something that did NOT happen (no open in 60 days) and for which there is no event to emit. The run is hourly and enrollment stays once-per-contact, so nobody enters twice. Mind the difference between **absent** and **null**: a field you do not name stays as it is, `null` clears it. Required scope: `automations:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:write"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAutomationInput"}}}},"responses":{"200":{"description":"Automation updated.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":["string","null"]},"enrollSegmentId":{"type":["string","null"],"format":"uuid"},"enrollmentsOnOlderVersions":{"type":"integer","description":"Contacts in flight on an older version. Message content reaches them (it is re-read at every send), structure and waits do not."}},"required":["id","name","description","enrollSegmentId","enrollmentsOnOlderVersions"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/automations/{id}/stats":{"get":{"tags":["Automations"],"summary":"Per-node aggregate of an automation","description":"How many contacts went through each step, how many were skipped and how many failed, plus enrollments by status. For each step that sends: absolute numbers and email rates (human and non-human opens, clicks, content clicks), the most clicked links with their role and the attributed conversions. Answers the question of whoever designed the flow (at which step half of the people stop, and what they really click); to know what happened to ONE contact use the step log instead. A node with many `skipped` is the first place to look. `?since=<ISO>` restricts to messages sent from that date, `revenue` included (orders attributed to those messages, whenever placed). `revenue`, overall and per node, is what the flow sold: orders attributed by the last click on the content, test runs excluded. Required scope: `automations:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:read"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"ISO 8601: only messages sent from this date."},"required":false,"name":"since","in":"query"},{"schema":{"type":"string","enum":["first","last"],"description":"Conversion model, `last` by default."},"required":false,"name":"attribution","in":"query"}],"responses":{"200":{"description":"Automation statistics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationStats"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/automations/{id}/restart":{"post":{"tags":["Automations"],"summary":"Restart contacts from the beginning of the flow","description":"Ends the run in progress and rewrites the contacts onto the version published today.\n\nUse it **only** for structural errors. Enrollment pins the version, the DAG travels inside the workflow and one enrollment per contact prevents re-entering: whoever entered on a version with an extra node or a wrong branch cannot be reached in any other way. A **text** error does not need it: message content is re-read from the current version at every send, so a PATCH of the journey is enough.\n\n**It is destructive**: the contact starts over and will see again the emails already received, which is why `confirm: true` is mandatory. The old run is marked as superseded and not deleted, so sent messages and the step log stay readable. Works only on `active` automations (409 on drafts and paused automations) and also answers 409 if none of the given contacts is inside the flow. Required scope: `automations:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:write"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationRestartRequest"}}}},"responses":{"202":{"description":"Restart queued.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"queued":{"type":"boolean"},"contacts":{"type":"integer","description":"Contacts found inside the flow, which will restart."},"notEnrolled":{"type":"integer","description":"Given but never entered in this automation."}},"required":["id","queued","contacts","notEnrolled"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/automations/{id}/export":{"get":{"tags":["Automations"],"summary":"Automation analysis export","description":"Everything needed to analyze a flow in a single document: overview, metrics per node, DAG structure (the node ids the other tables refer to), clicked links with their role, enrolled contacts row by row with the node they are on, and the log of steps traversed. Each table is CSV, with its definition next to it: 'opens' without saying they are human ones, and 'clicks' without saying they exclude the logo, are numbers an analyst reads at random.\n\nWithout `dataset` you get a single text file with all tables; with `dataset` you get that raw CSV. Test runs are excluded everywhere. Tables with one row per contact are cut at 10,000 (`enrollments`) and 50,000 rows (`steps`): the cut is declared in the file name and in the document, never silently.\n\nEmail addresses appear **only** if the key also carries `contacts:read`: `automations:read` alone returns no personal data anywhere else, and an export must not be the shortcut around that rule. Without it, rows stay identified by `contact_id`. Required scope: `automations:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["automations:read"],"parameters":[{"schema":{"type":"string","description":"Automation ID."},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["overview","nodes","journey","links","enrollments","steps"],"description":"A single table, as raw CSV."},"required":false,"name":"dataset","in":"query"}],"responses":{"200":{"description":"Analysis export.","content":{"text/markdown":{"schema":{"type":"string","description":"All tables in CSV blocks, with the metric definitions at the top."}},"text/csv":{"schema":{"type":"string","description":"The single requested table (UTF-8 BOM)."}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns":{"get":{"tags":["Campaigns"],"summary":"List campaigns","description":"Returns up to 100 campaigns of the workspace. With `?metrics=1` every row carries a summary of results (delivered, human opens, clicks, rates) computed in a single query. Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"`1` to include `metrics` on every campaign."},"required":false,"name":"metrics","in":"query"}],"responses":{"200":{"description":"Campaign list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Campaigns"],"summary":"Create a draft campaign","description":"Audience via list XOR segment. Required scope: `campaigns:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["campaigns:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignInput"}}}},"responses":{"201":{"description":"Campaign created.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking warnings: present only when there is something to report, e.g. {{...}} variables that match no contact field."}},"required":["id","status"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/campaigns/{id}":{"get":{"tags":["Campaigns"],"summary":"Get a campaign","description":"Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Campaign ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Campaign detail.","content":{"application/json":{"schema":{"type":"object","properties":{"campaign":{"$ref":"#/components/schemas/Campaign"}},"required":["campaign"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Campaigns"],"summary":"Update a draft campaign","description":"Updates only the fields present in the body: fixing a draft does not require recreating it. After scheduling the content is frozen and the change is rejected. Required scope: `campaigns:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["campaigns:write"],"parameters":[{"schema":{"type":"string","description":"Campaign ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCampaignDraft"}}}},"responses":{"200":{"description":"Campaign updated.","content":{"application/json":{"schema":{"type":"object","properties":{"campaign":{"$ref":"#/components/schemas/Campaign"},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-blocking warnings: present only when there is something to report, e.g. {{...}} variables that match no contact field."}},"required":["campaign"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/campaigns/{id}/estimate":{"post":{"tags":["Campaigns"],"summary":"Estimate the audience (dry run) and open the send confirmation","description":"Counts recipients without side effects and returns a confirmationToken: POST /campaigns/{id}/send needs it only for an immediate send or one within 5 minutes (scheduling further ahead does not require it). The token expires after 15 minutes. Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Campaign ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Audience estimate and confirmation token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignEstimate"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/campaigns/{id}/send":{"post":{"tags":["Campaigns"],"summary":"Schedule or send the campaign now","description":"`sendAt` absent, in the past or less than 5 minutes from now = immediate send: requires `confirmationToken` from POST /campaigns/{id}/estimate, because a real, irreversible send has no window to be corrected. A `sendAt` further ahead schedules without needing confirmation. Required scope: `email:send`.","security":[{"bearerAuth":[]}],"x-required-scope":["email:send"],"parameters":[{"schema":{"type":"string","description":"Campaign ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleCampaignBody"}}}},"responses":{"202":{"description":"Campaign scheduled or sending.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSendResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/campaigns/{id}/cancel":{"post":{"tags":["Campaigns"],"summary":"Cancel a scheduled or sending campaign","description":"Stops recipients not yet queued; those already queued in the fan-out are sent anyway. Required scope: `campaigns:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["campaigns:write"],"parameters":[{"schema":{"type":"string","description":"Campaign ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Campaign canceled.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"}},"required":["id","status"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns/{id}/metrics":{"get":{"tags":["Campaigns"],"summary":"Campaign results","description":"Deliveries, unique opens and clicks, unsubscribes, hard and soft bounces, complaints and derived rates. Opens count only events classified as human (Apple MPP and proxies excluded): compare campaigns on clicks, and on CONTENT clicks (`contentClicks`): a click rate made of logo clicks is not engagement. Optional blocks: `?timeseries=1|day|hour` (event series), `?links=1` (clicks per link, with role), `?conversions=1|last|first` (attributed conversions, with the list and the link that converted). `revenue` is always there: what the campaign sold, as orders attributed to its messages by the last click on the content within the workspace window (never a total across currencies). Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Campaign ID."},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"`1` or `day` for the daily series, `hour` for the hourly one."},"required":false,"name":"timeseries","in":"query"},{"schema":{"type":"string","description":"`1` to include `links`."},"required":false,"name":"links","in":"query"},{"schema":{"type":"string","description":"`1` or `last` for last touch, `first` for first touch."},"required":false,"name":"conversions","in":"query"}],"responses":{"200":{"description":"Campaign metrics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignMetrics"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns/{id}/export":{"get":{"tags":["Campaigns"],"summary":"Campaign analysis export","description":"Everything needed to analyze a campaign in a single document: overview, daily trend, clicked links with their role, recipients row by row with their behavior, unsubscribe reasons and attributed conversions. Each table is CSV, with its definition next to it: 'opens' without saying they are human ones, and 'clicks' without saying they exclude the logo, are numbers an analyst reads at random.\n\nWithout `dataset` you get a single text file with all tables; with `dataset` you get that raw CSV. Recipients are cut at 10,000 rows and the cut is declared in the file name and in the document, never silently.\n\nEmail addresses appear **only** if the key also carries `contacts:read`: `campaigns:read` alone returns no personal data anywhere else. Without it, rows stay identified by `contact_id`. Required scope: `campaigns:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["campaigns:read"],"parameters":[{"schema":{"type":"string","description":"Campaign ID."},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["overview","daily","links","recipients","unsubscribes","unsubscribe_comments","conversions"],"description":"A single table, as raw CSV."},"required":false,"name":"dataset","in":"query"}],"responses":{"200":{"description":"Analysis export.","content":{"text/markdown":{"schema":{"type":"string","description":"All tables in CSV blocks, with the metric definitions at the top."}},"text/csv":{"schema":{"type":"string","description":"The single requested table (UTF-8 BOM)."}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts":{"get":{"tags":["Contacts"],"summary":"List contacts","description":"Paginated list with search and filters. Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"tagId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"listId","in":"query"},{"schema":{"type":"string","enum":["subscribed","unsubscribed","unknown"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"pageSize","in":"query"}],"responses":{"200":{"description":"Page of contacts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"post":{"tags":["Contacts"],"summary":"Create or update a contact","description":"Creates the contact with its per-channel identities, or attaches to the one that already has one of those identities (the per-channel address is the natural key). Idempotent: repeating the same request answers 200 with `created: false` instead of failing. `attributes` are merged with the existing ones (`null` on a key deletes it) and `consent` is touched only if declared. 409 if the request's identities belong to different contacts: merging two contacts is irreversible and is not done automatically. On a NEW email identity, `warnings` flags a suspicious domain typo or an address already undeliverable on SES (suppressed immediately for this tenant): absent, never an empty array, when there is nothing to say. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContact"}}}},"responses":{"200":{"description":"Contact already existed, updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpserted"}}}},"201":{"description":"Contact created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpserted"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/contacts/{id}":{"get":{"tags":["Contacts"],"summary":"Get a contact","description":"Contact with channel identities, tags and lists. Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"parameters":[{"schema":{"type":"string","description":"Contact ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Contact.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactDetail"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Contacts"],"summary":"Delete a contact","description":"Deletes the contact: identities, tags, list memberships and automation enrollments are removed in cascade. Messages already sent remain (without the link to the contact) because they are delivery history and the basis of the monthly usage, and suppressions stay active. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"Contact ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Contact deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{id}/commerce":{"get":{"tags":["Contacts"],"summary":"Contact purchases","description":"Orders count, spent (per currency, never summed across currencies), average order value, first and last order, and the last 10 orders of the contact, from connected stores and the commerce API. Required scope: `commerce:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["commerce:read"],"parameters":[{"schema":{"type":"string","description":"Contact ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Contact purchases.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactCommerce"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{id}/conversions":{"get":{"tags":["Contacts"],"summary":"Contact conversion detail","description":"Contact conversions with value, time to conversion (first touch → conversion), touchpoints in the lookback window and attributed UTMs. Required scope: `utm:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["utm:read"],"parameters":[{"schema":{"type":"string","description":"Contact ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Contact conversions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactConversionList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{id}/journey":{"get":{"tags":["Contacts"],"summary":"Full contact timeline","description":"Sent messages (split into transactional/campaign/automation), emails written by the contact to agent inboxes, UTM touches and conversions, newest first. Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"parameters":[{"schema":{"type":"string","description":"Contact ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Contact timeline.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactJourney"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/contacts/{id}/tags":{"post":{"tags":["Contacts"],"summary":"Assign a tag to a contact","description":"Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"Contact ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagBody"}}}},"responses":{"201":{"description":"Tag assigned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"delete":{"tags":["Contacts"],"summary":"Remove a tag from a contact","description":"Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"Contact ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagBody"}}}},"responses":{"200":{"description":"Tag removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/lists":{"get":{"tags":["Lists"],"summary":"List lists","description":"Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"responses":{"200":{"description":"Lists with member count.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Lists"],"summary":"Create a list","description":"Idempotent on the name (case-insensitive comparison): if the list already exists it answers 200 with `created: false` and its id, instead of creating a namesake. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateListBody"}}}},"responses":{"200":{"description":"A list with this name already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NamedUpserted"}}}},"201":{"description":"List created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NamedUpserted"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/lists/{id}":{"delete":{"tags":["Lists"],"summary":"Delete a list","description":"Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"List ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"List deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Lists"],"summary":"Rename a list","description":"The name is the list's natural key (unique on tenant + lowercase name), so renaming is the only way to fix a wrong name without recreating the list and moving the contacts back in by hand. A name already taken answers 409. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"List ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListUpdate"}}}},"responses":{"200":{"description":"List updated.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":["id","name"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/lists/{id}/contacts":{"post":{"tags":["Lists"],"summary":"Add contacts to a list","description":"Idempotent. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"List ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMembersBody"}}}},"responses":{"201":{"description":"Contacts added.","content":{"application/json":{"schema":{"type":"object","properties":{"added":{"type":"integer"}},"required":["added"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"delete":{"tags":["Lists"],"summary":"Remove contacts from a list","description":"Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"List ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListMembersBody"}}}},"responses":{"200":{"description":"Contacts removed.","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"integer"}},"required":["removed"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/tags":{"get":{"tags":["Tags"],"summary":"List tags","description":"Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"responses":{"200":{"description":"Tags with contact count.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Tags"],"summary":"Create a tag","description":"Idempotent on the name (unique per workspace, case-insensitive): if the tag already exists it answers 200 with `created: false` and its id, so there is no 409 to handle and re-read. The color of a repeated request does not overwrite the existing tag's color. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTagInput"}}}},"responses":{"200":{"description":"A tag with this name already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NamedUpserted"}}}},"201":{"description":"Tag created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NamedUpserted"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/tags/{id}":{"patch":{"tags":["Tags"],"summary":"Rename a tag","description":"Changes name or color. The name is the tag's natural key: without renaming, fixing a wrong one means creating another and re-applying it by hand on every contact, losing along the way the automations that listen to that tag. A name already taken answers 409. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"Tag ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagUpdate"}}}},"responses":{"200":{"description":"Tag updated.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":["string","null"]}},"required":["id","name","color"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"delete":{"tags":["Tags"],"summary":"Delete a tag","description":"Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"Tag ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Tag deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/custom-fields":{"get":{"tags":["Custom Fields"],"summary":"List fields (system + custom)","description":"Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"responses":{"200":{"description":"Available fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomFieldList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Custom Fields"],"summary":"Create a custom field","description":"Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCustomFieldInput"}}}},"responses":{"201":{"description":"Field created.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"}},"required":["id","key"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/segments":{"get":{"tags":["Segments"],"summary":"List segments","description":"Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"responses":{"200":{"description":"Workspace segments.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Segments"],"summary":"Create a segment","description":"Validated rule tree (`AudienceRules`). Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSegment"}}}},"responses":{"201":{"description":"Segment created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Created"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/segments/{id}":{"patch":{"tags":["Segments"],"summary":"Update a segment","description":"At least one of name and rules. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"Segment ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSegment"}}}},"responses":{"200":{"description":"Segment updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Segment"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"delete":{"tags":["Segments"],"summary":"Delete a segment","description":"Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"parameters":[{"schema":{"type":"string","description":"Segment ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Segment deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/segments/preview":{"post":{"tags":["Segments"],"summary":"Preview an unsaved rule tree","description":"Count + sample. Required scope: `contacts:read` or `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read","contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentPreviewBody"}}}},"responses":{"200":{"description":"Audience preview.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SegmentPreview"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/events":{"post":{"tags":["Events"],"summary":"Ingest a behavioral event","description":"Records the event, applies UTM/conversion attribution and queues the automation. Provide `contactId` or `email` (at the top level of the body). With `idempotencyKey` (8-200 characters, e.g. the order id) the same repeated request answers 200 `duplicate` without recording a second event or a second conversion: a payment webhook delivered twice is the norm. Without a key every call is a new event. Required scope: `events:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["events:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventInput"}}}},"responses":{"200":{"description":"Same `idempotencyKey` already seen: nothing new recorded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventAccepted"}}}},"202":{"description":"Event accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventAccepted"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/domains":{"get":{"tags":["Domains"],"summary":"List domains","description":"Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Workspace domains.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Domains"],"summary":"Register a domain on SES","description":"SES onboarding (Easy DKIM + MAIL-FROM); returns the DNS records to publish. Required scope: `domains:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["domains:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomain"}}}},"responses":{"200":{"description":"Domain already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainCreated"}}}},"201":{"description":"Domain registered (pending).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainCreated"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"502":{"description":"Upstream provider error (e.g. SES).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/domains/{id}":{"get":{"tags":["Domains"],"summary":"Get a domain","description":"Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Domain ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Domain.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Domains"],"summary":"Default sender name and mailbox","description":"`defaultFromName` is the display name mail clients show for emails sent from this domain when the `from` is a bare address; a `from` with an explicit name wins over the default.\n\n`defaultFromAddress` is the mailbox sends leave from when they do not declare one, i.e. **automations**, which otherwise use `no-reply@<domain>` · an address that says not to reply under the name of a person who instead asks to be contacted. It must be on this domain.\n\nOnly the fields present are touched. Required scope: `domains:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["domains:write"],"parameters":[{"schema":{"type":"string","description":"Domain ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDomain"}}}},"responses":{"200":{"description":"Domain updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/domains/{id}/verify":{"post":{"tags":["Domains"],"summary":"Check the domain status on SES","description":"Queries SES and updates the status (idempotent). Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Domain ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Status updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainVerify"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream provider error (e.g. SES).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/domains/{id}/inbound":{"post":{"tags":["Domains"],"summary":"Enable inbound receiving on the domain","description":"Requires a verified domain. Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Domain ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Inbound enabled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainInbound"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream provider error (e.g. SES).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Domains"],"summary":"Disable inbound receiving on the domain","description":"Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Domain ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Inbound disabled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainInbound"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Upstream provider error (e.g. SES).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inboxes":{"get":{"tags":["Inboxes"],"summary":"List agent inboxes","description":"Required scope: `inbox:read`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:read"],"responses":{"200":{"description":"Workspace inboxes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Inboxes"],"summary":"Create an agent inbox","description":"Required scope: `inbox:write`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInboxInput"}}}},"responses":{"201":{"description":"Inbox created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxEnvelope"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/inboxes/metrics":{"get":{"tags":["Inboxes"],"summary":"Aggregate inbox metrics","description":"KPIs + daily volume + per inbox. Required scope: `inbox:read`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:read"],"responses":{"200":{"description":"Inbox metrics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxMetrics"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}}},"/inboxes/{id}":{"get":{"tags":["Inboxes"],"summary":"Get an inbox","description":"Required scope: `inbox:read`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:read"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Inbox detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxEnvelope"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Inboxes"],"summary":"Update an inbox","description":"Required scope: `inbox:write`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:write"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxPatch"}}}},"responses":{"200":{"description":"Inbox updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InboxEnvelope"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"delete":{"tags":["Inboxes"],"summary":"Delete an inbox","description":"Required scope: `inbox:write`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:write"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Inbox deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"string"}},"required":["deleted"]}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inboxes/{id}/send":{"post":{"tags":["Inboxes"],"summary":"Send an email from the inbox","description":"Required scope: `inbox:send`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:send"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendFromInboxInput"}}}},"responses":{"202":{"description":"Email queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/inboxes/{id}/threads":{"get":{"tags":["Inboxes"],"summary":"List the threads of a folder","description":"`folder` parameter (default `inbox`). Required scope: `inbox:read`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:read"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["inbox","starred","sent","drafts","important","scheduled","all","spam","unauthenticated","trash"],"description":"Folder (view) to list."},"required":false,"name":"folder","in":"query"}],"responses":{"200":{"description":"Threads of the folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inboxes/{id}/threads/{threadId}":{"get":{"tags":["Inboxes"],"summary":"Get a thread with its messages","description":"Required scope: `inbox:read`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:read"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Thread ID."},"required":true,"name":"threadId","in":"path"}],"responses":{"200":{"description":"Thread and messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadDetail"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/inboxes/{id}/threads/{threadId}/reply":{"post":{"tags":["Inboxes"],"summary":"Reply in a thread","description":"Required scope: `inbox:send`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:send"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","description":"Thread ID."},"required":true,"name":"threadId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyInput"}}}},"responses":{"202":{"description":"Reply queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/inboxes/{id}/drafts":{"post":{"tags":["Inboxes"],"summary":"Create a draft","description":"Required scope: `inbox:send`. (`inbox:*` scopes cannot be assigned from the UI: they require a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:send"],"parameters":[{"schema":{"type":"string","description":"Inbox ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDraftInput"}}}},"responses":{"201":{"description":"Draft created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftCreated"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/email-rules":{"get":{"tags":["Email Rules"],"summary":"List inbound allow/block rules","description":"Required scope: `inbox:read`. (`inbox:*` scope cannot be assigned from the UI: it requires a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:read"],"responses":{"200":{"description":"Workspace rules.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRuleList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Email Rules"],"summary":"Create an allow/block rule","description":"Precedence allow > block. Required scope: `inbox:write`. (`inbox:*` scope cannot be assigned from the UI: it requires a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailRuleInput"}}}},"responses":{"201":{"description":"Rule created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailRuleEnvelope"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/email-rules/{id}":{"delete":{"tags":["Email Rules"],"summary":"Delete a rule","description":"Required scope: `inbox:write`. (`inbox:*` scope cannot be assigned from the UI: it requires a full-access `*` key).","security":[{"bearerAuth":[]}],"x-required-scope":["inbox:write"],"parameters":[{"schema":{"type":"string","description":"Rule ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Rule deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","description":"Required scope: `webhooks:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["webhooks:read"],"responses":{"200":{"description":"Workspace webhooks.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook","description":"The signing `secret` is returned only once. Required scope: `webhooks:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["webhooks:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookInput"}}}},"responses":{"201":{"description":"Webhook created (with secret).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreated"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/webhooks/{id}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook","description":"Required scope: `webhooks:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["webhooks:read"],"parameters":[{"schema":{"type":"string","description":"Webhook ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Webhook detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Webhooks"],"summary":"Update a webhook","description":"Required scope: `webhooks:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["webhooks:write"],"parameters":[{"schema":{"type":"string","description":"Webhook ID."},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookInput"}}}},"responses":{"200":{"description":"Webhook updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","description":"Required scope: `webhooks:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["webhooks:write"],"parameters":[{"schema":{"type":"string","description":"Webhook ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Webhook deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}/deliveries":{"get":{"tags":["Webhooks"],"summary":"Delivery log of a webhook","description":"Required scope: `webhooks:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["webhooks:read"],"parameters":[{"schema":{"type":"string","description":"Webhook ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Recent deliveries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/utm/touches":{"get":{"tags":["UTM"],"summary":"List UTM touches","description":"Max 10k rows in CSV. Required scope: `utm:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["utm:read"],"parameters":[{"schema":{"type":"string","description":"ISO date, window start."},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","description":"ISO date, window end."},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","enum":["csv"],"description":"`csv` for the export."},"required":false,"name":"format","in":"query"},{"schema":{"type":"string"},"required":false,"name":"source","in":"query"},{"schema":{"type":"string"},"required":false,"name":"campaign","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"contactId","in":"query"},{"schema":{"type":["integer","null"]},"required":false,"name":"page","in":"query"},{"schema":{"type":["integer","null"]},"required":false,"name":"pageSize","in":"query"}],"responses":{"200":{"description":"UTM touches.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UtmTouchList"}},"text/csv":{"schema":{"type":"string","description":"CSV export (UTF-8 BOM)."}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/utm/summary":{"get":{"tags":["UTM"],"summary":"UTM aggregate by campaign/source/medium","description":"Required scope: `utm:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["utm:read"],"parameters":[{"schema":{"type":"string","description":"ISO date, window start."},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","description":"ISO date, window end."},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","enum":["csv"],"description":"`csv` for the export."},"required":false,"name":"format","in":"query"},{"schema":{"type":"string","enum":["first","last"],"description":"Attribution model (default `last`)."},"required":false,"name":"attribution","in":"query"}],"responses":{"200":{"description":"UTM aggregate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UtmSummary"}},"text/csv":{"schema":{"type":"string","description":"CSV export (UTF-8 BOM)."}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/utm/conversions":{"get":{"tags":["UTM"],"summary":"List attributed conversions","description":"Max 10k rows in CSV. Required scope: `utm:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["utm:read"],"parameters":[{"schema":{"type":"string","description":"ISO date, window start."},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","description":"ISO date, window end."},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","enum":["csv"],"description":"`csv` for the export."},"required":false,"name":"format","in":"query"},{"schema":{"type":"string","enum":["event","stripe","posthog"]},"required":false,"name":"source","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"contactId","in":"query"},{"schema":{"type":["integer","null"]},"required":false,"name":"page","in":"query"},{"schema":{"type":["integer","null"]},"required":false,"name":"pageSize","in":"query"}],"responses":{"200":{"description":"Attributed conversions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UtmConversionList"}},"text/csv":{"schema":{"type":"string","description":"CSV export (UTF-8 BOM)."}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/utm/conversions/stats":{"get":{"tags":["UTM"],"summary":"Conversion aggregate by goal","description":"Per conversion name: volumes, unique contacts, revenue, average time to conversion (from first touch) and average touchpoints in the lookback window. Required scope: `utm:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["utm:read"],"parameters":[{"schema":{"type":"string","description":"ISO date, window start."},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","description":"ISO date, window end."},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"Aggregate by goal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UtmConversionStats"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/integrations/posthog/sync":{"post":{"tags":["Integrations"],"summary":"Import conversions from PostHog","description":"HogQL pull with a cursor. Required scope: `integrations:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["integrations:write"],"responses":{"200":{"description":"Sync completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PosthogSyncResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/commerce/products":{"put":{"tags":["Commerce"],"summary":"Bulk upsert of the product catalog","description":"Idempotent on `externalId` (source `api`), max 500 per call. Required scope: `commerce:write`. Requires a plan with the `ecommerce` feature.","security":[{"bearerAuth":[]}],"x-required-scope":["commerce:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"products":{"type":"array","items":{"$ref":"#/components/schemas/CommerceProductInput"},"minItems":1,"maxItems":500}},"required":["products"]}}}},"responses":{"200":{"description":"Products upserted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceUpsertResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"get":{"tags":["Commerce"],"summary":"List catalog products","description":"Excludes deleted ones. Required scope: `commerce:read`. Requires a plan with the `ecommerce` feature.","security":[{"bearerAuth":[]}],"x-required-scope":["commerce:read"],"parameters":[{"schema":{"type":"string","description":"Search on title."},"required":false,"name":"q","in":"query"},{"schema":{"type":["integer","null"],"description":"Default 50, max 200."},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Cursor on `updatedAt` (ISO)."},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Catalog products.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceProductList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}}},"/commerce/products/{externalId}":{"delete":{"tags":["Commerce"],"summary":"Soft delete a product","description":"Required scope: `commerce:write`. Requires a plan with the `ecommerce` feature.","security":[{"bearerAuth":[]}],"x-required-scope":["commerce:write"],"parameters":[{"schema":{"type":"string","description":"External id of the product."},"required":true,"name":"externalId","in":"path"}],"responses":{"200":{"description":"Product deleted (soft).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceDeleteResult"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}}},"/commerce/carts":{"post":{"tags":["Commerce"],"summary":"Upsert a cart","description":"Idempotent on `externalId`. Queues a delayed abandonment check that emits the `cart_abandoned` event. A new cart whose email matches an existing contact emits `started_checkout` once per `externalId`. Required scope: `commerce:write`. Requires a plan with the `ecommerce` feature.","security":[{"bearerAuth":[]}],"x-required-scope":["commerce:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceCartInput"}}}},"responses":{"202":{"description":"Cart accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceAccepted"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/commerce/orders":{"post":{"tags":["Commerce"],"summary":"Notify a paid order","description":"Closes the source cart, emits `order_paid`, `placed_order` and one `ordered_product` per item, and records the conversion. A buyer who is not a contact yet is created as a transactional-only contact (consent `not_subscribed`: receipts and notices, no marketing campaigns or automations, and not counted toward the plan's contact limit) instead of dropping the order. The events are deduplicated on `externalId`: sending the same order again returns 202 without emitting second events or starting post-purchase automations twice. Required scope: `commerce:write`. Requires a plan with the `ecommerce` feature.","security":[{"bearerAuth":[]}],"x-required-scope":["commerce:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceOrderInput"}}}},"responses":{"202":{"description":"Order accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceAccepted"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Plan quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaError"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"get":{"tags":["Commerce"],"summary":"List orders","description":"Orders from connected stores and from `POST /commerce/orders`, newest first. `attributedMessageId` is the marketing message credited with the order (last content click in the window). Required scope: `commerce:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["commerce:read"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":false,"name":"contactId","in":"query"},{"schema":{"type":"string","enum":["placed","fulfilled","cancelled"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"date-time","description":"Orders placed at or after this instant (ISO 8601, offset allowed)."},"required":false,"name":"since","in":"query"},{"schema":{"type":["integer","null"],"description":"Default 50, max 200."},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"`nextCursor` of the previous page; an unreadable cursor is a 422 `invalid_cursor`."},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Orders.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommerceOrderList"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/usage":{"get":{"tags":["Usage"],"summary":"Usage snapshot against the plan","description":"Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Usage snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSnapshot"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/settings/frequency-cap":{"get":{"tags":["Usage"],"summary":"Per-contact frequency cap","description":"Requires authentication only (any valid API key).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current frequency cap. With the cap on it includes `impact`: how many messages were dropped or deferred in the last 30 days, and how many contacts were affected.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FrequencyCapWithImpact"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Usage"],"summary":"Set the frequency cap","description":"At most `max` MARKETING messages per contact every `days` days. Needed because no flow knows about the others: someone who joins a list on Monday, clicks on Tuesday and has an event during the week gets four emails in three days without anyone having decided it. Transactional messages are never held and do not count. Out-of-range values are clamped into the limits instead of being rejected. Required scope: `settings:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["settings:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FrequencyCapUpdate"}}}},"responses":{"200":{"description":"Cap updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FrequencyCap"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/imports/activecampaign":{"post":{"tags":["Imports"],"summary":"Start an ActiveCampaign import","description":"Configures the credentials in the same call (`apiUrl`+`apiKey`, together) or uses the saved ones, then queues the import. Required scope: `contacts:write`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:write"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartAcImportBody"}}}},"responses":{"202":{"description":"Import queued: job id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Created"}}}},"400":{"description":"Invalid AC credentials or connection failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"409":{"description":"State conflict (e.g. duplicate).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/imports":{"get":{"tags":["Imports"],"summary":"List imports","description":"Required scope: `contacts:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read"],"responses":{"200":{"description":"Workspace imports.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListImportJobsResponse"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}}}}},"/imports/{id}":{"get":{"tags":["Imports"],"summary":"Get an import","description":"Required scope: `contacts:read`.","security":[{"bearerAuth":[]}],"x-required-scope":["contacts:read"],"parameters":[{"schema":{"type":"string","description":"Import job ID."},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Import detail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportJobResponse"}}}},"401":{"description":"Missing or invalid token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Insufficient scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForbiddenError"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}