{"openapi":"3.1.0","info":{"title":"BlueMarlin API","version":"1.0.0","description":"Public REST API for BlueMarlin. Authentication uses Bearer tokens (API keys with prefix `bm_live_`). Errors follow the Stripe-style shape { error: { type, code?, message, param? } }."},"servers":[{"url":"https://api.bluemarlinchat.com","description":"Production"}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"bm_live_*","description":"BlueMarlin API key. Use `Authorization: Bearer bm_live_...`."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["invalid_request_error","authentication_error","permission_error","not_found","conflict","rate_limit_error","api_error"]},"code":{"type":"string"},"message":{"type":"string"},"param":{"type":"string"}},"required":["type","message"]}},"required":["error"]},"DeletedResponse":{"type":"object","properties":{"object":{"type":"string","enum":["deleted"]},"id":{"type":"string"}},"required":["object","id"]},"UsageTotals":{"type":"object","properties":{"inputTokens":{"type":"integer","minimum":0},"outputTokens":{"type":"integer","minimum":0},"embeddingTokens":{"type":"integer","minimum":0},"estimatedCost":{"type":"number"},"requestCount":{"type":"integer","minimum":0}},"required":["inputTokens","outputTokens","embeddingTokens","estimatedCost","requestCount"]},"UsageResponse":{"type":"object","properties":{"object":{"type":"string","enum":["usage"]},"periodStart":{"type":"string","format":"date-time"},"periodEnd":{"type":"string","format":"date-time"},"user":{"allOf":[{"$ref":"#/components/schemas/UsageTotals"},{"type":["object","null"]}]},"org":{"$ref":"#/components/schemas/UsageTotals"},"quota":{"type":"object","properties":{"usedEur":{"type":"number"},"limitEur":{"type":"number"},"percent":{"type":"number"},"state":{"type":"string","enum":["ok","warning","blocked"]}},"required":["usedEur","limitEur","percent","state"]}},"required":["object","periodStart","periodEnd","user","org","quota"]},"Record":{"type":"object","properties":{"object":{"type":"string","enum":["record"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"organizationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"collectionId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"phoneNumber":{"type":["string","null"]},"phoneCountry":{"type":["string","null"],"minLength":2,"maxLength":2},"properties":{"type":"object","additionalProperties":{}},"lastContactedAt":{"type":["string","null"],"format":"date-time"},"lastRepliedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["object","id","organizationId","collectionId","phoneNumber","phoneCountry","properties","lastContactedAt","lastRepliedAt","createdAt","updatedAt"]},"RecordList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Record"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more"]},"RecordCount":{"type":"object","properties":{"object":{"type":"string","enum":["count"]},"count":{"type":"integer","minimum":0}},"required":["object","count"]},"CreateRecordBody":{"type":"object","properties":{"phoneNumber":{"type":["string","null"],"minLength":1},"phoneCountry":{"type":["string","null"],"minLength":2,"maxLength":2},"properties":{"type":"object","additionalProperties":{},"default":{}},"autoCreateOptions":{"type":"boolean","default":false}}},"UpdateRecordBody":{"type":"object","properties":{"phoneNumber":{"type":["string","null"],"minLength":1},"phoneCountry":{"type":["string","null"],"minLength":2,"maxLength":2},"properties":{"type":"object","additionalProperties":{}},"autoCreateOptions":{"type":"boolean","default":false}}},"File":{"type":"object","properties":{"object":{"type":"string","enum":["file"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"organizationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"recordId":{"type":["string","null"],"format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"collectionId":{"type":["string","null"],"format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"fieldId":{"type":["string","null"]},"name":{"type":"string"},"originalName":{"type":"string"},"mimeType":{"type":"string"},"size":{"type":["integer","null"]},"kind":{"type":"string","enum":["image","video","audio","pdf","document"]},"url":{"type":"string"},"isExternal":{"type":"boolean"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["object","id","organizationId","recordId","collectionId","fieldId","name","originalName","mimeType","size","kind","url","isExternal","position","createdAt"]},"BulkExternalAttachBody":{"type":"object","properties":{"mode":{"type":"string","enum":["append","replace_field"],"default":"append"},"attachments":{"type":"array","items":{"type":"object","properties":{"recordId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"fieldId":{"type":"string","minLength":1,"maxLength":64},"url":{"type":"string","maxLength":2048,"format":"uri"},"mimeType":{"type":"string","minLength":1,"maxLength":255},"name":{"type":"string","minLength":1,"maxLength":255}},"required":["recordId","fieldId","url"]},"minItems":1,"maxItems":5000}},"required":["attachments"]},"BulkExternalAttachResponse":{"type":"object","properties":{"object":{"type":"string","enum":["bulk_attach"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/File"}},"deleted":{"type":"integer","minimum":0}},"required":["object","data","deleted"]},"CollectionSchemaJson":{"type":"object","properties":{"sections":{"type":"array","items":{"type":"object","additionalProperties":{}}},"primaryFieldId":{"type":"string"}},"required":["sections"],"additionalProperties":{}},"Collection":{"type":"object","properties":{"object":{"type":"string","enum":["collection"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"name":{"type":"string"},"icon":{"type":"string"},"isContact":{"type":"boolean"},"isDefault":{"type":"boolean"},"schema":{"$ref":"#/components/schemas/CollectionSchemaJson"},"position":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["object","id","name","icon","isContact","isDefault","schema","position","createdAt","updatedAt"]},"CollectionList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more"]},"SearchResult":{"type":"object","properties":{"object":{"type":"string","enum":["search_result"]},"type":{"type":"string","enum":["record"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"displayName":{"type":"string"},"phoneNumber":{"type":["string","null"]},"updatedAt":{"type":"string","format":"date-time"},"collection":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"name":{"type":"string"},"icon":{"type":"string"},"isContact":{"type":"boolean"}},"required":["id","name","icon","isContact"]}},"required":["object","type","id","displayName","phoneNumber","updatedAt","collection"]},"SearchList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more"]},"Tag":{"type":"object","properties":{"object":{"type":"string","enum":["tag"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"organizationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"name":{"type":"string"},"color":{"type":"string","minLength":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["object","id","organizationId","name","color","createdAt","updatedAt"]},"TagList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more"]},"CreateTagBody":{"type":"object","properties":{"name":{"type":"string","minLength":1},"color":{"type":"string","minLength":1,"default":"blue"}},"required":["name"]},"UpdateTagBody":{"type":"object","properties":{"name":{"type":"string","minLength":1},"color":{"type":"string","minLength":1}}},"SetRecordTagsBody":{"type":"object","properties":{"tagIds":{"type":"array","items":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"}}},"required":["tagIds"]},"AddRecordTagBody":{"type":"object","properties":{"tagId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"}},"required":["tagId"]},"Conversation":{"type":"object","properties":{"object":{"type":"string","enum":["conversation"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"organizationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"whatsappAccountId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"contactPhoneNumber":{"type":"string"},"contactName":{"type":["string","null"]},"contactProfilePicUrl":{"type":["string","null"]},"status":{"type":"string","enum":["active","archived","spam"]},"handler":{"type":"string","enum":["human","ai"]},"unreadCount":{"type":"integer","minimum":0},"isStarred":{"type":"boolean"},"mutedUntil":{"type":["string","null"],"format":"date-time"},"windowExpiresAt":{"type":["string","null"],"format":"date-time"},"assignedUserId":{"type":["string","null"],"format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"lastMessageContent":{"type":["string","null"]},"lastMessageAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["object","id","organizationId","whatsappAccountId","contactPhoneNumber","contactName","contactProfilePicUrl","status","unreadCount","isStarred","mutedUntil","windowExpiresAt","assignedUserId","lastMessageContent","lastMessageAt","createdAt","updatedAt"]},"ConversationList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more"]},"AssignConversationBody":{"type":"object","properties":{"userId":{"type":["string","null"],"format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"}},"required":["userId"]},"SetHandlerBody":{"type":"object","properties":{"handler":{"type":"string","enum":["human","ai"]},"handoffReturn":{"type":"string","enum":["archive","never"]}},"required":["handler"]},"Message":{"type":"object","properties":{"object":{"type":"string","enum":["message"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"organizationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"accountPhoneNumber":{"type":"string"},"contactPhoneNumber":{"type":"string"},"waMessageId":{"type":["string","null"]},"direction":{"type":"string","enum":["inbound","outbound"]},"type":{"type":"string","enum":["text","image","video","audio","document","sticker","template","reaction","location","contacts","unknown"]},"status":{"type":"string","enum":["pending","queued","sent","delivered","read","failed"]},"content":{"type":"object","additionalProperties":{}},"statusHistory":{"type":["object","null"],"additionalProperties":{"type":"number"}},"senderUserId":{"type":["string","null"],"format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"origin":{"type":["string","null"]},"campaignId":{"type":["string","null"],"format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"replyToWaMessageId":{"type":["string","null"]},"errorCode":{"type":["string","null"]},"errorMessage":{"type":["string","null"]},"timestamp":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["object","id","organizationId","accountPhoneNumber","contactPhoneNumber","waMessageId","direction","type","status","content","statusHistory","senderUserId","origin","campaignId","replyToWaMessageId","errorCode","errorMessage","timestamp","createdAt"]},"MessageList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more"]},"SendMessageBody":{"anyOf":[{"type":"object","properties":{"text":{"type":"string","minLength":1}},"required":["text"]},{"type":"object","properties":{"mediaType":{"type":"string","enum":["image","video","audio","document"]},"mediaStorageKey":{"type":"string","minLength":1},"mimeType":{"type":"string","minLength":1},"filename":{"type":"string","minLength":1},"mediaSize":{"type":"integer","exclusiveMinimum":0},"caption":{"type":"string"}},"required":["mediaType","mediaStorageKey","mimeType","filename","mediaSize"]},{"type":"object","properties":{"type":{"type":"string","enum":["template"]},"template":{"type":"object","properties":{"templateName":{"type":"string","minLength":1},"languageCode":{"type":"string","minLength":1},"components":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["templateName","languageCode"]}},"required":["type","template"]},{"type":"object","properties":{"reaction":{"type":"object","properties":{"targetWaMessageId":{"type":"string","minLength":1},"emoji":{"type":"string"}},"required":["targetWaMessageId","emoji"]}},"required":["reaction"]}]},"TagsByPhonesBody":{"type":"object","properties":{"phones":{"type":"array","items":{"type":"string","minLength":1,"maxLength":40},"minItems":1,"maxItems":10000}},"required":["phones"]},"TagsByPhonesResponse":{"type":"object","properties":{"object":{"type":"string","enum":["tags_by_phones"]},"data":{"type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}}}},"required":["object","data"]},"MediaUrlResponse":{"type":"object","properties":{"object":{"type":"string","enum":["media_url"]},"url":{"type":"string","format":"uri"},"storageKey":{"type":"string"},"mediaSize":{"type":"integer"},"contentType":{"type":"string"},"alreadyDownloaded":{"type":"boolean"}},"required":["object","url"]},"ConversationActionResponse":{"type":"object","properties":{"object":{"type":"string","enum":["conversation_action"]},"success":{"type":"boolean"}},"required":["object","success"]},"MessageListAcrossConversations":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"type":"object","additionalProperties":{}}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more","next_cursor"]},"SendMessageTopLevelBody":{"allOf":[{"anyOf":[{"type":"object","properties":{"conversationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"}},"required":["conversationId"]},{"type":"object","properties":{"accountId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"contactPhoneNumber":{"type":"string","minLength":1}},"required":["accountId","contactPhoneNumber"]}]},{"$ref":"#/components/schemas/SendMessageBody"}]},"SentMessageResponse":{"type":"object","properties":{"object":{"type":"string","enum":["sent_message"]},"message":{"$ref":"#/components/schemas/Message"},"conversationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"}},"required":["object","message","conversationId"]},"WhatsAppAccount":{"type":"object","properties":{"object":{"type":"string","enum":["whatsapp_account"]},"id":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"organizationId":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"phoneNumberId":{"type":"string"},"wabaId":{"type":"string"},"phoneNumber":{"type":"string"},"displayName":{"type":"string"},"status":{"type":"string","enum":["active","disconnected","suspended"]},"qualityRating":{"type":["string","null"]},"throughputMps":{"type":["integer","null"]},"nameStatus":{"type":["string","null"]},"platformType":{"type":["string","null"]},"connectionType":{"type":"string","enum":["dedicated","coexistence"]},"webhookUrl":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["object","id","organizationId","phoneNumberId","wabaId","phoneNumber","displayName","status","qualityRating","throughputMps","nameStatus","platformType","connectionType","webhookUrl","createdAt","updatedAt"]},"WhatsAppAccountListResponse":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/WhatsAppAccount"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0}},"required":["object","data","has_more"]},"TemplateList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"type":"object","additionalProperties":{}}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0}},"required":["object","data","has_more"]},"CreateWhatsAppTemplateBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":512},"language":{"type":"string","minLength":2,"maxLength":10},"category":{"type":"string","enum":["marketing","utility","authentication"]},"components":{"type":"array","items":{"type":"object","additionalProperties":{}}},"allow_category_change":{"type":"boolean"}},"required":["name","language","category","components"]},"UpdateWhatsAppTemplateBody":{"type":"object","properties":{"components":{"type":"array","items":{"type":"object","additionalProperties":{}},"minItems":1},"category":{"type":"string","enum":["marketing","utility","authentication"]}},"required":["components"]},"WhatsAppTemplateSyncResponse":{"type":"object","properties":{"object":{"type":"string","enum":["template_sync"]},"synced":{"type":"integer","minimum":0},"removed":{"type":"integer","minimum":0}},"required":["object","synced"]},"ContactRestrictionList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"type":"object","additionalProperties":{}}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}},"required":["object","data","has_more","next_cursor"]},"Member":{"type":"object","properties":{"object":{"type":"string","enum":["member"]},"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"image":{"type":["string","null"]},"role":{"type":"string"}},"required":["object","id","name","email","image","role"]},"MemberList":{"type":"object","properties":{"object":{"type":"string","enum":["list"]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Member"}},"has_more":{"type":"boolean"},"total":{"type":"integer","minimum":0}},"required":["object","data","has_more"]},"WebhookConfig":{"type":"object","properties":{"object":{"type":"string","enum":["webhook_config"]},"url":{"type":["string","null"]},"secret":{"type":"string"},"events":{"type":"array","items":{"type":"string","enum":["whatsapp","contacts"]}},"enabled":{"type":"boolean"}},"required":["object","url","secret","events","enabled"]},"UpdateWebhookBody":{"type":"object","properties":{"url":{"type":["string","null"]},"events":{"type":"array","items":{"type":"string","enum":["whatsapp","contacts"]}},"enabled":{"type":"boolean"}},"additionalProperties":false},"RegenerateWebhookSecretResponse":{"type":"object","properties":{"object":{"type":"string","enum":["webhook_secret"]},"secret":{"type":"string"}},"required":["object","secret"]},"TestWebhookBody":{"type":"object","properties":{"eventType":{"type":"string","enum":["whatsapp.message","whatsapp.status"]}},"required":["eventType"]},"TestWebhookResponse":{"type":"object","properties":{"object":{"type":"string","enum":["webhook_test"]},"success":{"type":"boolean"},"statusCode":{"type":"integer"},"error":{"type":"string"}},"required":["object","success"]},"Me":{"type":"object","properties":{"object":{"type":"string","enum":["auth_context"]},"organizationId":{"type":"string","format":"uuid"},"organizationName":{"type":"string"},"organizationSlug":{"type":"string"},"method":{"type":"string","enum":["cookie","api_key"]},"apiKeyId":{"type":["string","null"],"format":"uuid"},"userId":{"type":["string","null"]},"scopes":{"type":"array","items":{"type":"string"}}},"required":["object","organizationId","organizationName","organizationSlug","method","apiKeyId","userId","scopes"]}},"parameters":{}},"paths":{"/v1/me/usage":{"get":{"tags":["Auth"],"summary":"Month-to-date AI usage for the caller and their organization","description":"Returns the calling org's month-to-date AI token usage, estimated cost, and quota state for the current calendar month (UTC). When authenticated via cookie, `user` carries the individual caller's slice; for API-key callers `user` is null (no associated user). Requires the `settings:read` scope (this exposes org-wide billing data).","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Usage + quota snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/collections/{collectionId}/records":{"get":{"tags":["Records"],"summary":"List records in a collection","description":"Returns records with cursor-based pagination. Pass `after` (UUID from `next_cursor` of the previous page) to fetch the next page. Supports `search` for fuzzy text and `filter` as URL-encoded JSON. `offset` is accepted as legacy fallback but `after` is preferred.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"collectionId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"after","in":"query"},{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"offset","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"search","in":"query"},{"schema":{"type":"string"},"required":false,"name":"groupByFieldId","in":"query"},{"schema":{"type":"string"},"required":false,"name":"groupKey","in":"query"},{"schema":{"type":"string"},"required":false,"name":"filter","in":"query"},{"schema":{"type":"string"},"required":false,"name":"sort","in":"query"}],"responses":{"200":{"description":"Paginated records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Records"],"summary":"Create a record","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"collectionId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRecordBody"}}}},"responses":{"201":{"description":"The created record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Record"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Phone number already exists in this collection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/whatsapp/{version}/{phone_number_id}/messages":{"post":{"tags":["WhatsApp Cloud API (compatible)"],"summary":"Send a message (Meta Cloud API compatible)","description":"Drop-in replacement for Meta's `POST /{version}/{phone_number_id}/messages`: keep your existing Cloud API payloads and SDKs, change only the base URL and use your BlueMarlin API key (`bm_live_*`, scope `whatsapp:write`) as the Bearer token. Supports every Meta message type (text, template, interactive, media by link, location, reaction...). Sent messages are recorded in the BlueMarlin inbox automatically. Responses mirror Meta's shapes, including errors. See Meta's Cloud API reference for the full payload catalog.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","example":"v21.0","description":"Graph API version, forwarded to Meta as-is."},"required":true,"description":"Graph API version, forwarded to Meta as-is.","name":"version","in":"path"},{"schema":{"type":"string","description":"Meta phone number ID of one of your connected WhatsApp numbers."},"required":true,"description":"Meta phone number ID of one of your connected WhatsApp numbers.","name":"phone_number_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{},"description":"Meta Cloud API message payload, forwarded verbatim.","example":{"messaging_product":"whatsapp","to":"+34600000000","type":"text","text":{"body":"Hello from BlueMarlin"}}}}}},"responses":{"200":{"description":"Meta's response, returned verbatim (includes `messages[0].id`, the wamid).","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key (Meta-style error shape)."},"403":{"description":"API key lacks the `whatsapp:write` scope (Meta-style error shape)."},"404":{"description":"Phone number not found or not owned by the key's organization."}}}},"/v1/search":{"get":{"tags":["Search"],"summary":"Global search across records","description":"Returns the top matching records across every collection in the org, ordered by full-text relevance with recency as a tiebreaker. When `q` is omitted or shorter than 2 characters after trimming, returns the most-recently-updated records instead — useful as the command-palette's idle state. Each result carries the collection's name/icon so the renderer doesn't have to cross-reference.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","maxLength":256},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Ranked search hits.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/collections":{"get":{"tags":["Collections"],"summary":"List collections","description":"Returns every collection in the authenticated organization.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"A list of collections.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/collections/{collectionId}":{"get":{"tags":["Collections"],"summary":"Retrieve a collection","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"collectionId","in":"path"}],"responses":{"200":{"description":"The collection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Collection"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/collections/{collectionId}/records/count":{"get":{"tags":["Records"],"summary":"Count records in a collection","description":"Returns the total number of records matching `search` and `filter`, without fetching them.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"collectionId","in":"path"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"search","in":"query"},{"schema":{"type":"string"},"required":false,"name":"filter","in":"query"}],"responses":{"200":{"description":"Total matching records.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecordCount"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/collections/{collectionId}/records/{recordId}":{"get":{"tags":["Records"],"summary":"Retrieve a record","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"collectionId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"recordId","in":"path"}],"responses":{"200":{"description":"The record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Record"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Records"],"summary":"Update a record","description":"Partially updates a record. `properties` is shallow-merged; omitted keys are preserved.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"collectionId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"recordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRecordBody"}}}},"responses":{"200":{"description":"The updated record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Record"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Phone number already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Records"],"summary":"Delete a record","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"collectionId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"recordId","in":"path"}],"responses":{"200":{"description":"Deletion confirmation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/records/{recordId}/tags":{"get":{"tags":["Tags"],"summary":"List tags attached to a record","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"recordId","in":"path"}],"responses":{"200":{"description":"The record's tags.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Tags"],"summary":"Replace the set of tags attached to a record","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"recordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetRecordTagsBody"}}}},"responses":{"200":{"description":"Confirmation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Tags"],"summary":"Attach a tag to a record","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"recordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddRecordTagBody"}}}},"responses":{"201":{"description":"The attached tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/records/{recordId}/tags/{tagId}":{"delete":{"tags":["Tags"],"summary":"Detach a tag from a record","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"recordId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"tagId","in":"path"}],"responses":{"200":{"description":"Detach confirmation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tags":{"get":{"tags":["Tags"],"summary":"List tags","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"All tags in the organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Tags"],"summary":"Create a tag","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTagBody"}}}},"responses":{"201":{"description":"The created tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A tag with this name already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tags/{tagId}":{"patch":{"tags":["Tags"],"summary":"Update a tag","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"tagId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTagBody"}}}},"responses":{"200":{"description":"The updated tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Tags"],"summary":"Delete a tag","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"tagId","in":"path"}],"responses":{"200":{"description":"Deletion confirmation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tags/by-phones":{"post":{"tags":["Tags"],"summary":"Lookup tags for many phone numbers at once","description":"Returns a map of phone → tags[]. Phones without matching records are omitted from the map.","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagsByPhonesBody"}}}},"responses":{"200":{"description":"Tags grouped by phone.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagsByPhonesResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations":{"get":{"tags":["Conversations"],"summary":"List conversations","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["active","archived","spam"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":false,"name":"accountId","in":"query"},{"schema":{"type":"string"},"required":false,"name":"phone","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":false,"name":"after","in":"query"},{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"offset","in":"query"}],"responses":{"200":{"description":"Paginated conversations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}":{"get":{"tags":["Conversations"],"summary":"Retrieve a conversation","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"The conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/messages":{"get":{"tags":["Conversations"],"summary":"List messages for a conversation","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"before","in":"query"}],"responses":{"200":{"description":"Messages ordered from oldest to newest.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Conversations"],"summary":"Send a message in a conversation","description":"Supports text, media, template, and reaction payloads. Template messages bypass the 24-hour window; free-form messages require an active window.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageBody"}}}},"responses":{"201":{"description":"The sent message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited by WhatsApp.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/messages/{messageId}/media":{"get":{"tags":["Conversations"],"summary":"Get a presigned URL for a message's media","description":"Only works if the media has already been downloaded from WhatsApp. Use POST first for new media.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"messageId","in":"path"}],"responses":{"200":{"description":"Presigned URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUrlResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Conversations"],"summary":"Download media from WhatsApp and store it","description":"Fetches the media bytes from Meta, stores them in object storage, and returns a presigned URL.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"messageId","in":"path"}],"responses":{"200":{"description":"Presigned URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUrlResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/archive":{"post":{"tags":["Conversations"],"summary":"Archive a conversation","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Archived.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationActionResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/unarchive":{"post":{"tags":["Conversations"],"summary":"Unarchive a conversation","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Unarchived.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["conversation_action"]},"success":{"type":"boolean"}},"required":["object","success"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/read":{"post":{"tags":["Conversations"],"summary":"Mark a conversation as read","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Marked as read.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["conversation_action"]},"success":{"type":"boolean"}},"required":["object","success"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/unread":{"post":{"tags":["Conversations"],"summary":"Mark a conversation as unread","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Marked as unread.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["conversation_action"]},"success":{"type":"boolean"}},"required":["object","success"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/assign":{"post":{"tags":["Conversations"],"summary":"Assign (or unassign) a conversation to a member","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignConversationBody"}}}},"responses":{"200":{"description":"Assignment saved.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["conversation_action"]},"success":{"type":"boolean"}},"required":["object","success"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/conversations/{conversationId}/handler":{"post":{"tags":["Conversations"],"summary":"Set the conversation handler (AI vs human)","description":"Currently supports transitioning back to the AI handler; human takeover happens automatically on reply.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetHandlerBody"}}}},"responses":{"200":{"description":"Handler updated.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["conversation_action"]},"success":{"type":"boolean"}},"required":["object","success"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/messages":{"get":{"tags":["Messages"],"summary":"Search messages across the organization","description":"Cross-conversation message list with optional filters.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"after","in":"query"},{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"offset","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"search","in":"query"},{"schema":{"type":"string","enum":["incoming","outgoing"]},"required":false,"name":"direction","in":"query"},{"schema":{"type":"string","maxLength":40},"required":false,"name":"accountPhoneNumber","in":"query"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":false,"name":"senderUserId","in":"query"}],"responses":{"200":{"description":"Messages matching filters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageListAcrossConversations"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Messages"],"summary":"Send a message","description":"Send a message either to an existing conversation (include `conversationId`) or to a WhatsApp account + contact phone (include `accountId` and `contactPhoneNumber`) — in the second case the conversation is created lazily. Payload shapes are the same four variants supported by POST /v1/conversations/{conversationId}/messages.","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageTopLevelBody"}}}},"responses":{"201":{"description":"The sent message and conversation id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SentMessageResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/whatsapp/accounts":{"get":{"tags":["WhatsApp"],"summary":"List WhatsApp Business accounts","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"All accounts in the org.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsAppAccountListResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/whatsapp/accounts/{accountId}":{"get":{"tags":["WhatsApp"],"summary":"Retrieve a WhatsApp Business account","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"accountId","in":"path"}],"responses":{"200":{"description":"The account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsAppAccount"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/whatsapp/accounts/{accountId}/templates":{"get":{"tags":["WhatsApp"],"summary":"List templates cached for a WhatsApp account","description":"Reads from the local template cache so this endpoint is fast and safe to call on every send. Filter by `status` and/or `category`.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"accountId","in":"path"},{"schema":{"type":"string"},"required":false,"name":"status","in":"query"},{"schema":{"type":"string"},"required":false,"name":"category","in":"query"}],"responses":{"200":{"description":"Cached templates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["WhatsApp"],"summary":"Create a WhatsApp message template","description":"Submits the template to Meta and persists the local row. The template starts in `PENDING` status and Meta updates it via webhook.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"accountId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWhatsAppTemplateBody"}}}},"responses":{"201":{"description":"Created template.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A template with this name already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited by Meta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/whatsapp/accounts/{accountId}/templates/{templateId}":{"get":{"tags":["WhatsApp"],"summary":"Retrieve a WhatsApp template","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"accountId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"templateId","in":"path"}],"responses":{"200":{"description":"The template.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["WhatsApp"],"summary":"Update a WhatsApp template (Meta API + local cache)","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"accountId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"templateId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWhatsAppTemplateBody"}}}},"responses":{"200":{"description":"Updated template.","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited by Meta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["WhatsApp"],"summary":"Delete a WhatsApp template (all language variants)","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"accountId","in":"path"},{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"templateId","in":"path"}],"responses":{"200":{"description":"Deletion confirmation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletedResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited by Meta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/whatsapp/accounts/{accountId}/templates/sync":{"post":{"tags":["WhatsApp"],"summary":"Synchronize templates from Meta API to local cache","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"019d1b6e-af9e-715b-80e9-6fc1240a585a"},"required":true,"name":"accountId","in":"path"}],"responses":{"200":{"description":"Sync result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsAppTemplateSyncResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited by Meta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/whatsapp/{version}/{waba_id}/message_templates":{"get":{"tags":["WhatsApp Cloud API (compatible)"],"summary":"List templates (Meta Cloud API compatible)","description":"Mirror of Meta's `GET /{waba_id}/message_templates`. Query parameters (`fields`, `limit`, `status`, `name`, cursors) are forwarded verbatim and Meta's paginated response is returned as-is. Authenticate with a BlueMarlin API key (`bm_live_*`, scope `whatsapp:read`).","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","example":"v21.0"},"required":true,"name":"version","in":"path"},{"schema":{"type":"string","description":"WhatsApp Business Account ID owning your numbers."},"required":true,"description":"WhatsApp Business Account ID owning your numbers.","name":"waba_id","in":"path"}],"responses":{"200":{"description":"Meta's template list response, verbatim (`data[]`, `paging`).","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key (Meta-style error shape)."},"403":{"description":"API key lacks the `whatsapp:read` scope."},"404":{"description":"WABA not found or not owned by the key's organization."}}},"post":{"tags":["WhatsApp Cloud API (compatible)"],"summary":"Create a template (Meta Cloud API compatible)","description":"Mirror of Meta's `POST /{waba_id}/message_templates`: same body (`name`, `language`, `category`, `components`), forwarded verbatim — Meta validates and queues the template for review. Requires scope `whatsapp:write`. The BlueMarlin template list resyncs automatically after creation; approval status updates arrive via Meta webhooks as usual.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","example":"v21.0"},"required":true,"name":"version","in":"path"},{"schema":{"type":"string"},"required":true,"name":"waba_id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{},"example":{"name":"order_shipped","language":"es","category":"UTILITY","components":[{"type":"BODY","text":"Tu pedido {{1}} ha sido enviado."}]}}}}},"responses":{"200":{"description":"Meta's response, verbatim (`id`, `status`, `category`).","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key (Meta-style error shape)."},"403":{"description":"API key lacks the `whatsapp:write` scope."},"404":{"description":"WABA not found or not owned by the key's organization."}}},"delete":{"tags":["WhatsApp Cloud API (compatible)"],"summary":"Delete a template (Meta Cloud API compatible)","description":"Mirror of Meta's `DELETE /{waba_id}/message_templates?name=...` (deletes every language of that template name; add `hsm_id` to target one). Requires scope `whatsapp:write`. The BlueMarlin template list resyncs automatically.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string","example":"v21.0"},"required":true,"name":"version","in":"path"},{"schema":{"type":"string"},"required":true,"name":"waba_id","in":"path"},{"schema":{"type":"string","description":"Template name to delete."},"required":true,"description":"Template name to delete.","name":"name","in":"query"},{"schema":{"type":"string"},"required":false,"name":"hsm_id","in":"query"}],"responses":{"200":{"description":"Meta's response, verbatim (`{ success: true }`).","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key (Meta-style error shape)."},"403":{"description":"API key lacks the `whatsapp:write` scope."},"404":{"description":"WABA not found or not owned by the key's organization."}}}},"/v1/contact-restrictions":{"get":{"tags":["Contact Restrictions"],"summary":"List contact restrictions","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":100},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"after","in":"query"},{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"offset","in":"query"},{"schema":{"type":"string","enum":["all","marketing"]},"required":false,"name":"type","in":"query"}],"responses":{"200":{"description":"Restrictions list.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactRestrictionList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Contact Restrictions"],"summary":"Add a contact restriction","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string","minLength":1,"maxLength":40},"type":{"type":"string","enum":["all","marketing"]},"reason":{"type":"string","maxLength":500}},"required":["phoneNumber"]}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["contact_restriction"]},"success":{"type":"boolean"}},"required":["object","success"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/contact-restrictions/{phoneNumber}":{"get":{"tags":["Contact Restrictions"],"summary":"Get the restriction status for a phone number","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"phoneNumber","in":"path"}],"responses":{"200":{"description":"Current restriction type (null if none).","content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":["string","null"],"enum":["all","marketing",null]}},"required":["type"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Contact Restrictions"],"summary":"Remove a restriction","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"phoneNumber","in":"path"},{"schema":{"type":"string","enum":["all","marketing"]},"required":false,"name":"type","in":"query"}],"responses":{"200":{"description":"Removed.","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","enum":["contact_restriction"]},"success":{"type":"boolean"}},"required":["object","success"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/members":{"get":{"tags":["Members"],"summary":"List organization members","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Members in the org.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberList"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/files/download-url":{"get":{"tags":["Files"],"summary":"Get a presigned URL for a storage key owned by the organization","description":"Security: only storage keys beginning with `organizations/{orgId}/` are accepted.","security":[{"ApiKeyAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"key","in":"query"}],"responses":{"200":{"description":"Presigned URL.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/files/bulk-external":{"post":{"tags":["Files"],"summary":"Attach external URLs as files in bulk","description":"Inserts attachments where each entry references an external HTTPS URL (no upload to R2). Use `mode: append` to add to existing files for each (recordId, fieldId), or `mode: replace_field` to first remove existing external attachments for those groups (R2-backed files are preserved). Designed for sync jobs that periodically refresh attachments from a third-party feed.","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkExternalAttachBody"}}}},"responses":{"200":{"description":"Attached files plus a count of any rows removed in replace mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkExternalAttachResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/media/upload-url":{"post":{"tags":["Files"],"summary":"Presigned upload URL for WhatsApp message media","description":"Validates against WhatsApp's media limits (type + size). Use the returned `storageKey` when sending a media message via POST /v1/conversations/:id/messages.","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255},"contentType":{"type":"string","minLength":1,"maxLength":255},"size":{"type":"integer","exclusiveMinimum":0,"maximum":104857600}},"required":["filename","contentType","size"]}}}},"responses":{"200":{"description":"Upload URL.","content":{"application/json":{"schema":{"type":"object","properties":{"uploadUrl":{"type":"string","format":"uri"},"storageKey":{"type":"string"},"mediaType":{"type":"string"}},"required":["uploadUrl","storageKey","mediaType"]}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"Retrieve the organization's outbound webhook configuration","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Webhook config.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConfig"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Webhooks"],"summary":"Update the outbound webhook configuration","description":"Configures the URL, event categories, and enabled flag. Non-localhost URLs must use HTTPS. Rotate the signing secret via POST /v1/webhooks/regenerate-secret.","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookBody"}}}},"responses":{"200":{"description":"Updated config.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookConfig"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/regenerate-secret":{"post":{"tags":["Webhooks"],"summary":"Regenerate the outbound webhook signing secret","description":"Returns the new signing secret. The previous secret is invalidated immediately — update consumers promptly.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"New signing secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegenerateWebhookSecretResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/webhooks/test":{"post":{"tags":["Webhooks"],"summary":"Send a test event to the configured webhook URL","description":"Delivers a synthetic event of the given type to the configured URL. Useful to verify signature validation on the receiver.","security":[{"ApiKeyAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestWebhookBody"}}}},"responses":{"200":{"description":"Delivery result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestWebhookResponse"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me":{"get":{"tags":["Auth"],"summary":"Inspect the current authentication context","description":"Returns the organization, authentication method, and scopes associated with the caller. Useful for clients (Claude Code, MCP servers, mobile apps) to confirm access at startup.","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Current auth context.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"400":{"description":"Invalid request (validation, missing params, bad shape).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid authentication.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Authenticated but not authorized (missing scope, foreign resource).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}