{"openapi":"3.1.0","info":{"title":"Sendinel API","version":"1.0","description":"Sendinel public REST API.\nAuthenticate with an API key. Approved first-party integrations may use a\nshort-lived scoped JWT:\nAuthorization: Bearer <token>\n"},"servers":[{"url":"https://sendinel.ai/api/v1","description":"Production"},{"url":"http://localhost:3000/api/v1","description":"Local development"}],"security":[{"ApiKeyAuth":[]},{"OAuth2":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key or scoped JWT"},"OAuth2":{"type":"oauth2","description":"OAuth 2.0 authorization code flow with PKCE (RFC 7636).\nDiscovery: https://sendinel.ai/.well-known/oauth-authorization-server\nResource metadata: https://sendinel.ai/.well-known/oauth-protected-resource\n","flows":{"authorizationCode":{"authorizationUrl":"https://sendinel.ai/oauth/authorize","tokenUrl":"https://sendinel.ai/oauth/token","refreshUrl":"https://sendinel.ai/oauth/token","scopes":{"contacts":"Contacts, lists, and email logs","campaigns":"Campaign management and sending","analytics":"Stats, deliverability health, and reporting","segments":"Audience segments","drafts":"AI drafts","sites":"Sending sites","read":"Read-only access","write":"Read and write access","admin":"Full administrative access"}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}}}}},"AiContextEvent":{"type":"object","required":["source","workspace_id","project_id","event_type","title","detail","idempotency_key"],"properties":{"source":{"type":"string","enum":["synchronex"]},"workspace_id":{"type":"string"},"project_id":{"type":"string","format":"uuid"},"event_type":{"type":"string","enum":["strategic_segment_intent","business_priority","customer_journey_signal","campaign_opportunity","risk_signal"]},"title":{"type":"string"},"detail":{"type":"string"},"evidence":{"type":"object","additionalProperties":true},"suggested_actions":{"type":"array","items":{"type":"object","additionalProperties":true}},"idempotency_key":{"type":"string"}}},"Site":{"type":"object","required":["id","name","slug","from_email"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"from_name":{"type":"string"},"from_email":{"type":"string","format":"email"},"sending_domain":{"type":"string"},"website_url":{"type":"string","format":"uri","nullable":true},"active":{"type":"boolean"}}},"Contact":{"type":"object","required":["id","email"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"first_name":{"type":"string","nullable":true},"last_name":{"type":"string","nullable":true},"company_id":{"type":"string","format":"uuid","nullable":true},"company":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"domain":{"type":"string","nullable":true}}},"tags":{"type":"array","items":{"type":"string"}},"lifecycle_stage":{"type":"string","nullable":true},"global_unsubscribed":{"type":"boolean"}}},"SegmentRule":{"type":"object","additionalProperties":true},"Segment":{"type":"object","required":["id","name","rules"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"rules":{"$ref":"#/components/schemas/SegmentRule"}}},"Template":{"type":"object","required":["id","name","category","brief_template"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"category":{"type":"string"},"description":{"type":"string"},"subject_hint":{"type":"string"},"brief_template":{"type":"string"},"body_html":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"}}}},"CampaignStep":{"type":"object","required":["id","campaign_id","step_order","subject"],"properties":{"id":{"type":"string","format":"uuid"},"campaign_id":{"type":"string","format":"uuid"},"step_order":{"type":"integer"},"subject":{"type":"string"},"body_html":{"type":"string","nullable":true},"body_text":{"type":"string","nullable":true},"delay_days":{"type":"integer"},"delay_hours":{"type":"integer"}}},"Campaign":{"type":"object","required":["id","site_id","name","type","status"],"properties":{"id":{"type":"string","format":"uuid"},"site_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["sequence","broadcast","triggered"]},"status":{"type":"string","enum":["draft","active","paused","archived"]},"description":{"type":"string","nullable":true}}},"EventRequest":{"type":"object","required":["event"],"properties":{"event":{"type":"string"},"email":{"type":"string","format":"email"},"user_id":{"type":"string"},"properties":{"type":"object","additionalProperties":true}}},"TriggerRequest":{"type":"object","required":["event"],"properties":{"event":{"type":"string"},"email":{"type":"string","format":"email"},"properties":{"type":"object","additionalProperties":true}}},"SendRequest":{"type":"object","required":["site_id","to","subject"],"properties":{"site_id":{"type":"string","format":"uuid"},"to":{"type":"string","format":"email"},"subject":{"type":"string"},"html":{"type":"string"},"text":{"type":"string"}}},"ConversionRequest":{"type":"object","required":["event"],"properties":{"event":{"type":"string"},"email":{"type":"string","format":"email"},"value":{"type":"number"},"properties":{"type":"object","additionalProperties":true}}},"SynchronexProvisionRequest":{"type":"object","required":["owner_email","bundle","synchronex_user_id"],"properties":{"owner_email":{"type":"string","format":"email"},"bundle":{"type":"string","enum":["synchronex_pro"]},"synchronex_user_id":{"type":"string"},"synchronex_team_id":{"type":"string","description":"Synchronex team to link to the provisioned Sendinel organization."},"synchronex_account_id":{"type":"string"},"synchronex_account_no":{"type":"string"},"synchronex_workspace_id":{"type":"string"},"synchronex_workspace_name":{"type":"string"},"synchronex_brand_id":{"type":"string"},"synchronex_brand_name":{"type":"string"},"period_start":{"type":"string","format":"date-time"},"period_end":{"type":"string","format":"date-time"},"approval_mode":{"type":"string","enum":["standard","autonomous"],"description":"Optional. Written to email.projects.approval_mode on create. Omitted means standard, matching the column default. On an idempotent re-provision the stored value changes only when this field is sent."}}},"SynchronexProvisionResponse":{"type":"object","required":["project_id","org_id","project_api_key","send_cap","cap_context"],"properties":{"project_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid","description":"Persist this as the linked Sendinel organization for the Synchronex team."},"project_api_key":{"type":"string","nullable":true,"description":"Returned only when a new project key is created."},"send_cap":{"type":"integer","example":10000},"cap_context":{"type":"string","enum":["synchronex_bundle"]},"approval_mode":{"type":"string","enum":["standard","autonomous"],"description":"Present when this call wrote approval_mode. Omitted when an idempotent call left the stored value unchanged."}}},"ServiceProjectLookupResponse":{"type":"object","required":["project_id","org_id","project_name","plan","sites"],"properties":{"project_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"project_name":{"type":"string"},"plan":{"type":"string"},"sites":{"type":"array","items":{"type":"object","required":["site_id","site_name"],"properties":{"site_id":{"type":"string","format":"uuid"},"site_name":{"type":"string"},"sending_domain":{"type":"string","nullable":true},"website_url":{"type":"string","format":"uri","nullable":true}}}},"synchronex_team_id":{"type":"string","nullable":true},"synchronex_workspace_id":{"type":"string","nullable":true},"synchronex_workspace_name":{"type":"string","nullable":true},"synchronex_brand_id":{"type":"string","nullable":true},"synchronex_brand_name":{"type":"string","nullable":true}}}},"responses":{"BadRequest":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_error","message":"Request validation failed"}}}}},"Unauthorized":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Invalid or missing API key"}}}}},"Forbidden":{"description":"Credential lacks the required scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"Missing required scope"}}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Resource not found"}}}}},"RateLimited":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limited","message":"Too many requests"}}}}},"Conflict":{"description":"The request conflicts with the resource's current state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"Conflict with current state"}}}}},"Unprocessable":{"description":"The request is well-formed but cannot be processed as sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unprocessable","message":"Request cannot be processed"}}}}}}},"paths":{"/approvals":{"get":{"summary":"List approval requests","parameters":[{"name":"status","in":"query","schema":{"type":"string","default":"pending"},"example":"string"},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100},"example":1}],"responses":{"200":{"description":"Approval requests"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getApprovals","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/approvals/{id}":{"get":{"summary":"Get approval status without consuming it","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Approval status"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getApprovalsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/platform-connections/{id}/events":{"get":{"summary":"List events for a platform connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100},"example":1}],"responses":{"200":{"description":"Platform events"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getPlatformConnectionsByIdEvents","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/platform-connections":{"get":{"summary":"List platform connections","responses":{"200":{"description":"Platform connections"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getPlatformConnections","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create or update a platform connection","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["platform","credentials"],"properties":{"platform":{"type":"string"},"display_name":{"type":"string"},"credentials":{"type":"object","additionalProperties":true},"config":{"type":"object","additionalProperties":true}}},"example":{"platform":"string","credentials":{}}}}},"responses":{"201":{"description":"Platform connection created or updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postPlatformConnections","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/platform-connections/{id}":{"delete":{"summary":"Disconnect a platform connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Platform connection removed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deletePlatformConnectionsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/platform-connections/{id}/import":{"post":{"summary":"Trigger a contact/data import for a platform connection","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"artifact_types":{"type":"array","items":{"type":"string","enum":["contacts","templates","campaigns","suppressions","segments","enrollments","newsletters","broadcasts","transactional","snippets","collections","messages"]}},"options":{"type":"object","additionalProperties":true},"field_mapping":{"type":"object","additionalProperties":{"type":"string"}}}},"example":{}}}},"responses":{"200":{"description":"Import job created or updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Platform connection not found"},"409":{"description":"Platform connection is inactive"},"422":{"description":"Platform does not support imports, or stored credentials are invalid"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postPlatformConnectionsByIdImport","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/platform-connections/{id}/triggers":{"post":{"summary":"Configure platform trigger mappings","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["triggers"],"properties":{"triggers":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"example":{"triggers":[{}]}}}},"responses":{"200":{"description":"Trigger mappings updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postPlatformConnectionsByIdTriggers","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/dmarc/status":{"get":{"summary":"Get DMARC inbound status, Cloudflare setup, and monitor state","parameters":[{"name":"site_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"DMARC status"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDmarcStatus","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/dmarc/publish-cloudflare":{"post":{"summary":"Publish or preview the merged DMARC record in the organization's connected Cloudflare zone","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"},"dry_run":{"type":"boolean"}}},"example":{"domain":"string"}}}},"responses":{"200":{"description":"DMARC record published or previewed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDmarcPublishCloudflare","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/dmarc/monitors":{"get":{"summary":"List DMARC monitors","responses":{"200":{"description":"DMARC monitors"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDmarcMonitors","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Enable DMARC monitoring for a domain","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"}}},"example":{"domain":"string"}}}},"responses":{"201":{"description":"DMARC monitor enabled"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDmarcMonitors","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/dmarc/monitors/{domain}":{"get":{"summary":"Get DMARC monitor detail","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"DMARC monitor detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDmarcMonitorsByDomain","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"delete":{"summary":"Disable a DMARC monitor","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"DMARC monitor disabled"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteDmarcMonitorsByDomain","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/migrations/campaigns":{"post":{"summary":"Start a campaign migration import job","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider"],"properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"oauth_token":{"type":"string"},"platform_connection_id":{"type":"string","format":"uuid"}}},"example":{"provider":"string"}}}},"responses":{"201":{"description":"Migration job created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postMigrationsCampaigns","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/migrations":{"get":{"summary":"List migration jobs","responses":{"200":{"description":"Migration jobs"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getMigrations","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/migrations/{id}":{"get":{"summary":"Get a migration job and log history","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Migration job status"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getMigrationsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/org/usage":{"get":{"summary":"Get organization usage","responses":{"200":{"description":"Organization usage"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getOrgUsage","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/org/members":{"get":{"summary":"List organization members","responses":{"200":{"description":"Organization members"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getOrgMembers","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Add, update, or invite an organization member","description":"The requested organization must own the authenticated project. A viewer request grants the view-only tester role on the membership or invitation; admin and member are unchanged.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["org_id","email","role"],"properties":{"org_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["admin","member","viewer"],"description":"viewer maps to the view-only tester role, which cannot send."}}},"example":{"org_id":"00000000-0000-4000-8000-000000000000","email":"user@example.com","role":"admin"}}}},"responses":{"200":{"description":"Existing member or invitation returned"},"201":{"description":"Member or invitation created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Project/organization mismatch or plan member limit reached"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"description":"Invalid org_id, email, or role"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postOrgMembers","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/org/members/{userId}":{"delete":{"summary":"Remove an organization member","description":"Organization owners cannot be removed through this endpoint.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["org_id"],"properties":{"org_id":{"type":"string","format":"uuid"}}},"example":{"org_id":"00000000-0000-4000-8000-000000000000"}}}},"responses":{"200":{"description":"Member removed or already absent"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Project/organization mismatch or owner removal attempted"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteOrgMembersByUserId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/org/invitations":{"post":{"summary":"Create or dedupe an organization invitation","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["admin","member"]}}},"example":{"email":"user@example.com"}}}},"responses":{"201":{"description":"Invitation created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postOrgInvitations","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/org/plans":{"get":{"summary":"List available plan limits","responses":{"200":{"description":"Plan limits"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getOrgPlans","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/automations":{"get":{"summary":"List automation sources","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1},{"in":"query","name":"status","schema":{"type":"string","enum":["active","paused"]},"example":"active"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"source_type","schema":{"type":"string","enum":["rss","webhook","schedule","github"]},"example":"rss"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"}],"responses":{"200":{"description":"Automation list with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAutomations","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create an automation source","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","source_type","site_id"],"properties":{"name":{"type":"string"},"source_type":{"type":"string","enum":["rss","webhook","schedule","github"]},"site_id":{"type":"string","format":"uuid"},"format":{"type":"string"},"feed_url":{"type":"string"},"schedule_cron":{"type":"string"},"brief_template":{"type":"string"},"max_words":{"type":"integer"},"tone_override":{"type":"string"},"cta_url":{"type":"string"},"cta_text":{"type":"string"},"github_repo":{"type":"string"},"github_label_filter":{"type":"string"}}},"example":{"name":"string","source_type":"rss","site_id":"00000000-0000-4000-8000-000000000000"}}}},"responses":{"201":{"description":"Automation created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAutomations","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/automations/{id}":{"get":{"summary":"Get an automation source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Automation source detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAutomationsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update an automation source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Automation source updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchAutomationsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Delete an automation source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Automation deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteAutomationsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/automations/{id}/history":{"get":{"summary":"List automation trigger history","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1},{"in":"query","name":"status","schema":{"type":"string","enum":["pending","drafted","approved","sent","skipped"]},"example":"pending"},{"in":"query","name":"start_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"end_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"}],"responses":{"200":{"description":"Automation history with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAutomationsByIdHistory","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/automations/{id}/preview":{"get":{"summary":"Preview recent automation source items","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Automation preview items"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAutomationsByIdPreview","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/automations/enroll":{"post":{"summary":"Enroll a subscriber into a triggered campaign","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subscriber_id"],"properties":{"subscriber_id":{"type":"string","format":"uuid"},"campaign_id":{"type":"string","format":"uuid"},"site_id":{"type":"string","format":"uuid"},"trigger_event_name":{"type":"string"},"trigger_tag":{"type":"string"},"next_send_at":{"type":"string","format":"date-time"},"context":{"type":"object","additionalProperties":true}}},"example":{"subscriber_id":"00000000-0000-4000-8000-000000000000"}}}},"responses":{"200":{"description":"Enrollment result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAutomationsEnroll","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/automations/{id}/pause":{"post":{"summary":"Pause an automation source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Automation paused"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAutomationsByIdPause","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/automations/{id}/resume":{"post":{"summary":"Resume an automation source","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Automation resumed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAutomationsByIdResume","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/automations/{id}/trigger":{"post":{"summary":"Trigger automation draft generation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"200":{"description":"Trigger result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAutomationsByIdTrigger","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/social-posts/adapt":{"post":{"summary":"Adapt content into social posts","responses":{"200":{"description":"Adapted social copy"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSocialPostsAdapt","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/advisor/subject-lines":{"post":{"summary":"Generate or create subject line variants","responses":{"200":{"description":"Subject line recommendations"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAdvisorSubjectLines","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/advisor/content-topics":{"get":{"summary":"Recommend content topics","responses":{"200":{"description":"Content topic recommendations"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAdvisorContentTopics","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/advisor/campaign/{id}":{"get":{"summary":"Get campaign advisor recommendations","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Campaign advisor result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAdvisorCampaignById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/advisor/send-time":{"get":{"summary":"Recommend send times","responses":{"200":{"description":"Send time recommendations"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAdvisorSendTime","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/advisor/recovery-plan":{"get":{"summary":"Recommend deliverability recovery actions","responses":{"200":{"description":"Recovery plan"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAdvisorRecoveryPlan","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/advisor/portfolio-analysis":{"get":{"summary":"Analyze portfolio email performance","responses":{"200":{"description":"Portfolio analysis"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAdvisorPortfolioAnalysis","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/sites/{id}/warmup":{"patch":{"summary":"Update, pause, or resume site warmup schedule","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"200":{"description":"Warmup schedule"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchSitesByIdWarmup","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/sites/{id}/dnsbl":{"get":{"summary":"Get latest DNSBL snapshots for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"DNSBL snapshots"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdDnsbl","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/send-queue/dlq":{"get":{"summary":"List dead-letter queue entries for a site project","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"unresolved_only","in":"query","schema":{"type":"boolean","default":true},"example":true}],"responses":{"200":{"description":"Dead-letter queue entries"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdSendQueueDlq","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/enrollment-dlq":{"get":{"summary":"List dead-lettered campaign enrollments for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"unresolved_only","in":"query","schema":{"type":"boolean","default":true},"example":true},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"example":1}],"responses":{"200":{"description":"Enrollment dead-letter queue entries"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdEnrollmentDlq","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/enrollment-dlq/replay":{"post":{"summary":"Replay dead-lettered campaign enrollments for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"max_count":{"type":"integer","minimum":1,"maximum":1000,"default":100},"failed_after":{"type":"string","format":"date-time"}}},"example":{}}}},"responses":{"200":{"description":"Replayed and skipped enrollment counts"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSitesByIdEnrollmentDlqReplay","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/sites/{id}/send-queue":{"get":{"summary":"Get queued and scheduled send status for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Queue summary by channel, audience size, and next send time"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdSendQueue","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/send-queue/cancel":{"post":{"summary":"Cancel unclaimed queued sends for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"campaign_id":{"type":"string","format":"uuid"},"created_before":{"type":"string","format":"date-time"}}},"example":{}}}},"responses":{"200":{"description":"Queue rows cancelled"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSitesByIdSendQueueCancel","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/sites/{id}/send-queue/retry":{"post":{"summary":"Make unclaimed retry rows immediately eligible for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"campaign_id":{"type":"string","format":"uuid"},"queue_ids":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string","format":"uuid"}}}},"example":{}}}},"responses":{"200":{"description":"Queue rows made immediately eligible"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSitesByIdSendQueueRetry","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/sites/{id}/send-queue/rows":{"get":{"summary":"List individual queued sends with retry details for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"campaign_id","in":"query","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"status","in":"query","description":"Comma-separated queue statuses","schema":{"type":"string","example":"pending,retry"},"example":"pending,retry"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"example":1}],"responses":{"200":{"description":"Individual queued sends with errors and next retry times"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdSendQueueRows","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/send-queue/resend":{"post":{"summary":"Requeue DLQ sends for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"max_count":{"type":"integer","minimum":1,"maximum":1000},"failed_after":{"type":"string","format":"date-time"}}},"example":{}}}},"responses":{"200":{"description":"DLQ sends requeued"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSitesByIdSendQueueResend","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/sites/{id}/send-queue/throttle":{"post":{"summary":"Set or clear a per-site send throttle","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["send_rate_limit"],"properties":{"send_rate_limit":{"nullable":true,"oneOf":[{"type":"integer","minimum":1,"maximum":100000},{"type":"null"}]}}},"example":{}}}},"responses":{"200":{"description":"Throttle updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSitesByIdSendQueueThrottle","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/sites/{id}/smart-schedule":{"get":{"summary":"Recommend best send windows for a site","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"campaign_type","in":"query","schema":{"type":"string","enum":["email","sms","social"]},"example":"email"}],"responses":{"200":{"description":"Recommended send windows from historical audience activity"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdSmartSchedule","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/gdpr":{"post":{"summary":"Delete a contact and related data under GDPR workflow","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contact_id"],"properties":{"contact_id":{"type":"string","format":"uuid"},"reason":{"type":"string"}}},"example":{"contact_id":"00000000-0000-4000-8000-000000000000"}}}},"responses":{"200":{"description":"GDPR delete result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postGdpr","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/identify":{"post":{"summary":"Identify or upsert a contact profile","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"},"example":{"id":"00000000-0000-4000-8000-000000000000","email":"user@example.com"}}}},"responses":{"200":{"description":"Contact identified"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postIdentify","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/events":{"get":{"summary":"List recorded contact events","parameters":[{"in":"query","name":"contact_email","schema":{"type":"string","format":"email"},"example":"user@example.com"},{"in":"query","name":"event_type","schema":{"type":"string"},"example":"string"},{"in":"query","name":"limit","schema":{"type":"integer","maximum":500},"example":1}],"responses":{"200":{"description":"Events"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getEvents","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Record a custom event","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventRequest"},"example":{"event":"string"}}}},"responses":{"202":{"description":"Event accepted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postEvents","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/trigger":{"post":{"summary":"Trigger automation evaluation for a contact event","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerRequest"},"example":{"event":"string"}}}},"responses":{"202":{"description":"Trigger accepted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postTrigger","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/send":{"post":{"summary":"Send a transactional email","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendRequest"},"example":{"site_id":"00000000-0000-4000-8000-000000000000","to":"user@example.com","subject":"string"}}}},"responses":{"202":{"description":"Send accepted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSend","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/sms/send":{"post":{"summary":"Send an SMS message","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to_number","body"],"properties":{"to_number":{"type":"string","example":"+14155551234"},"body":{"type":"string"},"site_id":{"type":"string","format":"uuid"},"contact_id":{"type":"string","format":"uuid"},"campaign_id":{"type":"string","format":"uuid"},"campaign_step_id":{"type":"string","format":"uuid"},"classification":{"type":"string","enum":["marketing","transactional","conversational"]}}},"example":{"to_number":"+14155551234","body":"string"}}}},"responses":{"200":{"description":"SMS sent"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSmsSend","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/sms/consent":{"post":{"summary":"Set contact SMS consent (opt-in/opt-out)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contact_id"],"properties":{"contact_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["opt_in","opt_out"],"default":"opt_in"},"source":{"type":"string","default":"api"},"consent_text":{"type":"string","nullable":true}}},"example":{"contact_id":"00000000-0000-4000-8000-000000000000"}}}},"responses":{"200":{"description":"Consent saved"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSmsConsent","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/sms":{"post":{"summary":"Send an SMS message (alias of /sms/send)","responses":{"200":{"description":"SMS sent"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSms","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/sms/campaigns":{"post":{"summary":"Create an SMS campaign","responses":{"201":{"description":"SMS campaign created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSmsCampaigns","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/sms/log":{"get":{"summary":"List SMS delivery log rows","responses":{"200":{"description":"SMS log"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSmsLog","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/sms/inbound":{"get":{"summary":"List inbound SMS replies","responses":{"200":{"description":"Inbound SMS replies"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSmsInbound","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/sms/provider":{"get":{"summary":"Get default SMS provider status","responses":{"200":{"description":"SMS provider status"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSmsProvider","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/sms/cost-preview":{"get":{"summary":"Estimate SMS send cost","parameters":[{"in":"query","name":"body","required":true,"schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"SMS cost estimate"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSmsCostPreview","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/provision":{"post":{"summary":"Provision an account-scoped messaging channel","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","enum":["sms","whatsapp","telegram"],"default":"sms"},"provider":{"type":"string","enum":["telnyx","twilio","meta","telegram"]},"friendly_name":{"type":"string"},"area_code":{"type":"string","description":"3-digit US area code for managed SMS provisioning"},"phone_number":{"type":"string","description":"Required for Twilio BYO when channel=sms"},"credentials":{"type":"object","additionalProperties":true,"description":"Provider-specific BYO credentials:\n- Twilio SMS: account_sid, auth_token\n- WhatsApp Meta: access_token, phone_number_id, business_account_id?, verify_token?, app_secret?\n- Telegram: bot_token, bot_username?\n"}}},"example":{}}}},"responses":{"200":{"description":"Existing active provision returned idempotently"},"201":{"description":"Channel provisioned"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postProvision","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/provision/{channel_handle}":{"delete":{"summary":"Deprovision an account-scoped messaging channel","parameters":[{"in":"path","name":"channel_handle","required":true,"schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"Channel deprovisioned"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteProvisionByChannelHandle","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/channels/send":{"post":{"summary":"Send an outbound channel message through the account-scoped transport","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId","channel","to","body","clientMessageId"],"properties":{"accountId":{"type":"string","format":"uuid","channel":{"type":"string","enum":["sms","whatsapp","telegram"]}},"to":{"type":"object","description":"Exactly one of contactId, handle, or broadcastListId","properties":{"contactId":{"type":"string"},"handle":{"type":"string"},"broadcastListId":{"type":"string"}}},"body":{"type":"string"},"clientMessageId":{"type":"string"},"attachments":{"type":"array","description":"Optional for SMS. WhatsApp and Telegram attachment delivery is not implemented yet.","items":{"type":"object","additionalProperties":true}}}},"example":{"accountId":"00000000-0000-4000-8000-000000000000","to":{},"body":"string","clientMessageId":"string"}}}},"responses":{"200":{"description":"Message accepted or idempotently returned"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postChannelsSend","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/conversion":{"post":{"summary":"Record a conversion event","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionRequest"},"example":{"event":"string"}}}},"responses":{"202":{"description":"Conversion accepted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postConversion","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/domains":{"get":{"summary":"List sending domains","responses":{"200":{"description":"Sending domains with linked senders and DNS status"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDomains","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Register a sending domain","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"region":{"type":"string"}}},"example":{"name":"string"}}}},"responses":{"201":{"description":"Domain registered"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDomains","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/domains/{id}":{"get":{"summary":"Get sending domain detail","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Domain detail including expected DNS records"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDomainsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"delete":{"summary":"Delete a sending domain","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Domain deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteDomainsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/domains/{id}/health":{"get":{"summary":"Get sending domain health history","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":90},"example":1}],"responses":{"200":{"description":"Domain health and warmup history across linked sites"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDomainsByIdHealth","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/domains/{id}/verify":{"post":{"summary":"Trigger sending domain verification","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Verification result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDomainsByIdVerify","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/service/projects/provision":{"post":{"summary":"Provision a Synchronex-bundled Sendinel project","description":"Customer bundle provisioning only. Requires a service API key with the service:provision scope. The internal Synchronex platform project is intentionally excluded from this customer crosswalk.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynchronexProvisionRequest"},"example":{"owner_email":"user@example.com","bundle":"synchronex_pro","synchronex_user_id":"string"}}}},"responses":{"200":{"description":"Existing project returned idempotently","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynchronexProvisionResponse"}}}},"201":{"description":"Project provisioned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynchronexProvisionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postServiceProjectsProvision","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"},"delete":{"summary":"Deprovision a Synchronex-bundled Sendinel project","description":"Customer bundle provisioning only. Requires a service API key with the service:provision scope. Suspends the project, revokes its project API key, zeroes the send limit, and resets approval_mode to standard. The internal Synchronex platform project is intentionally excluded from this customer crosswalk.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["synchronex_user_id"],"properties":{"owner_email":{"type":"string","format":"email"},"synchronex_user_id":{"type":"string"},"synchronex_account_id":{"type":"string"},"synchronex_account_no":{"type":"string"},"synchronex_team_id":{"type":"string"},"synchronex_workspace_id":{"type":"string"},"synchronex_brand_id":{"type":"string"},"synchronex_brand_name":{"type":"string"}}},"example":{"synchronex_user_id":"string"}}}},"responses":{"200":{"description":"Project deprovisioned or already absent"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteServiceProjectsProvision","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/observer/connections":{"post":{"summary":"Create or re-affirm a read-only Observer Mode connection","description":"Requires a service API key with the service:provision scope. Registers a read-only ESP/CRM connection (connection_mode=observe) for a Synchronex account already linked to an active Sendinel project — distinct from the migrate-mode platform connections used for one-time data import.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["synchronex_account_id","provider","auth"],"properties":{"synchronex_account_id":{"type":"string"},"provider":{"type":"string"},"auth":{"type":"object"},"label":{"type":"string"},"workspace_hint":{"type":"string"}}},"example":{"synchronex_account_id":"string","provider":"string","auth":{}}}}},"responses":{"201":{"description":"Connection created or re-affirmed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Synchronex account is not linked to an active Sendinel project"},"422":{"description":"Missing or unsupported provider/auth fields"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postObserverConnections","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"},"get":{"summary":"List Observer Mode connections for a Synchronex account","parameters":[{"name":"synchronex_account_id","in":"query","required":true,"schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"Observer connections for the account"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"synchronex_account_id is required"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getObserverConnections","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/observer/oauth/start":{"post":{"summary":"Start an OAuth Observer Mode connection","description":"Requires a service API key with the service:provision scope. Returns a provider authorization URL for Synchronex to redirect a user through an OAuth consent flow. The callback writes a connection_mode=observe platform connection and returns the browser to Synchronex.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["synchronex_account_id","provider","return_to","state"],"properties":{"synchronex_account_id":{"type":"string"},"provider":{"type":"string","enum":["hubspot","shopify","stripe","calendly"]},"return_to":{"type":"string","format":"uri"},"state":{"type":"string"},"label":{"type":"string"},"workspace_hint":{"type":"string"}}},"example":{"synchronex_account_id":"string","provider":"hubspot","return_to":"string","state":"string"}}}},"responses":{"200":{"description":"Provider authorization URL","content":{"application/json":{"schema":{"type":"object","required":["authorization_url"],"properties":{"authorization_url":{"type":"string","format":"uri"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Signed project does not own this Synchronex account"},"404":{"description":"Synchronex account is not linked to an active Sendinel project"},"422":{"description":"Missing or invalid observer OAuth request fields"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postObserverOauthStart","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/observer/connections/{connectionId}":{"get":{"summary":"Get an Observer Mode connection's status","parameters":[{"name":"connectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Connection status"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Observer connection not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getObserverConnectionsByConnectionId","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"delete":{"summary":"Disconnect an Observer Mode connection","parameters":[{"name":"connectionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Connection disconnected"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Observer connection not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteObserverConnectionsByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/service/projects/{projectId}":{"get":{"summary":"Resolve a Sendinel project for Synchronex reconciliation","description":"Read-only first-party lookup for existing Sendinel projects. Requires the Synchronex shared service token, or a first-party service key / scoped JWT carrying `service:provision`. Returns project, org, site, and Synchronex crosswalk fields only. Excludes credentials, encrypted keys, and billing data.","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Project reconciliation payload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceProjectLookupResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Missing first-party service access"},"404":{"description":"Project not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getServiceProjectsByProjectId","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/synchronex/content-opportunity/signals":{"get":{"summary":"Export content-opportunity signals for Synchronex","description":"Read-only pull surface for Synchronex workers to consume Sendinel's content-opportunity signal classes and proposal-backed recommendations. The catalog includes all planned classes; current live producer output is lifecycle plus cadence-gap from create_content_recommendation proposals.","parameters":[{"in":"query","name":"since","schema":{"type":"string","format":"date-time"},"description":"Return proposal-backed signals generated after this ISO timestamp.","example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":500},"example":1},{"in":"query","name":"status","schema":{"type":"string"},"description":"Comma-separated proposal statuses, or `all`. Defaults to pending, stale, applied, and auto_applied.","example":"string"},{"in":"query","name":"signal_class","schema":{"type":"string","enum":["engagement","lifecycle","revenue","cadence_gap","deliverability","segment_shift","content_inventory","cross_channel","portfolio_gap"]},"example":"engagement"}],"responses":{"200":{"description":"Content-opportunity signal export page","content":{"application/json":{"schema":{"type":"object","required":["synchronex_account_id","signal_classes","signals","next_cursor"],"properties":{"synchronex_account_id":{"type":"string","nullable":true},"signal_classes":{"type":"array","items":{"type":"object","required":["id","label","description","source_tables","status","producer"],"properties":{"id":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"source_tables":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["live","planned"]},"producer":{"type":"string","nullable":true}}}},"signals":{"type":"array","items":{"type":"object","required":["id","event","proposal_id","project_id","org_id","signal_classes","target","recommendation","metrics","status","generated_at","updated_at","source"],"properties":{"id":{"type":"string"},"event":{"type":"string","enum":["sendinel.content.recommendation"]},"proposal_id":{"type":"string","format":"uuid"},"project_id":{"type":"string","format":"uuid"},"org_id":{"type":"string","format":"uuid"},"signal_classes":{"type":"array","items":{"type":"string"}},"target":{"type":"object","additionalProperties":true},"recommendation":{"type":"object","additionalProperties":true},"metrics":{"type":"object","additionalProperties":true},"confidence":{"type":"integer","nullable":true},"status":{"type":"string"},"generated_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"source":{"type":"object","additionalProperties":true}}}},"next_cursor":{"type":"string","nullable":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Could not load content-opportunity signals"}},"operationId":"getSynchronexContentOpportunitySignals","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/synchronex/recommendations/approve":{"post":{"summary":"Apply a Synchronex CEO-approved campaign recommendation","description":"Return leg for Synchronex CEO approvals of a sendinel.campaign.recommendation signal. Requires a service API key with the service:provision scope; the request's synchronex_account_id must match the project's linked account. Applies the underlying start_campaign or end_campaign agent_proposal.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["proposal_id","synchronex_account_id"],"properties":{"proposal_id":{"type":"string","format":"uuid"},"synchronex_account_id":{"type":"string"},"event_id":{"type":"string"}}},"example":{"proposal_id":"00000000-0000-4000-8000-000000000000","synchronex_account_id":"string"}}}},"responses":{"200":{"description":"Proposal applied"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Missing service:provision scope, or synchronex_account_id does not match the project's linked account"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"description":"Proposal type is not start_campaign or end_campaign"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSynchronexRecommendationsApprove","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/synchronex/replies/post":{"post":{"summary":"Post an approved LinkedIn comment reply","description":"Return leg for Synchronex to post an approved reply to a LinkedIn comment (#3875). Requires exact match of sha256(text) against stored reply_draft.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["engagement_id","text"],"properties":{"engagement_id":{"type":"string"},"text":{"type":"string"},"body_sha256":{"type":"string"}}},"example":{"engagement_id":"string","text":"string"}}}},"responses":{"200":{"description":"Reply posted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Engagement not found"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"description":"Text sha256 does not match stored reply draft"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSynchronexRepliesPost","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/synchronex/signals":{"get":{"summary":"Replay Synchronex signal webhooks","parameters":[{"in":"query","name":"since","schema":{"type":"string"},"description":"ISO timestamp or prior event_id cursor.","example":"string"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":500},"example":1}],"responses":{"200":{"description":"Signal replay page"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSynchronexSignals","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/synchronex/signals/summary":{"get":{"summary":"Summarize recent Synchronex signal activity","parameters":[{"in":"query","name":"window_days","schema":{"type":"integer","minimum":1,"maximum":90},"example":1}],"responses":{"200":{"description":"Signal activity summary"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSynchronexSignalsSummary","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/sites":{"get":{"summary":"List sites","responses":{"200":{"description":"Sites"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSites","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"},"post":{"summary":"Create a site","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"},"example":{"id":"00000000-0000-4000-8000-000000000000","name":"string","slug":"string","from_email":"user@example.com"}}}},"responses":{"201":{"description":"Site created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSites","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/sites/{id}":{"get":{"summary":"Get a site","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Site"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesById","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"},"patch":{"summary":"Update a site","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"},"example":{"id":"00000000-0000-4000-8000-000000000000","name":"string","slug":"string","from_email":"user@example.com"}}}},"responses":{"200":{"description":"Site updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchSitesById","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/contacts":{"get":{"summary":"List contacts","parameters":[{"in":"query","name":"search","schema":{"type":"string"},"example":"string"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"company_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"company_domain","schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"Contacts"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContacts","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts"},"post":{"summary":"Create a contact","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"},"example":{"id":"00000000-0000-4000-8000-000000000000","email":"user@example.com"}}}},"responses":{"201":{"description":"Contact created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContacts","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/drafts":{"get":{"summary":"List AI draft artifacts","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1},{"in":"query","name":"status","schema":{"type":"string","enum":["all","pending","approved","rejected","expired"]},"example":"all"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"campaign_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"}],"responses":{"200":{"description":"Draft list"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDrafts","security":[{"OAuth2":["drafts"]},{"ApiKeyAuth":[]}],"x-required-scope":"drafts"},"post":{"summary":"Create an AI draft for review","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["site_id","subject","body_html"],"properties":{"site_id":{"type":"string","format":"uuid"},"subject":{"type":"string"},"body_html":{"type":"string"},"body_text":{"type":"string"},"campaign_id":{"type":"string","format":"uuid"},"prompt":{"type":"string"},"model":{"type":"string"},"preview_text":{"type":"string"},"brand_asset_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Stable brand_media_assets ids explicitly referenced by the draft."}}},"example":{"site_id":"00000000-0000-4000-8000-000000000000","subject":"string","body_html":"string"}}}},"responses":{"201":{"description":"Draft created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDrafts","security":[{"OAuth2":["drafts"]},{"ApiKeyAuth":[]}],"x-required-scope":"drafts","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/drafts/{id}":{"get":{"summary":"Get an AI draft and its latest review","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Draft detail with latest non-stale review"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDraftsById","security":[{"OAuth2":["drafts"]},{"ApiKeyAuth":[]}],"x-required-scope":"drafts"}},"/drafts/{id}/approve":{"post":{"summary":"Approve an AI draft","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Draft approved"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDraftsByIdApprove","security":[{"OAuth2":["drafts"]},{"ApiKeyAuth":[]}],"x-required-scope":"drafts","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/drafts/{id}/regenerate":{"post":{"summary":"Regenerate an AI draft review","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"202":{"description":"Draft review regeneration accepted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDraftsByIdRegenerate","security":[{"OAuth2":["drafts"]},{"ApiKeyAuth":[]}],"x-required-scope":"drafts","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/drafts/{id}/reject":{"post":{"summary":"Reject an AI draft","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Draft rejected"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postDraftsByIdReject","security":[{"OAuth2":["drafts"]},{"ApiKeyAuth":[]}],"x-required-scope":"drafts","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/forms":{"get":{"summary":"List signup forms","parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"status","schema":{"type":"string"},"example":"string"},{"in":"query","name":"search","schema":{"type":"string"},"example":"string"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"}],"responses":{"200":{"description":"Signup forms"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getForms","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a signup form","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"site_id":{"type":"string","format":"uuid"},"fields":{"type":"array","items":{"type":"object","additionalProperties":true}},"settings":{"type":"object","additionalProperties":true}}},"example":{"name":"string","slug":"string"}}}},"responses":{"201":{"description":"Signup form created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postForms","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/forms/{id}":{"get":{"summary":"Get signup form detail","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Signup form detail with embed code"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getFormsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a signup form","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Signup form updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchFormsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Delete a signup form","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Signup form deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteFormsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/forms/{id}/submissions":{"get":{"summary":"List signup form submissions","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"}],"responses":{"200":{"description":"Signup form submission history"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getFormsByIdSubmissions","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/email-log":{"get":{"summary":"List delivery events","parameters":[{"in":"query","name":"campaign_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"contact_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"status","schema":{"type":"string","description":"Comma-separated delivery statuses"},"example":"string"},{"in":"query","name":"start_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"end_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":500},"example":1}],"responses":{"200":{"description":"Email delivery events with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getEmailLog","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/email-log/export":{"get":{"summary":"Export delivery events","parameters":[{"in":"query","name":"campaign_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"contact_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"status","schema":{"type":"string","description":"Comma-separated delivery statuses"},"example":"string"},{"in":"query","name":"start_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"end_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"format","schema":{"type":"string","enum":["csv","jsonl"]},"example":"csv"}],"responses":{"200":{"description":"Email delivery events export"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getEmailLogExport","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/content-blocks":{"get":{"summary":"List reusable content blocks","parameters":[{"in":"query","name":"category","schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"Reusable content blocks"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContentBlocks","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a reusable content block","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","html"],"properties":{"name":{"type":"string"},"html":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"thumbnail":{"type":"string"}}},"example":{"name":"string","html":"string"}}}},"responses":{"201":{"description":"Content block created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContentBlocks","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/content-blocks/{id}":{"get":{"summary":"Get a reusable content block","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Content block detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContentBlocksById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a reusable content block","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Content block updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchContentBlocksById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Delete a reusable content block","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Content block deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteContentBlocksById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/pages":{"get":{"summary":"List landing pages","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["draft","published","archived"]},"example":"draft"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"search","schema":{"type":"string"},"example":"string"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1}],"responses":{"200":{"description":"Landing pages with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getPages","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a landing page","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","slug"],"properties":{"title":{"type":"string"},"slug":{"type":"string"},"site_id":{"type":"string","format":"uuid"},"blocks":{"type":"array","items":{"type":"object","additionalProperties":true}},"form_id":{"type":"string","format":"uuid"},"meta_title":{"type":"string"},"meta_description":{"type":"string"}}},"example":{"title":"string","slug":"string"}}}},"responses":{"201":{"description":"Landing page created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postPages","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/pages/{id}":{"get":{"summary":"Get a landing page","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Landing page detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getPagesById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a landing page","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Landing page updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchPagesById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Delete a landing page","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Landing page deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deletePagesById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/asset-links":{"get":{"summary":"List gated asset links","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["draft","active","archived"]},"example":"draft"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1}],"responses":{"200":{"description":"Gated asset links with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAssetLinks","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a gated asset link","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","slug","asset_type","asset_url"],"properties":{"title":{"type":"string"},"slug":{"type":"string"},"asset_type":{"type":"string","enum":["pdf","page","deck","video","other"]},"asset_url":{"type":"string","format":"uri"},"site_id":{"type":"string","format":"uuid"},"source_attribution":{"type":"string"},"gate_headline":{"type":"string"},"gate_body":{"type":"string"}}},"example":{"title":"string","slug":"string","asset_type":"pdf","asset_url":"string"}}}},"responses":{"201":{"description":"Gated asset link created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAssetLinks","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/asset-links/{id}":{"get":{"summary":"Get a gated asset link","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Gated asset link detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAssetLinksById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a gated asset link","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Gated asset link updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchAssetLinksById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Archive a gated asset link","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Gated asset link archived"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteAssetLinksById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/asset-links/{id}/views":{"get":{"summary":"List gated asset link views","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1}],"responses":{"200":{"description":"Per-view gated asset events"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAssetLinksByIdViews","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/signatures":{"get":{"summary":"List signature blocks","parameters":[{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Signature blocks"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSignatures","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a signature block","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["site_id","name","html"],"properties":{"site_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"html":{"type":"string"},"is_default":{"type":"boolean"}}},"example":{"site_id":"00000000-0000-4000-8000-000000000000","name":"string","html":"string"}}}},"responses":{"201":{"description":"Signature block created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSignatures","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/signatures/{id}":{"get":{"summary":"Get a signature block","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Signature block detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSignaturesById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a signature block","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Signature block updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchSignaturesById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Delete a signature block","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Signature block deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteSignaturesById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/sending-domains":{"get":{"summary":"List managed sending domains","responses":{"200":{"description":"Managed sending domains"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSendingDomains","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Provision a managed sending domain","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["parent"],"properties":{"parent":{"type":"string","enum":["sendinel.ai","synchronex.ai"]},"label":{"type":"string"}}},"example":{"parent":"sendinel.ai"}}}},"responses":{"201":{"description":"Managed sending domain provisioned"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSendingDomains","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/sending-domains/{id}":{"get":{"summary":"Get a managed sending domain","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Managed sending domain detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSendingDomainsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"delete":{"summary":"Delete a managed sending domain","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Managed sending domain deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteSendingDomainsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/social-posts":{"get":{"summary":"List social posts","parameters":[{"in":"query","name":"status","schema":{"type":"string"},"example":"string"},{"in":"query","name":"platform","schema":{"type":"string"},"example":"string"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"scheduled_after","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"scheduled_before","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1}],"responses":{"200":{"description":"Social posts with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialPosts","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a social post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","platforms"],"properties":{"title":{"type":"string"},"content":{"type":"string"},"platforms":{"type":"array","items":{"type":"string"}},"scheduled_at":{"type":"string","format":"date-time"},"queue_requested":{"type":"boolean"},"platform_captions":{"type":"object","additionalProperties":true},"linkedin_company_crosspost":{"type":"boolean","description":"When true, also publish the LinkedIn post to the provided company page target."},"linkedin_company_page_id":{"type":"string","description":"UploadPost target_linkedin_page_id for the LinkedIn company page."},"media_urls":{"type":"array","items":{"type":"string"}},"destination_url":{"type":"string"},"site_id":{"type":"string","format":"uuid"},"timezone":{"type":"string"}}},"example":{"title":"string","content":"string","platforms":["string"]}}}},"responses":{"201":{"description":"Social post created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSocialPosts","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/social-posts/{id}":{"get":{"summary":"Get a social post","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Social post detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialPostsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a social post","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Social post updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchSocialPostsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Archive a social post","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Social post archived"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteSocialPostsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/templates/{id}/preview":{"get":{"summary":"Preview a template with seeded sample content","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"refresh","schema":{"type":"integer","enum":[1]},"example":1}],"responses":{"200":{"description":"Template preview render"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getTemplatesByIdPreview","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/scoring-rules":{"get":{"summary":"Get project scoring rules","responses":{"200":{"description":"Project scoring rules"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getScoringRules","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"put":{"summary":"Update project scoring rules","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"number"}},"example":{}}}},"responses":{"200":{"description":"Project scoring rules updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"putScoringRules","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/channels/roster":{"post":{"summary":"Sync a project channel roster","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entries"],"properties":{"entries":{"type":"array","minItems":1,"maxItems":1000,"items":{"type":"object","required":["channel","handle"],"properties":{"channel":{"type":"string","enum":["sms","whatsapp","telegram","email"]},"handle":{"type":"string"},"contact_id":{"type":"string","format":"uuid","nullable":true}}}}}},"example":{"entries":[{"channel":"sms","handle":"string"}]}}}},"responses":{"200":{"description":"Channel roster synced"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postChannelsRoster","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/social-connections":{"get":{"summary":"List connected social accounts and connection health","responses":{"200":{"description":"Org-scoped social connections with account identity, status, and expiry","content":{"application/json":{"schema":{"type":"object","required":["connections"],"properties":{"connections":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"account_name":{"type":"string","nullable":true},"account_id":{"type":"string","nullable":true},"account_status":{"type":"string"},"expires_at":{"type":"string","format":"date-time","nullable":true},"follower_count":{"type":"integer","nullable":true},"follower_count_synced_at":{"type":"string","format":"date-time","nullable":true},"updated_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}}},"message":{"type":"string","description":"Present when no social accounts are connected"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialConnections","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/social-inbox":{"get":{"summary":"List inbound social engagements","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["all","open","responded","dismissed"]},"example":"all"},{"in":"query","name":"platform","schema":{"type":"string"},"example":"string"},{"in":"query","name":"social_post_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1}],"responses":{"200":{"description":"Inbound social engagements with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialInbox","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/social-analytics/campaigns":{"get":{"summary":"Get social campaign analytics","parameters":[{"in":"query","name":"site_id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"campaign_id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Social campaign analytics"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialAnalyticsCampaigns","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/social-analytics/portfolio":{"get":{"summary":"Get aggregate social portfolio analytics","parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365},"example":1},{"in":"query","name":"group_by","schema":{"type":"string","enum":["day","week","month"]},"example":"day"}],"responses":{"200":{"description":"Aggregate social impressions, engagement, posts, clicks, conversions, followers, and period/platform breakdowns"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialAnalyticsPortfolio","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/social-analytics/engagements":{"get":{"summary":"List inbound social engagements for worker context","parameters":[{"in":"query","name":"status","schema":{"type":"string"},"description":"Engagement status to filter by; use all to disable filtering.","example":"string"}],"responses":{"200":{"description":"Social engagement inbox rows joined to post title/platform context"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialAnalyticsEngagements","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/embed/token":{"post":{"summary":"Issue an embed token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scopes"],"properties":{"scopes":{"type":"array","minItems":1,"items":{"type":"string"}},"ttl_seconds":{"type":"integer","minimum":60,"maximum":900}}},"example":{"scopes":["string"]}}}},"responses":{"200":{"description":"Embed token issued"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postEmbedToken","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/dmarc-reports":{"get":{"summary":"List DMARC report summaries","parameters":[{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"domain","schema":{"type":"string"},"example":"string"},{"in":"query","name":"start_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"end_date","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"cursor","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200},"example":1}],"responses":{"200":{"description":"DMARC report summaries with cursor pagination"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getDmarcReports","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/recipients/{id}/export":{"get":{"summary":"Export recipient data","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Recipient data export"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getRecipientsByIdExport","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/service/embed-session":{"post":{"summary":"Mint a service embed session token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["project_id","owner_email","synchronex_user_id"],"properties":{"project_id":{"type":"string","format":"uuid"},"owner_email":{"type":"string","format":"email"},"synchronex_user_id":{"type":"string"},"synchronex_tenant_claim":{"type":"string"}}},"example":{"project_id":"00000000-0000-4000-8000-000000000000","owner_email":"user@example.com","synchronex_user_id":"string"}}}},"responses":{"200":{"description":"Embed session token minted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postServiceEmbedSession","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/export":{"get":{"summary":"Export tenant data","parameters":[{"in":"query","name":"site_id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"format","schema":{"type":"string","enum":["json","csv"]},"example":"json"}],"responses":{"200":{"description":"Tenant export bundle or uploaded export reference"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getExport","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/brand-brain":{"get":{"summary":"Get project brand brain settings","responses":{"200":{"description":"Project brand brain settings"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBrandBrain","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update project brand brain settings","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Project brand brain settings updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchBrandBrain","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/brand-kit":{"get":{"summary":"Get a project's assembled brand kit (assets, templates, campaigns, brand settings)","parameters":[{"in":"query","name":"kit_id","required":false,"schema":{"type":"string","format":"uuid"},"description":"Assemble a specific kit. Omit to get the most recently created kit for the project.","example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"kind","required":false,"schema":{"type":"string"},"description":"Filter assets to one BrandAssetKind (logo, image, document, font, avatar, video).","example":"string"},{"in":"query","name":"collection","required":false,"schema":{"type":"string"},"example":"string"},{"in":"query","name":"tag","required":false,"schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"Assembled brand kit"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No brand kit exists for this project, or the specified kit_id was not found"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBrandKit","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/brand-kit/assets":{"get":{"summary":"List a project's confirmed brand assets across ALL brand kits (not scoped to a single kit)","description":"The project-wide sibling of GET /brand-kit, which assembles a single kit (defaulting to the most recently created one). Use this to see everything in the project's media library without assuming there's only one kit.","parameters":[{"in":"query","name":"kind","required":false,"schema":{"type":"string"},"description":"Filter assets to one BrandAssetKind (logo, image, document, font, avatar, video).","example":"string"},{"in":"query","name":"collection","required":false,"schema":{"type":"string"},"example":"string"},{"in":"query","name":"tag","required":false,"schema":{"type":"string"},"example":"string"},{"in":"query","name":"reference_purpose","required":false,"schema":{"type":"string","enum":["product","style","scene","brand-mark"]},"description":"Filter assets whose reference_purposes array includes this value.","example":"product"},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":100},"description":"Max assets to return (default 50).","example":1},{"in":"query","name":"offset","required":false,"schema":{"type":"integer","minimum":0},"description":"Number of matching assets to skip (default 0).","example":0}],"responses":{"200":{"description":"Confirmed assets with signed download URLs, counts by kind, and pagination metadata"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Invalid kind filter"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBrandKitAssets","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/brand-kit/assets/{id}/rehost":{"post":{"summary":"Rehost a brand asset for email or social use","description":"Creates a real hosted copy of an existing brand asset using the dashboard media rehost pipeline. Use this when a brand asset read returns `url: null`, such as a Drive-linked asset, before referencing it in generated content.\n\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Brand media asset id.","example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["purpose"],"properties":{"purpose":{"type":"string","enum":["email","social"]},"platforms":{"type":"array","items":{"type":"string"},"description":"Optional target platform context for social validation."}}},"example":{"purpose":"email"}}}},"responses":{"200":{"description":"Hosted asset URL and asset metadata"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Asset not found"},"409":{"$ref":"#/components/responses/Conflict"},"415":{"description":"Asset cannot be rehosted for the requested purpose"},"422":{"description":"Invalid purpose"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postBrandKitAssetsByIdRehost","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported"}},"/brand-kit/import-text":{"post":{"summary":"Import raw Brand Core / Brand Brain / Content Library / Brand Kit companion markdown text","description":"Parses a companion's raw text reply and applies whatever it finds (voice fields into brand_settings, colors, templates, social posts) to the current project. Same deterministic parsers as the dashboard's paste-back flow.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","description":"Raw markdown text from the Brand Core / Brand Kit companion output."}}},"example":{"text":"string"}}}},"responses":{"200":{"description":"Import summary (fields/colors/templates/social posts saved)"},"400":{"description":"Text is missing, or no recognized Brand Core/Brand Brain/Content Library/Brand Kit section was found"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Project not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postBrandKitImportText","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/brand-kit/ingest-assets":{"post":{"summary":"Ingest brand assets from public HTTPS URLs into the project media library","description":"Downloads each asset URL server-side (private/internal addresses and redirects are rejected) and persists it the same way a dashboard upload would. Raw file bytes are not accepted in the request body — provide URLs only.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["assets"],"properties":{"assets":{"type":"array","minItems":1,"maxItems":25,"items":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Public HTTPS asset URL."},"kind":{"type":"string","enum":["logo","image","document","font","avatar","video"]},"filename":{"type":"string"}}}},"collection":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"example":{"assets":[{"url":"string"}]}}}},"responses":{"200":{"description":"Per-asset ingest results plus imported/failed counts"},"400":{"description":"assets is missing, empty, or exceeds the 25-item limit"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Project not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postBrandKitIngestAssets","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/brand-kit/github-connections":{"get":{"summary":"List approved GitHub Brand Kit sync connections","description":"Returns repo + path-prefix bindings registered for the authenticated project.","responses":{"200":{"description":"Registered GitHub connections"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Project not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBrandKitGithubConnections","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Register an approved GitHub repo path for Brand Kit ingest","description":"Creates or updates a project-scoped repo/path_prefix binding that the GitHub ingest endpoint uses to validate every incoming file path.\n\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["repo","path_prefix"],"properties":{"repo":{"type":"string","example":"owner/repo"},"path_prefix":{"type":"string","example":"marketing"},"brand_kit_id":{"type":"string","format":"uuid","nullable":true}}},"example":{"repo":"owner/repo","path_prefix":"marketing"}}}},"responses":{"201":{"description":"Registered GitHub connection"},"400":{"description":"Invalid repo, path_prefix, or brand_kit_id"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Project not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postBrandKitGithubConnections","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/brand-kit/github-connections/{id}":{"delete":{"summary":"Revoke an approved GitHub Brand Kit sync connection","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Deleted GitHub connection"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Project or connection not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteBrandKitGithubConnectionsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/brand-kit/github-ingest":{"post":{"summary":"Push GitHub-sourced files into the Brand Kit media library","description":"Accepts a Synchronex-pushed batch of repo-relative files, rejects the whole request when no repo binding exists, and rejects individual files outside the registered path prefix while importing in-scope siblings. Imported assets use source imported with metadata.cloud_provider github.\n\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["repo","files"],"properties":{"repo":{"type":"string","example":"owner/repo"},"ref":{"type":"string"},"brand_kit_id":{"type":"string","format":"uuid","nullable":true},"collection":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"files":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"object","required":["path"],"properties":{"path":{"type":"string","example":"marketing/logos/wordmark.svg"},"content_base64":{"type":"string","description":"Base64-encoded file bytes. Required unless content_url is provided."},"content_url":{"type":"string","format":"uri","description":"Public HTTPS URL fetched with the same SSRF protections as ingest-assets."},"mime_type":{"type":"string"},"sha":{"type":"string"}}}}}},"example":{"repo":"owner/repo","files":[{"path":"marketing/logos/wordmark.svg"}]}}}},"responses":{"200":{"description":"Per-file GitHub ingest results plus imported, failed, and rejected_out_of_scope counts"},"400":{"description":"Invalid request body, repo, files, or brand_kit_id"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"No approved GitHub connection exists for this repo"},"404":{"description":"Project not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postBrandKitGithubIngest","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/blog":{"get":{"summary":"List blog posts","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["draft","scheduled","published","archived"]},"description":"Optional status filter.","example":"draft"},{"in":"query","name":"limit","schema":{"type":"integer"},"description":"Max rows (1-200, default 50).","example":1}],"responses":{"200":{"description":"Blog posts for the project."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBlog","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Ingest a blog post (staged as draft for review)","description":"Sender-owns-schema ingest — only `title` is required; every other field is mapped from whatever arrives and the full raw payload is preserved. The post lands as `draft` for review; publishing to the user's own site is a separate step. Requires the `blog:write` scope.\n\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","responses":{"201":{"description":"Created blog post (draft)."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"description":"Missing or invalid field."},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postBlog","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/newsletters":{"get":{"summary":"List newsletters","description":"Requires the `newsletters:read` scope.","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["active","paused","archived"]},"example":"active"},{"in":"query","name":"limit","schema":{"type":"integer"},"description":"Max rows (1-200, default 50).","example":1}],"responses":{"200":{"description":"Newsletters for the project."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getNewsletters","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a newsletter publication","description":"Requires the `newsletters:write` scope.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","responses":{"201":{"description":"Created newsletter."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Newsletter slug already exists."},"422":{"description":"Missing or invalid field."},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postNewsletters","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/newsletters/{id}":{"get":{"summary":"Get a newsletter","description":"Requires the `newsletters:read` scope.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Newsletter row."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Newsletter not found."},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getNewslettersById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a newsletter","description":"Requires the `newsletters:write` scope.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"200":{"description":"Updated newsletter row."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Newsletter not found."},"409":{"description":"Newsletter slug already exists."},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchNewslettersById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported"}},"/newsletters/{id}/issues":{"get":{"summary":"List newsletter issues","description":"Requires the `newsletters:read` scope.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"status","schema":{"type":"string","enum":["draft","scheduled","sent","archived"]},"example":"draft"}],"responses":{"200":{"description":"Newsletter issue rows."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getNewslettersByIdIssues","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a newsletter issue draft","description":"Requires the `newsletters:write` scope.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"201":{"description":"Created newsletter issue draft."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Newsletter not found."},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postNewslettersByIdIssues","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported"}},"/newsletters/{id}/issues/{issueId}/schedule":{"post":{"summary":"Schedule a newsletter issue","description":"Requires the `newsletters:write` scope. Creates or reuses the linked campaign broadcast, enrolls active newsletter subscribers, and sets campaign send_at.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"path","name":"issueId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["scheduled_at"],"properties":{"scheduled_at":{"type":"string","format":"date-time"}}},"example":{"scheduled_at":"2026-01-01T00:00:00Z"}}}},"responses":{"200":{"description":"Scheduled newsletter issue, linked campaign id, and enrollment count."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Issue cannot be scheduled from its current state."},"422":{"description":"Missing site_id, content, or valid scheduled_at."},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postNewslettersByIdIssuesByIssueIdSchedule","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported"}},"/newsletters/{id}/issues/{issueId}/send":{"post":{"summary":"Send a newsletter issue now","description":"Requires the `newsletters:write` scope. Creates or reuses the linked campaign broadcast, enrolls active newsletter subscribers, and creates a Blog archive row.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"path","name":"issueId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"200":{"description":"Sent newsletter issue, linked campaign id, enrollment count, and archive metadata."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Issue has already been sent."},"422":{"description":"Missing site_id or issue content."},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postNewslettersByIdIssuesByIssueIdSend","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported"}},"/newsletters/{id}/subscribe":{"post":{"summary":"Add or reactivate a newsletter subscription","description":"Requires the `newsletters:write` scope.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"201":{"description":"Newsletter subscription row."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postNewslettersByIdSubscribe","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported"},"delete":{"summary":"Unsubscribe from one newsletter","description":"Requires the `newsletters:write` scope. This does not create a global suppression.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Newsletter-scoped unsubscribe result."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteNewslettersByIdSubscribe","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/newsletters/{id}/subscribers":{"get":{"summary":"List newsletter subscribers","description":"Requires the `newsletters:read` scope.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"status","schema":{"type":"string","enum":["pending","active","unsubscribed"]},"example":"pending"},{"in":"query","name":"limit","schema":{"type":"integer","default":50,"minimum":1,"maximum":200},"example":1}],"responses":{"200":{"description":"Newsletter subscriptions for this publication."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getNewslettersByIdSubscribers","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/newsletters/{id}/stats":{"get":{"summary":"Get newsletter stats","description":"Requires the `newsletters:read` scope. Issue-level analytics intentionally return `pending_phase_4` in this core slice.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Newsletter subscriber count and explicit Phase 4 analytics placeholder."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getNewslettersByIdStats","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/content-sources":{"get":{"summary":"List content sources available to worker context","parameters":[{"in":"query","name":"site","schema":{"type":"string"},"description":"Optional site filter, accepting either site UUID or display id.","example":"string"}],"responses":{"200":{"description":"Content source rows without credential/token fields"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContentSources","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/surveys":{"get":{"summary":"List surveys available to worker context","responses":{"200":{"description":"Survey list scoped to the authenticated API key's project"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSurveys","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/blackout-dates":{"get":{"summary":"List campaign scheduling blackout dates","responses":{"200":{"description":"Blackout date list ordered by date ascending"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getBlackoutDates","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/revenue":{"get":{"summary":"List conversion revenue records and summary","parameters":[{"in":"query","name":"site","schema":{"type":"string"},"description":"Optional site filter, accepting either site UUID or display id.","example":"string"},{"in":"query","name":"search","schema":{"type":"string"},"description":"Search order id or conversion event name.","example":"string"},{"in":"query","name":"page","schema":{"type":"integer"},"example":1},{"in":"query","name":"pageSize","schema":{"type":"integer"},"example":1}],"responses":{"200":{"description":"Conversion rows plus total/count/average revenue summary"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getRevenue","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/campaigns/{id}/steps/{stepId}":{"get":{"summary":"Get a campaign step","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"path","name":"stepId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Campaign step detail"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaignsByIdStepsByStepId","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"},"patch":{"summary":"Update a campaign step","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"path","name":"stepId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true},"example":{}}}},"responses":{"200":{"description":"Campaign step updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchCampaignsByIdStepsByStepId","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."},"delete":{"summary":"Delete a campaign step","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"path","name":"stepId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"204":{"description":"Campaign step deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteCampaignsByIdStepsByStepId","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/openapi.json":{"get":{"summary":"Get the OpenAPI specification as JSON","responses":{"200":{"description":"OpenAPI specification document"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getOpenapiJson","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/ai/context-events":{"post":{"summary":"Submit Synchronex strategic context into the AI work queue","description":"Stores a project-scoped Synchronex context event and may translate it into reviewable AI work items and approval-gated proposals.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiContextEvent"},"example":{"source":"synchronex","workspace_id":"string","project_id":"00000000-0000-4000-8000-000000000000","event_type":"strategic_segment_intent","title":"string","detail":"string","idempotency_key":"string"}}}},"responses":{"200":{"description":"Duplicate idempotency key; existing context event returned"},"201":{"description":"Context event accepted and translated into AI work"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Missing or invalid API key"},"403":{"description":"Admin scope required"},"422":{"description":"Invalid context event payload"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAiContextEvents","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/webhooks/cal-com/{connectionId}":{"post":{"summary":"Receive a Cal.com webhook for a platform connection","parameters":[{"in":"path","name":"connectionId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Cal.com webhook processed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhooksCalComByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/webhooks/calendly/{connectionId}":{"post":{"summary":"Receive a Calendly webhook for a platform connection","parameters":[{"in":"path","name":"connectionId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Calendly webhook processed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhooksCalendlyByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/webhooks/hubspot/{connectionId}":{"post":{"summary":"Receive a HubSpot webhook for a platform connection","parameters":[{"in":"path","name":"connectionId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"HubSpot webhook processed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhooksHubspotByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/webhooks/shopify/{connectionId}":{"post":{"summary":"Receive a Shopify webhook for a platform connection","parameters":[{"in":"path","name":"connectionId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Shopify webhook processed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhooksShopifyByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/webhooks/stripe/{connectionId}":{"post":{"summary":"Receive a Stripe webhook for a platform connection","parameters":[{"in":"path","name":"connectionId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Stripe webhook processed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhooksStripeByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/webhooks/stripe-connect":{"post":{"summary":"Receive a platform-level Stripe Connect webhook","security":[],"responses":{"200":{"description":"Stripe Connect webhook processed"},"400":{"description":"Invalid or missing Stripe signature"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Stripe Connect webhook signing secret is not configured"}},"operationId":"postWebhooksStripeConnect","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/webhooks/typeform/{connectionId}":{"post":{"summary":"Receive a Typeform webhook for a platform connection","parameters":[{"in":"path","name":"connectionId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Typeform webhook processed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhooksTypeformByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/webhooks/custom/{connectionId}":{"post":{"summary":"Receive a signed custom-app webhook event (single event or batch)","parameters":[{"in":"path","name":"connectionId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"header","name":"X-Sendinel-Signature","required":true,"schema":{"type":"string"},"description":"HMAC-SHA256 signature over the raw request body, format sha256=<hex>","example":"string"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","required":["email","event"],"properties":{"email":{"type":"string"},"event":{"type":"string"},"data":{"type":"object"},"event_id":{"type":"string"}}},{"type":"object","required":["events"],"properties":{"events":{"type":"array","maxItems":100,"items":{"type":"object","required":["email","event"],"properties":{"email":{"type":"string"},"event":{"type":"string"},"data":{"type":"object"},"event_id":{"type":"string"}}}}}}]}}}},"responses":{"200":{"description":"Custom webhook event(s) processed"},"400":{"description":"Missing or invalid signature"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Connection not found"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhooksCustomByConnectionId","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/contacts/import":{"post":{"summary":"Bulk import contacts","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contacts"],"properties":{"contacts":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}}}},"example":{"contacts":[{"id":"00000000-0000-4000-8000-000000000000","email":"user@example.com"}]}}}},"responses":{"200":{"description":"Import result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContactsImport","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/contacts/batch":{"post":{"summary":"Batch upsert contacts by email","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contacts"],"properties":{"contacts":{"type":"array","maxItems":500,"items":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"first_name":{"type":"string"},"last_name":{"type":"string"},"custom_properties":{"type":"object","additionalProperties":true},"tags":{"type":"array","maxItems":50,"items":{"type":"string"}}}}}}},"example":{"contacts":[{"email":"user@example.com"}]}}}},"responses":{"202":{"description":"Batch result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContactsBatch","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/contacts/tags":{"post":{"summary":"Bulk add or remove contact tags","responses":{"200":{"description":"Tags updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContactsTags","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/contacts/estimate":{"post":{"summary":"Estimate audience size from contact filters","responses":{"200":{"description":"Audience estimate"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContactsEstimate","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/contacts/delivery-state":{"get":{"summary":"Read delivery verdicts for subscribers","description":"Read-only. Sendinel is the authority for suppression and bounce state.\n`status` is one of `no_record`, `deliverable`, `hard_bounced`, or\n`suppressed_other`. `no_record` means Sendinel has no deliverability\nverdict (never sent, or only a non-permanent bounce carried on\n`bounce_type` and `reason`). `matched: false` means no subscriber row.\nNeither value is deliverable. `bounce_type: permanent` is set only for\n`hard_bounced`. Reason is a category code, not a complaint body.\nPass `source_id` (the contact view's source id, including `sendinel:<id>`)\nfor one lookup. Omit it to page every subscriber in the project.\n","parameters":[{"in":"query","name":"source_id","schema":{"type":"string","maxLength":200},"example":"string"},{"in":"query","name":"cursor","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":50},"example":1}],"responses":{"200":{"description":"Delivery verdicts. An empty project returns an empty list. An unknown source_id returns one matched=false no_record row."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"Invalid cursor or source_id"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContactsDeliveryState","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts"}},"/contacts/{id}":{"get":{"summary":"Get a contact","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Contact"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContactsById","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts"},"patch":{"summary":"Update a contact","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"},"example":{"id":"00000000-0000-4000-8000-000000000000","email":"user@example.com"}}}},"responses":{"200":{"description":"Contact updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchContactsById","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."},"delete":{"summary":"Delete a contact","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"204":{"description":"Contact deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteContactsById","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/contacts/{id}/delivery-state":{"get":{"summary":"Read one subscriber's delivery verdict","description":"Same verdict contract as /contacts/delivery-state. A missing subscriber\nis HTTP 200 with matched=false and status=no_record, not a deliverable\naddress and not an empty body.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"Delivery verdict for the subscriber, or matched=false when the id is unknown"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContactsByIdDeliveryState","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts"}},"/contacts/{id}/unsubscribe":{"post":{"summary":"Globally unsubscribe a contact","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Contact unsubscribed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContactsByIdUnsubscribe","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/contacts/{id}/timeline":{"get":{"summary":"Get a contact activity timeline","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Contact timeline"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getContactsByIdTimeline","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts"}},"/contacts/{id}/enrich":{"post":{"summary":"Enrich a contact from connected providers","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"200":{"description":"Contact enrichment result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postContactsByIdEnrich","security":[{"OAuth2":["contacts"]},{"ApiKeyAuth":[]}],"x-required-scope":"contacts","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/segments":{"get":{"summary":"List segments","responses":{"200":{"description":"Segments"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSegments","security":[{"OAuth2":["segments"]},{"ApiKeyAuth":[]}],"x-required-scope":"segments"},"post":{"summary":"Create a segment","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Segment"},"example":{"id":"00000000-0000-4000-8000-000000000000","name":"string","rules":{}}}}},"responses":{"201":{"description":"Segment created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSegments","security":[{"OAuth2":["segments"]},{"ApiKeyAuth":[]}],"x-required-scope":"segments","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/segments/{id}":{"get":{"summary":"Get a segment","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Segment"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSegmentsById","security":[{"OAuth2":["segments"]},{"ApiKeyAuth":[]}],"x-required-scope":"segments"},"patch":{"summary":"Update a segment","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Segment"},"example":{"id":"00000000-0000-4000-8000-000000000000","name":"string","rules":{}}}}},"responses":{"200":{"description":"Segment updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchSegmentsById","security":[{"OAuth2":["segments"]},{"ApiKeyAuth":[]}],"x-required-scope":"segments","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."},"delete":{"summary":"Delete a segment","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"204":{"description":"Segment deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteSegmentsById","security":[{"OAuth2":["segments"]},{"ApiKeyAuth":[]}],"x-required-scope":"segments","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/segments/{id}/preview":{"get":{"summary":"Preview segment membership","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Preview result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSegmentsByIdPreview","security":[{"OAuth2":["segments"]},{"ApiKeyAuth":[]}],"x-required-scope":"segments"}},"/templates":{"get":{"summary":"List templates","responses":{"200":{"description":"Templates"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getTemplates","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a template","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"},"example":{"id":"00000000-0000-4000-8000-000000000000","name":"string","category":"string","brief_template":"string"}}}},"responses":{"201":{"description":"Template created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postTemplates","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/templates/{id}":{"get":{"summary":"Get a template","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Template"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getTemplatesById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update a template","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"},"example":{"id":"00000000-0000-4000-8000-000000000000","name":"string","category":"string","brief_template":"string"}}}},"responses":{"200":{"description":"Template updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchTemplatesById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."},"delete":{"summary":"Archive a template","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"204":{"description":"Template archived"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteTemplatesById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/campaigns":{"get":{"summary":"List campaigns","responses":{"200":{"description":"Campaigns"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaigns","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"},"post":{"summary":"Create a campaign","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"},"example":{"id":"00000000-0000-4000-8000-000000000000","site_id":"00000000-0000-4000-8000-000000000000","name":"string","type":"sequence","status":"draft"}}}},"responses":{"201":{"description":"Campaign created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postCampaigns","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/campaigns/{id}":{"get":{"summary":"Get a campaign","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Campaign"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaignsById","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"},"patch":{"summary":"Update a campaign","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"status":{"type":"string"},"send_at":{"type":"string","format":"date-time","nullable":true},"segment_id":{"type":"string","format":"uuid","nullable":true},"site_id":{"type":"string","format":"uuid"},"topic":{"type":"string","nullable":true},"trigger_event_name":{"type":"string","nullable":true},"trigger_tag":{"type":"string","nullable":true},"send_in_contact_timezone":{"type":"boolean"}}},"example":{}}}},"responses":{"200":{"description":"Campaign updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchCampaignsById","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."},"delete":{"summary":"Delete a campaign (requires campaign not active)","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"204":{"description":"Campaign deleted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteCampaignsById","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/campaigns/{id}/status":{"get":{"summary":"Campaign delivery status with per-channel breakdown","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Delivery status — { campaign_id, status, delivery_status, channel_statuses[], updated_at }"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaignsByIdStatus","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"}},"/campaigns/{id}/clone":{"post":{"summary":"Clone a campaign","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"responses":{"201":{"description":"Campaign cloned"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postCampaignsByIdClone","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/campaigns/review":{"post":{"summary":"Run the campaign portfolio review","description":"Evaluates every campaign in the project for completeness, dormancy, redundancy, and effectiveness, optionally raising agent_proposals (start_campaign / end_campaign / modify_campaign) and emitting sendinel.campaign.recommendation signals to Synchronex.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dry_run":{"type":"boolean","description":"Compute findings only, without raising proposals."},"dormant_draft_days":{"type":"integer"},"abandoned_days":{"type":"integer"}}},"example":{}}}},"responses":{"200":{"description":"Review results and any proposals raised"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postCampaignsReview","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported"}},"/campaigns/{id}/steps":{"get":{"summary":"List campaign steps","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Campaign steps"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaignsByIdSteps","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"},"post":{"summary":"Add a campaign step","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignStep"},"example":{"id":"00000000-0000-4000-8000-000000000000","campaign_id":"00000000-0000-4000-8000-000000000000","step_order":1,"subject":"string"}}}},"responses":{"201":{"description":"Step created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postCampaignsByIdSteps","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/campaigns/{id}/enrollments":{"post":{"summary":"Enroll one contact or an entire segment into a campaign","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contact_id":{"type":"string","format":"uuid"},"segment_id":{"type":"string","format":"uuid"},"site_id":{"type":"string","format":"uuid"}}},"example":{}}}},"responses":{"200":{"description":"Enrollments created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postCampaignsByIdEnrollments","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/campaigns/{id}/enrollments/{contactId}":{"get":{"summary":"Get one contact's campaign enrollment status","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"path","name":"contactId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Enrollment status"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaignsByIdEnrollmentsByContactId","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"},"delete":{"summary":"Remove one contact from a campaign","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"path","name":"contactId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"204":{"description":"Enrollment removed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteCampaignsByIdEnrollmentsByContactId","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/campaigns/test-send":{"post":{"summary":"Send or preview a test email from a step, draft, or raw content","description":"Requires campaigns:write (also granted by write/admin). All sources use the campaign-step renderer. Supply exactly one of step_id, draft_id or raw subject/body fields. A step must use its campaign's site; a site_id mismatch returns both IDs. Draft/raw sites must belong to the project. Actual sends refuse suppressed or globally unsubscribed recipients. dry_run renders without sending or writing email_log.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["to_email","site_id"],"properties":{"to_email":{"type":"string","format":"email"},"site_id":{"type":"string","format":"uuid"},"step_id":{"type":"string","format":"uuid"},"draft_id":{"type":"string","format":"uuid"},"subject":{"type":"string"},"body_html":{"type":"string"},"body_text":{"type":"string"},"dry_run":{"type":"boolean"}}},"example":{"to_email":"user@example.com","site_id":"00000000-0000-4000-8000-000000000000"}}}},"responses":{"200":{"description":"Sent response includes status, sent, to, to_email, provider, provider_message_id, resend_id (null except Resend), unsubscribe. Preview includes dry_run, subject, html, text, recipient_status, headers_preview; sent is false and provider/message IDs are null."},"400":{"description":"Invalid JSON or non-object body"},"401":{"description":"Authentication required"},"403":{"description":"Insufficient scope"},"404":{"description":"Step, draft or site not found in the project"},"409":{"description":"Recipient suppressed (RECIPIENT_SUPPRESSED)"},"422":{"description":"Unknown or invalid field, conflicting content sources, or SITE_MISMATCH"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"Failed to render, record or send the test"}},"operationId":"postCampaignsTestSend","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported"}},"/campaigns/{id}/steps/{stepId}/test":{"post":{"summary":"Send a campaign step test email","responses":{"200":{"description":"Test email sent"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postCampaignsByIdStepsByStepIdTest","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/campaigns/ab-tests":{"post":{"summary":"Create an A/B test from a campaign step","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["step_id","name"],"properties":{"step_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"metric":{"type":"string","enum":["open_rate","click_rate","conversion"],"default":"open_rate"},"split_ratio":{"type":"integer","minimum":1,"maximum":99,"default":50},"test_type":{"type":"string","enum":["full","subject_only"],"default":"full"}}},"example":{"step_id":"00000000-0000-4000-8000-000000000000","name":"string"}}}},"responses":{"200":{"description":"A/B test created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postCampaignsAbTests","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"patch":{"summary":"Update A/B test metadata or select winner","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["test_id"],"properties":{"test_id":{"type":"string","format":"uuid"},"variant_label":{"type":"string"},"subject":{"type":"string"},"body_html":{"type":"string"},"action":{"type":"string"},"winner_variant_label":{"type":"string"},"send_to_remainder":{"type":"boolean"}}},"example":{"test_id":"00000000-0000-4000-8000-000000000000"}}}},"responses":{"200":{"description":"A/B test updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchCampaignsAbTests","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"get":{"summary":"Check A/B test significance","parameters":[{"in":"query","name":"testId","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"A/B significance result"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaignsAbTests","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"}},"/campaigns/{id}/stats":{"get":{"summary":"Per-campaign delivery metrics","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Stats — { sent, opened, clicked, bounced, unsubscribed, open_rate, click_rate }"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getCampaignsByIdStats","security":[{"OAuth2":["campaigns"]},{"ApiKeyAuth":[]}],"x-required-scope":"campaigns"}},"/analytics/portfolio":{"get":{"summary":"Cross-site portfolio email analytics rollup","responses":{"200":{"description":"Portfolio analytics"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAnalyticsPortfolio","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics"}},"/analytics/product-usage":{"get":{"summary":"Product usage analytics from PostHog for worker context","responses":{"200":{"description":"PostHog identify/event/DAU rollup or configured false when PostHog is unavailable"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"PostHog analytics query failed"}},"operationId":"getAnalyticsProductUsage","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics"}},"/analytics/overview":{"get":{"summary":"Site-level email overview metrics for a lookback window","parameters":[{"in":"query","name":"site_id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365},"example":1}],"responses":{"200":{"description":"Overview metrics including sender health, list growth, and tracking-aware engagement rates"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAnalyticsOverview","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics"}},"/analytics/campaigns":{"get":{"summary":"Per-campaign analytics for a site over the recent lookback window","parameters":[{"in":"query","name":"site_id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50},"example":1}],"responses":{"200":{"description":"Campaign analytics sorted by sent volume"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAnalyticsCampaigns","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics"}},"/analytics/revenue":{"get":{"summary":"Stripe connector revenue, churn, MRR, and subscription lifecycle analytics","parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":365},"example":1},{"in":"query","name":"connection_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Revenue analytics including MRR, logo churn rate, lifecycle counts, collected revenue, and failed payments"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAnalyticsRevenue","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics"}},"/analytics/engagement":{"get":{"summary":"Contact engagement lifecycle analytics","responses":{"200":{"description":"Engagement analytics"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAnalyticsEngagement","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics"}},"/analytics/conversion":{"post":{"summary":"Record a conversion event (analytics alias)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionRequest"},"example":{"event":"string"}}}},"responses":{"200":{"description":"Conversion recorded"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postAnalyticsConversion","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/analytics/performance":{"get":{"summary":"Email performance trends and best send times","responses":{"200":{"description":"Performance analytics"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getAnalyticsPerformance","security":[{"OAuth2":["analytics"]},{"ApiKeyAuth":[]}],"x-required-scope":"analytics"}},"/sites/{id}/deliverability":{"get":{"summary":"Site deliverability status with DMARC monitor summary","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Deliverability status"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdDeliverability","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/domain-health":{"get":{"summary":"Site domain health history","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Domain health snapshots"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdDomainHealth","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/insights":{"get":{"summary":"Site analytics insights","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Insights"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdInsights","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/sites/{id}/abuse-monitor":{"get":{"summary":"Site complaint and abuse monitor","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Abuse monitor"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSitesByIdAbuseMonitor","security":[{"OAuth2":["sites"]},{"ApiKeyAuth":[]}],"x-required-scope":"sites"}},"/lists":{"get":{"summary":"List contact lists with subscriber counts","parameters":[{"in":"query","name":"site_id","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Lists — { lists[{ id, name, subscriber_count }] }"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getLists","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/lists/{id}/subscribers":{"get":{"summary":"Page through a contact list's subscribers","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"in":"query","name":"page","schema":{"type":"integer","minimum":1},"example":1}],"responses":{"200":{"description":"Subscribers — { subscribers[{ id, email, status, subscribed_at }], total, page }"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getListsByIdSubscribers","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/social/request-reply":{"post":{"summary":"Request a LinkedIn personal reply proposal card","description":"Parses a LinkedIn comment or post URL, drafts a suggested reply using transient in-memory context (never stored or logged), and creates a pending proposal card for the target member. Never posts directly; a human Accept is required.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","operationId":"requestSocialReply","tags":["Social"],"security":[{"apiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["comment_or_post_url"],"properties":{"comment_or_post_url":{"type":"string","description":"The LinkedIn comment or post URL/URN to reply to."},"comment_text_for_drafting":{"type":"string","description":"The comment (or post) text, needed to draft the reply. Used once in memory, never stored or logged. Without it the request returns 422 and no card is created."},"target_member_id":{"type":"string","format":"uuid","description":"Target member UUID. Required for API keys lacking member identity."}}},"example":{"comment_or_post_url":"string"}}}},"responses":{"200":{"description":"Existing pending proposal card returned (deduplication)"},"201":{"description":"Proposal card created","content":{"application/json":{"schema":{"type":"object","properties":{"card_id":{"type":"string","format":"uuid"},"status":{"type":"string"},"duplicate":{"type":"boolean"},"approve_link":{"type":"string"},"message":{"type":"string"},"post_urn":{"type":"string"},"comment_urn":{"type":"string","nullable":true}}}}}},"400":{"description":"Bad request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"description":"Rate limit exceeded"}},"x-required-scope":"write","x-idempotency":"not_supported"}},"/social/campaigns":{"get":{"summary":"List social campaigns","responses":{"200":{"description":"Social campaigns"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialCampaigns","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Create a social campaign with posts (honors Idempotency-Key)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"site_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"posts":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time"},"linkedin_company_crosspost":{"type":"boolean"},"linkedin_company_page_id":{"type":"string"},"content":{"type":"object"}}}}}},"example":{"name":"string"}}}},"responses":{"201":{"description":"Created — { campaign_id, status, posts[] }"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSocialCampaigns","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/social/campaigns/{id}":{"get":{"summary":"Get a social campaign with its posts","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Social campaign"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSocialCampaignsById","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"patch":{"summary":"Update social campaign status/name — status 'active' dispatches held posts","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","active","paused","completed"]},"name":{"type":"string"}}},"example":{}}}},"responses":{"200":{"description":"Updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchSocialCampaignsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/social/campaigns/{id}/posts":{"post":{"summary":"Add a post to a social campaign","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["platform","content"],"properties":{"platform":{"type":"string"},"linkedin_company_crosspost":{"type":"boolean"},"linkedin_company_page_id":{"type":"string"},"scheduled_at":{"type":"string","format":"date-time"},"content":{"type":"object"}}},"example":{"platform":"string","content":{}}}}},"responses":{"201":{"description":"Post created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSocialCampaignsByIdPosts","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes."}},"/suppressions":{"get":{"summary":"List suppressions","responses":{"200":{"description":"Suppressions — cursor pagination on created_at"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSuppressions","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Suppress an email address","responses":{"201":{"description":"Suppression created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSuppressions","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Remove a suppression by email","parameters":[{"in":"query","name":"email","required":true,"schema":{"type":"string","format":"email"},"example":"user@example.com"}],"responses":{"200":{"description":"Suppression removed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteSuppressions","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/suppressions/{id}":{"delete":{"summary":"Remove a suppression by id","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Suppression removed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteSuppressionsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/outbound-digest":{"get":{"summary":"Get the platform-admin outbound digest","description":"Requires admin scope and a key or OAuth grant bound to a configured platform-admin account, using the support-ticket reply gate. Tenant, unbound and scoped-JWT credentials receive Not available. Defaults to the last 24 hours across all projects. SQL aggregates sends per campaign step or broadcast and category, with test sends separate. Missing attribution and unsent approval counts stay null. Source failures are reported in status and unknown_sources instead of a complete empty result.","parameters":[{"name":"since","in":"query","description":"Inclusive window start; defaults to now minus 24 hours. Must be before now.","schema":{"type":"string","format":"date-time"},"example":"2026-01-01T00:00:00Z"},{"name":"project_id","in":"query","description":"Optional project filter; omitted means the full fleet.","schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Digest through the exclusive server timestamp, including explicit source availability.","content":{"application/json":{"schema":{"type":"object","required":["product","range","status","unknown_sources","items"],"properties":{"product":{"type":"string","enum":["sendinel"]},"range":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}},"status":{"type":"string","enum":["complete","partial","unknown"]},"unknown_sources":{"type":"array","items":{"type":"string","enum":["action_approvals","email_log"]}},"items":{"type":"array","items":{"type":"object","required":["project_id","agent_kind","agent_id","agent_label","item","audience_count","counts","is_test","approval_id","approve_url","outcome","approved_by","approved_at","occurred_at","provider_ref"],"properties":{"project_id":{"type":"string","format":"uuid"},"agent_kind":{"type":"string","nullable":true,"enum":["worker","connected_agent","user","system",null]},"agent_id":{"type":"string","nullable":true},"agent_label":{"type":"string","nullable":true},"item":{"type":"object","required":["type","id","summary","platform","preview_url"],"properties":{"type":{"type":"string","enum":["email","broadcast"]},"id":{"type":"string"},"summary":{"type":"string"},"platform":{"type":"string","nullable":true,"enum":[null]},"preview_url":{"type":"string","nullable":true}}},"audience_count":{"type":"integer","nullable":true},"counts":{"type":"object","nullable":true,"required":["sent","delivered","bounced","complained","opened"],"properties":{"sent":{"type":"integer"},"delivered":{"type":"integer"},"bounced":{"type":"integer"},"complained":{"type":"integer"},"opened":{"type":"integer"}}},"is_test":{"type":"boolean"},"approval_id":{"type":"string","nullable":true},"approve_url":{"type":"string","nullable":true},"outcome":{"type":"string","enum":["pending_approval","approved","declined","expired","scheduled","sent","failed"]},"approved_by":{"type":"string","nullable":true},"approved_at":{"type":"string","format":"date-time","nullable":true},"occurred_at":{"type":"string","format":"date-time"},"provider_ref":{"type":"string","nullable":true}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Not available to this credential."},"422":{"description":"Invalid since or project_id, or since is not before now."},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getOutboundDigest","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}},"/support/tickets":{"get":{"summary":"List support tickets for the caller's organization","description":"Returns customer-safe status for tickets belonging to the caller's organization. Scoped to the caller's org_id. Supports optional ticket reference and status filters.","parameters":[{"name":"ticket","in":"query","description":"Filter to a single ticket by SND number or integer ID (e.g. SND-1015 or 1015)","schema":{"type":"string"},"example":"string"},{"name":"status","in":"query","description":"Filter tickets by status (e.g. open, in_progress, closed)","schema":{"type":"string"},"example":"string"},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100},"example":1},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0},"example":0}],"responses":{"200":{"description":"List of support tickets"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getSupportTickets","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"File a support ticket on the tenant's behalf (bug report, feature request or feedback)","description":"Creates a ticket in the same pipeline as the dashboard support form, including the GitHub issue and Slack alert. Attributed to the acting user (user-bound key or OAuth caller), falling back to the project owner. Supports Idempotency-Key.\n\nIdempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","description"],"properties":{"title":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["bug","feature","feedback","other"],"default":"bug"},"priority":{"type":"string","enum":["low","medium","high","critical"],"default":"medium"},"page_context":{"type":"object","additionalProperties":true}}},"example":{"title":"string","description":"string"}}}},"responses":{"201":{"description":"Ticket created"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"description":"Missing or invalid field, or the acting user could not be resolved"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postSupportTickets","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/support/tickets/{ref}/reply":{"post":{"summary":"Post an exact Kevin-approved support ticket reply","description":"Platform-admin principal and admin scope only. The SHA-256 hash must match the exact body. An audit row is written before the comment; a failed insert gets a failure audit. No email or automatic status change. Resolved or closed tickets require explicit reopen.\n\nIdempotency-Key is not supported on this endpoint; a retried request may repeat the action.","parameters":[{"name":"ref","in":"path","required":true,"schema":{"type":"string","pattern":"^SND-[0-9]+$"},"example":"string"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body","approval_ref","body_sha256"],"properties":{"body":{"type":"string"},"approval_ref":{"type":"string"},"body_sha256":{"type":"string","pattern":"^[0-9a-f]{64}$"},"reopen":{"type":"boolean"}}},"example":{"body":"string","approval_ref":"string","body_sha256":"string"}}}},"responses":{"201":{"description":"Comment posted"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Not available to tenant principals"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Resolved or closed ticket requires reopen"},"422":{"description":"Missing input or exact-text hash mismatch"},"429":{"description":"Organization hourly reply limit exceeded"},"503":{"description":"Audit write failed; no comment was posted"}},"operationId":"postSupportTicketsByRefReply","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported"}},"/webhook-subscriptions":{"get":{"summary":"List registered outbound webhooks (secrets never returned)","responses":{"200":{"description":"Subscriptions"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getWebhookSubscriptions","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"},"post":{"summary":"Register an outbound webhook — signing secret returned once","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"site_id":{"type":"string","format":"uuid"},"description":{"type":"string"},"secret":{"type":"string","description":"Optional caller-supplied signing secret (16-256 chars)"}}},"example":{"url":"string","events":["string"]}}}},"responses":{"201":{"description":"Created — includes the signing secret (only time it is returned)"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"postWebhookSubscriptions","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"supported","description":"Idempotent with an Idempotency-Key header: the key is claimed when the request starts, so a retry with the same key and the same request returns the stored response instead of repeating the action. A request with the same key that arrives while the first is still running gets 409 IDEMPOTENCY_IN_FLIGHT with a Retry-After header, and the same key with a different request gets 422 IDEMPOTENCY_KEY_REUSED. A request that fails before completing frees its key after about 5 minutes.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional client-chosen key. A retry with the same key in the same project returns the stored response.","schema":{"type":"string","maxLength":255},"example":"3f1c2a9e-retry-safe-key"}]}},"/webhook-subscriptions/{id}":{"patch":{"summary":"Update an outbound webhook (url, events, active, description)","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Updated"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"patchWebhookSubscriptionsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."},"delete":{"summary":"Remove an outbound webhook","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"example":"00000000-0000-4000-8000-000000000000"}],"responses":{"200":{"description":"Removed"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"deleteWebhookSubscriptionsById","security":[{"OAuth2":["write"]},{"ApiKeyAuth":[]}],"x-required-scope":"write","x-idempotency":"not_supported","description":"Idempotency-Key is not supported on this endpoint; a retried request may repeat the action."}},"/embed/token/validate":{"get":{"summary":"Verify a Sendinel-issued embed token (server-to-server, for embedding platforms)","description":"Non-consuming (peek) validation — the same token may be checked repeatedly across a full embed session, not just once. Auth via Authorization Bearer header or embed_token query param.","parameters":[{"in":"query","name":"embed_token","required":false,"description":"Embed token, if not supplied via the Authorization Bearer header","schema":{"type":"string"},"example":"string"}],"responses":{"200":{"description":"Token is valid — returns the project and scopes it grants","content":{"application/json":{"schema":{"type":"object","properties":{"project_id":{"type":"string","format":"uuid"},"scopes":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Embed token missing, invalid, or expired"},"403":{"description":"Embed token does not grant the required scope"},"429":{"$ref":"#/components/responses/RateLimited"}},"operationId":"getEmbedTokenValidate","security":[{"OAuth2":["read"]},{"ApiKeyAuth":[]}],"x-required-scope":"read"}}}}