{"openapi":"3.1.0","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"info":{"description":"Trama's REST API. Authenticate with an organization API key, created under Developers in the dashboard, and send it as `Authorization: Bearer <key>` (or in the `x-api-key` header).\n\nEvery key is bound to ONE organization: everything this API returns and everything it writes stays inside that organization, and no request ever names it.\n\nErrors always come back as `{ \"error\": { \"code\", \"message\" } }`. Branch on `code` — it is stable; the `message` text is not.","title":"Trama API","version":"1.0.0"},"servers":[{"url":"https://api.trama.so"}],"components":{"securitySchemes":{"bearerAuth":{"bearerFormat":"API key","description":"The organization API key, sent as `Authorization: Bearer <key>`.","scheme":"bearer","type":"http"},"apiKeyHeader":{"description":"The same API key, sent in the `x-api-key` header.","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"CatalogProductList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CatalogProduct"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"CatalogProduct":{"type":"object","properties":{"budgetTier":{"type":["string","null"],"enum":["economic","mid","premium",null]},"capacityMax":{"type":["integer","null"]},"capacityMin":{"type":["integer","null"]},"coverImage":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"currency":{"type":["string","null"]},"description":{"type":["string","null"]},"destinations":{"type":"array","items":{"type":"string"}},"durationDays":{"type":["integer","null"]},"durationHours":{"type":["number","null"]},"excludes":{"type":"array","items":{"type":"string"}},"externalReferenceCode":{"type":["string","null"],"description":"The code the agency uses for this product in THEIR system. It is what makes syncing possible without storing Trama's ids."},"fromPrice":{"type":["number","null"]},"gallery":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"includes":{"type":"array","items":{"type":"string"}},"operator":{"type":["string","null"]},"priceBasis":{"type":["string","null"]},"priceMax":{"type":["number","null"]},"pricingMode":{"type":"string","enum":["per_person","per_group","total"]},"shortDescription":{"type":["string","null"]},"specialConditions":{"type":["string","null"]},"status":{"type":"string","enum":["active","paused","draft"]},"title":{"type":"string"},"type":{"type":"string","enum":["package","experience","expedition","custom"]},"updatedAt":{"type":"string","format":"date-time"},"validFrom":{"type":["string","null"]},"validUntil":{"type":["string","null"]},"variants":{"type":"array","items":{"$ref":"#/components/schemas/CatalogProductVariant"}}},"required":["budgetTier","capacityMax","capacityMin","coverImage","createdAt","currency","description","destinations","durationDays","durationHours","excludes","externalReferenceCode","fromPrice","gallery","id","includes","operator","priceBasis","priceMax","pricingMode","shortDescription","specialConditions","status","title","type","updatedAt","validFrom","validUntil","variants"]},"CatalogProductVariant":{"type":"object","properties":{"capacityMax":{"type":["integer","null"]},"capacityMin":{"type":["integer","null"]},"currency":{"type":["string","null"]},"description":{"type":["string","null"]},"durationDays":{"type":["integer","null"]},"durationHours":{"type":["number","null"]},"excludes":{"type":"array","items":{"type":"string"}},"fromPrice":{"type":["number","null"]},"id":{"type":"string"},"includes":{"type":"array","items":{"type":"string"}},"label":{"type":"string"},"position":{"type":"integer"},"priceMax":{"type":["number","null"]},"shortDescription":{"type":["string","null"]},"status":{"type":"string","enum":["active","paused","draft"]}},"required":["capacityMax","capacityMin","currency","description","durationDays","durationHours","excludes","fromPrice","id","includes","label","position","priceMax","shortDescription","status"]},"Pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"total":{"type":"integer"}},"required":["limit","offset","total"]},"ErrorResponse":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/ApiError"}},"required":["error"]},"ApiError":{"type":"object","properties":{"code":{"type":"string","description":"A stable, machine-readable code. Branch on this — the `message` text may change, the code will not.","example":"CATALOG_PRODUCT_NOT_FOUND"},"message":{"type":"string","example":"The catalog product does not exist."}},"required":["code","message"]},"ArchivedCatalogProduct":{"type":"object","properties":{"archivedAt":{"type":"string","format":"date-time"},"id":{"type":"string"}},"required":["archivedAt","id"]},"CustomerList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Customer":{"type":"object","properties":{"city":{"type":["string","null"]},"contacts":{"type":"array","items":{"$ref":"#/components/schemas/CustomerContact"}},"country":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"displayName":{"type":["string","null"],"description":"First and last name joined. Null when the person has not said their name yet — an anonymous lead is still a valid lead."},"firstName":{"type":["string","null"]},"id":{"type":"string"},"lastName":{"type":["string","null"]},"preferredLanguage":{"type":["string","null"]},"summary":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"updatedAt":{"type":"string","format":"date-time"}},"required":["city","contacts","country","createdAt","displayName","firstName","id","lastName","preferredLanguage","summary","tags","updatedAt"]},"CustomerContact":{"type":"object","properties":{"displayName":{"type":["string","null"]},"id":{"type":"string"},"identifierType":{"type":"string","enum":["whatsapp","instagram","messenger","email","telefono","web"]},"identifierValue":{"type":"string","description":"The identifier within its channel: an E.164 phone number for whatsapp/telefono, the handle for instagram, the address for email."},"phoneNumber":{"type":["string","null"]}},"required":["displayName","id","identifierType","identifierValue","phoneNumber"]},"ArchivedCustomer":{"type":"object","properties":{"archived":{"type":"boolean"},"id":{"type":"string"}},"required":["archived","id"]},"OpportunityList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Opportunity"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Opportunity":{"type":"object","properties":{"budgetCurrency":{"type":["string","null"]},"budgetMax":{"type":["number","null"]},"budgetMin":{"type":["number","null"]},"checkInDate":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"customerId":{"type":["string","null"]},"customerName":{"type":["string","null"]},"destination":{"type":["string","null"]},"id":{"type":"string"},"lastActivityAt":{"type":["string","null"],"format":"date-time"},"nights":{"type":["integer","null"]},"passengerCount":{"type":["integer","null"]},"qualifiedAt":{"type":["string","null"],"format":"date-time","description":"When the opportunity became qualified. Null means it never entered the pipeline."},"salesStage":{"type":"string"},"sellerMemberId":{"type":["string","null"]},"sellerName":{"type":["string","null"]},"shortRef":{"type":["string","null"],"description":"Short human-readable reference the agency uses to name it."},"stage":{"type":["string","null"],"description":"Key of the pipeline column it currently sits in. This is the key, not a title: each agency renames its columns, so the key is the stable thing to branch on."},"stageId":{"type":["string","null"]},"temperature":{"type":["string","null"],"description":"How warm the lead is: hot | warm | cold | unknown | discarded. This is what the agency sees in Trama: the agent qualifies it automatically, and a member of the team can override it by hand — when they do, theirs is the one reported here."},"title":{"type":["string","null"]},"updatedAt":{"type":"string","format":"date-time"}},"required":["budgetCurrency","budgetMax","budgetMin","checkInDate","createdAt","customerId","customerName","destination","id","lastActivityAt","nights","passengerCount","qualifiedAt","salesStage","sellerMemberId","sellerName","shortRef","stage","stageId","temperature","title","updatedAt"]},"ConversationList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Conversation":{"type":"object","properties":{"activityState":{"type":["string","null"]},"channel":{"type":"string","example":"whatsapp"},"contact":{"type":"string","description":"The identifier on its channel — a phone number, a handle."},"contactName":{"type":["string","null"]},"controlledBy":{"type":["string","null"],"description":"Who holds the thread: the agent, or a person on the team who took over."},"createdAt":{"type":"string","format":"date-time"},"customerId":{"type":["string","null"]},"customerName":{"type":["string","null"]},"id":{"type":"string"},"language":{"type":["string","null"]},"lastMessageAt":{"type":["string","null"],"format":"date-time"}},"required":["activityState","channel","contact","contactName","controlledBy","createdAt","customerId","customerName","id","language","lastMessageAt"]},"ConversationTranscript":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConversationMessage"}},"total":{"type":"integer"}},"required":["data","total"]},"ConversationMessage":{"type":"object","properties":{"content":{"type":"string"},"conversationId":{"type":"string","description":"Which thread this message came from. It matters when the reply stitches rotated threads together: without it, two stretches months apart read as one continuous chat."},"createdAt":{"type":"string"},"direction":{"type":"string","example":"inbound"},"id":{"type":"string"},"messageType":{"type":"string"},"senderName":{"type":["string","null"]}},"required":["content","conversationId","createdAt","direction","id","messageType","senderName"]},"QuoteList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Quote"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"Quote":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"currency":{"type":["string","null"]},"customerId":{"type":["string","null"]},"customerName":{"type":["string","null"]},"destination":{"type":["string","null"]},"firstOpenedAt":{"type":["string","null"],"format":"date-time"},"id":{"type":"string"},"lastOpenedAt":{"type":["string","null"],"format":"date-time"},"openCount":{"type":"integer","description":"How many times the customer opened it. 0 = never seen."},"opportunityId":{"type":"string"},"price":{"type":["number","null"]},"publishedAt":{"type":["string","null"],"format":"date-time"},"status":{"type":"string","enum":["draft","published","disabled"]},"title":{"type":"string"},"token":{"type":"string","description":"Token of the public quote link. Use it to build the URL the customer sees — that is what lets an integration deliver the quote through its own channel."},"updatedAt":{"type":"string","format":"date-time"}},"required":["createdAt","currency","customerId","customerName","destination","firstOpenedAt","id","lastOpenedAt","openCount","opportunityId","price","publishedAt","status","title","token","updatedAt"]},"QuoteAttachmentList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/QuoteAttachment"}}},"required":["data"]},"QuoteAttachment":{"type":"object","properties":{"fileName":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"mimeType":{"type":"string"},"sizeBytes":{"type":"integer"},"url":{"type":"string","description":"SIGNED download URL, and short-lived by design — it is a download credential, not a permanent link. Fetch the file when you receive it; do not store the URL."}},"required":["fileName","id","kind","mimeType","sizeBytes","url"]},"TeamMemberList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TeamMember"}},"pagination":{"$ref":"#/components/schemas/Pagination"}},"required":["data","pagination"]},"TeamMember":{"type":"object","properties":{"createdAt":{"type":"string","format":"date-time"},"email":{"type":"string"},"id":{"type":"string"},"isAssignable":{"type":"boolean","description":"Whether they take part in the automatic assignment of opportunities."},"name":{"type":"string"},"roles":{"type":"array","items":{"type":"string"},"description":"A LIST, not a single value: a member holds a base role plus optional add-ons.","example":["owner"]},"userId":{"type":"string"}},"required":["createdAt","email","id","isAssignable","name","roles","userId"]}},"parameters":{}},"paths":{"/v1/catalog/products":{"get":{"operationId":"listCatalogProducts","summary":"List catalog products","description":"Returns the organization's non-archived products, most recently updated first.","tags":["Catalog"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"How many items to return. Maximum 100.","example":25},"required":false,"description":"How many items to return. Maximum 100.","name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0,"description":"How many items to skip from the beginning.","example":0},"required":false,"description":"How many items to skip from the beginning.","name":"offset","in":"query"},{"schema":{"type":"string","enum":["economic","mid","premium"]},"required":false,"name":"budgetTier","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Matches against the title, summary and description."},"required":false,"description":"Matches against the title, summary and description.","name":"query","in":"query"},{"schema":{"type":"string","enum":["active","paused","draft"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","enum":["package","experience","expedition","custom"]},"required":false,"name":"type","in":"query"}],"responses":{"200":{"description":"The requested page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogProductList"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"createCatalogProduct","summary":"Create a product","tags":["Catalog"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"budgetTier":{"type":["string","null"],"enum":["economic","mid","premium",null]},"capacityMax":{"type":["integer","null"],"exclusiveMinimum":0},"capacityMin":{"type":["integer","null"],"exclusiveMinimum":0},"currency":{"type":["string","null"],"minLength":3,"maxLength":3,"example":"USD"},"description":{"type":["string","null"]},"durationDays":{"type":["integer","null"],"exclusiveMinimum":0},"durationHours":{"type":["number","null"],"exclusiveMinimum":0},"excludes":{"type":["array","null"],"items":{"type":"string"}},"externalReferenceCode":{"type":["string","null"],"description":"The code the agency uses for this product in THEIR system. It is what makes syncing possible without storing Trama's ids."},"fromPrice":{"type":["number","null"],"minimum":0},"includes":{"type":["array","null"],"items":{"type":"string"}},"operator":{"type":["string","null"]},"priceBasis":{"type":["string","null"]},"priceMax":{"type":["number","null"],"minimum":0},"pricingMode":{"type":"string","enum":["per_person","per_group","total"],"default":"per_person"},"shortDescription":{"type":["string","null"]},"specialConditions":{"type":["string","null"]},"status":{"type":"string","enum":["active","paused","draft"],"default":"active"},"title":{"type":"string","minLength":1},"type":{"type":"string","enum":["package","experience","expedition","custom"],"default":"package"},"validFrom":{"type":["string","null"],"example":"2026-01-01"},"validUntil":{"type":["string","null"],"example":"2026-12-31"},"variants":{"type":"array","items":{"type":"object","properties":{"capacityMax":{"type":["integer","null"],"exclusiveMinimum":0},"capacityMin":{"type":["integer","null"],"exclusiveMinimum":0},"currency":{"type":["string","null"],"minLength":3,"maxLength":3},"description":{"type":["string","null"]},"durationDays":{"type":["integer","null"],"exclusiveMinimum":0},"excludes":{"type":["array","null"],"items":{"type":"string"}},"fromPrice":{"type":["number","null"],"minimum":0},"includes":{"type":["array","null"],"items":{"type":"string"}},"label":{"type":"string","minLength":1},"priceMax":{"type":["number","null"],"minimum":0},"shortDescription":{"type":["string","null"]},"status":{"type":"string","enum":["active","paused","draft"],"default":"active"}},"required":["label"]}}},"required":["title"]}}}},"responses":{"201":{"description":"The created product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogProduct"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/catalog/products/{productId}":{"get":{"operationId":"getCatalogProduct","summary":"Get a product","tags":["Catalog"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"productId"}],"responses":{"200":{"description":"The product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogProduct"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"operationId":"updateCatalogProduct","summary":"Update a product","description":"Only touches the fields present in the body. Sending `null` clears a field; omitting it leaves it unchanged. Variants cannot be patched — send them on create, or the whole list would be replaced by a partial one.","tags":["Catalog"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"productId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"budgetTier":{"type":["string","null"],"enum":["economic","mid","premium",null]},"capacityMax":{"type":["integer","null"],"exclusiveMinimum":0},"capacityMin":{"type":["integer","null"],"exclusiveMinimum":0},"currency":{"type":["string","null"],"minLength":3,"maxLength":3,"example":"USD"},"description":{"type":["string","null"]},"durationDays":{"type":["integer","null"],"exclusiveMinimum":0},"durationHours":{"type":["number","null"],"exclusiveMinimum":0},"excludes":{"type":["array","null"],"items":{"type":"string"}},"externalReferenceCode":{"type":["string","null"],"description":"The code the agency uses for this product in THEIR system. It is what makes syncing possible without storing Trama's ids."},"fromPrice":{"type":["number","null"],"minimum":0},"includes":{"type":["array","null"],"items":{"type":"string"}},"operator":{"type":["string","null"]},"priceBasis":{"type":["string","null"]},"priceMax":{"type":["number","null"],"minimum":0},"pricingMode":{"type":"string","enum":["per_person","per_group","total"],"default":"per_person"},"shortDescription":{"type":["string","null"]},"specialConditions":{"type":["string","null"]},"status":{"type":"string","enum":["active","paused","draft"],"default":"active"},"title":{"type":"string","minLength":1},"type":{"type":"string","enum":["package","experience","expedition","custom"],"default":"package"},"validFrom":{"type":["string","null"],"example":"2026-01-01"},"validUntil":{"type":["string","null"],"example":"2026-12-31"}}}}}},"responses":{"200":{"description":"The updated product.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogProduct"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"deleteCatalogProduct","summary":"Archive a product","description":"ARCHIVES the product: it leaves the active catalog and can be restored from the dashboard for 30 days, after which it is purged. Deliberately not an immediate delete — a buggy integration should not be able to destroy an agency's catalog.","tags":["Catalog"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"productId"}],"responses":{"200":{"description":"The product was archived.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchivedCatalogProduct"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/customers":{"get":{"operationId":"listCustomers","summary":"List customers","description":"Returns the organization's non-archived customers, most recently updated first.","tags":["Customers"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"How many items to return. Maximum 100.","example":25},"required":false,"description":"How many items to return. Maximum 100.","name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0,"description":"How many items to skip from the beginning.","example":0},"required":false,"description":"How many items to skip from the beginning.","name":"offset","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Matches against the name, the summary, and the identifier of any of their contacts (phone number, Instagram handle, email)."},"required":false,"description":"Matches against the name, the summary, and the identifier of any of their contacts (phone number, Instagram handle, email).","name":"query","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"tag","in":"query"}],"responses":{"200":{"description":"The requested page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerList"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"createCustomer","summary":"Create a customer","description":"Fails if any of the contacts already belongs to another customer in the organization: one person is ONE record, and duplicating it splits their history in two.","tags":["Customers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"city":{"type":["string","null"]},"contacts":{"type":"array","items":{"type":"object","properties":{"identifierType":{"type":"string","enum":["whatsapp","instagram","messenger","email","telefono","web"]},"identifierValue":{"type":"string","minLength":1,"description":"An E.164 phone number for whatsapp/telefono, the handle for instagram, the address for email.","example":"+5491122334455"}},"required":["identifierType","identifierValue"]},"minItems":1,"description":"At least one. The first in the list becomes the primary contact."},"country":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"preferredLanguage":{"type":["string","null"],"enum":["es","pt","en",null]},"summary":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}}},"required":["contacts"]}}}},"responses":{"201":{"description":"The created customer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/customers/{customerId}":{"get":{"operationId":"getCustomer","summary":"Get a customer","tags":["Customers"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"customerId"}],"responses":{"200":{"description":"The customer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"operationId":"updateCustomer","summary":"Update a customer","description":"Only touches the fields present in the body. `contacts`, when present, REPLACES the whole list; when absent, the existing list is preserved.","tags":["Customers"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"customerId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"city":{"type":["string","null"]},"contacts":{"type":"array","items":{"type":"object","properties":{"identifierType":{"type":"string","enum":["whatsapp","instagram","messenger","email","telefono","web"]},"identifierValue":{"type":"string","minLength":1,"description":"An E.164 phone number for whatsapp/telefono, the handle for instagram, the address for email.","example":"+5491122334455"}},"required":["identifierType","identifierValue"]},"minItems":1,"description":"At least one. The first in the list becomes the primary contact."},"country":{"type":["string","null"]},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"preferredLanguage":{"type":["string","null"],"enum":["es","pt","en",null]},"summary":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"The updated customer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Customer"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"archiveCustomer","summary":"Archive a customer","description":"ARCHIVES the customer: they leave the active book and the listings, but their history is not destroyed. Deliberate — a buggy integration should not be able to wipe an agency's customer base.","tags":["Customers"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"customerId"}],"responses":{"200":{"description":"The customer was archived.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchivedCustomer"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/opportunities":{"get":{"operationId":"listOpportunities","summary":"List opportunities","description":"Returns the organization's non-archived opportunities, most recently updated first.","tags":["Opportunities"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"How many items to return. Maximum 100.","example":25},"required":false,"description":"How many items to return. Maximum 100.","name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0,"description":"How many items to skip from the beginning.","example":0},"required":false,"description":"How many items to skip from the beginning.","name":"offset","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Matches against the title, short reference and destination."},"required":false,"description":"Matches against the title, short reference and destination.","name":"query","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"salesStage","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Id of a pipeline column, to fetch just that stage."},"required":false,"description":"Id of a pipeline column, to fetch just that stage.","name":"stageId","in":"query"}],"responses":{"200":{"description":"The requested page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpportunityList"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/opportunities/{opportunityId}":{"get":{"operationId":"getOpportunity","summary":"Get an opportunity","tags":["Opportunities"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"opportunityId"}],"responses":{"200":{"description":"The opportunity.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Opportunity"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/conversations":{"get":{"operationId":"listConversations","summary":"List conversations","description":"Returns the organization's conversations, most recent message first.","tags":["Conversations"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"How many items to return. Maximum 100.","example":25},"required":false,"description":"How many items to return. Maximum 100.","name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0,"description":"How many items to skip from the beginning.","example":0},"required":false,"description":"How many items to skip from the beginning.","name":"offset","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"activityState","in":"query"},{"schema":{"type":"string","minLength":1,"example":"whatsapp"},"required":false,"name":"channel","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"customerId","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Matches against the contact name and the channel identifier."},"required":false,"description":"Matches against the contact name and the channel identifier.","name":"query","in":"query"}],"responses":{"200":{"description":"The requested page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationList"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/conversations/{conversationId}/messages":{"get":{"operationId":"listConversationMessages","summary":"Get the transcript of a conversation","description":"Oldest first — the order of a transcript, so it reads the way it was spoken.\n\nTakes `limit` but no `offset`, and that is deliberate rather than an omission: messages live in two different stores depending on how the channel arrived (WhatsApp, Instagram and Messenger come through the provider; the web chat is handled by the agent runtime), and the reply also stitches together rotated threads. There is no single ordering to offset into, so offering one would return wrong pages. Ask for the number of messages you need.","tags":["Conversations"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"conversationId"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"How many messages to return. Maximum 200."},"required":false,"description":"How many messages to return. Maximum 200.","name":"limit","in":"query"}],"responses":{"200":{"description":"The transcript.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationTranscript"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/quotes":{"get":{"operationId":"listQuotes","summary":"List quotes","description":"Returns the organization's non-archived quotes, most recently updated first.","tags":["Quotes"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"How many items to return. Maximum 100.","example":25},"required":false,"description":"How many items to return. Maximum 100.","name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0,"description":"How many items to skip from the beginning.","example":0},"required":false,"description":"How many items to skip from the beginning.","name":"offset","in":"query"},{"schema":{"type":"string","minLength":1},"required":false,"name":"opportunityId","in":"query"},{"schema":{"type":"string","minLength":1,"description":"Matches against the title and destination."},"required":false,"description":"Matches against the title and destination.","name":"query","in":"query"},{"schema":{"type":"string","enum":["draft","published","disabled"]},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"The requested page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteList"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/quotes/{quoteId}/attachments":{"get":{"operationId":"listQuoteAttachments","summary":"List the attachments of a quote","description":"Each attachment comes with a SIGNED, short-lived download URL. Fetch the file when you receive it; do not store the URL — it expires. Unlike catalog images, which live in a public bucket, quote attachments are private.","tags":["Quotes"],"parameters":[{"schema":{"type":"string"},"required":true,"in":"path","name":"quoteId"}],"responses":{"200":{"description":"The attachments, with signed URLs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteAttachmentList"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/team":{"get":{"operationId":"listTeamMembers","summary":"List team members","tags":["Team"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"description":"How many items to return. Maximum 100.","example":25},"required":false,"description":"How many items to return. Maximum 100.","name":"limit","in":"query"},{"schema":{"type":["integer","null"],"minimum":0,"default":0,"description":"How many items to skip from the beginning.","example":0},"required":false,"description":"How many items to skip from the beginning.","name":"offset","in":"query"}],"responses":{"200":{"description":"The requested page.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TeamMemberList"}}}},"400":{"description":"The request is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"The API key is missing or not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The resource does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"The API key exceeded its request limit. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"webhooks":{}}