{
  "openapi": "3.1.0",
  "info": {
    "title": "Oriann Public API",
    "version": "1.0.0",
    "description": "REST API publica para consultar el estado operativo actual de Tickets, contactos, conversaciones, mensajes y plantillas de WhatsApp. Los webhooks notifican cambios; esta API es la fuente autoritativa para reconciliar estado."
  },
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "servers": [
    {
      "url": "https://{deployment}.convex.site/api/v1",
      "variables": {
        "deployment": {
          "default": "example"
        }
      }
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Contacts"
    },
    {
      "name": "Conversations"
    },
    {
      "name": "Messages"
    },
    {
      "name": "Templates"
    },
    {
      "name": "Tickets"
    }
  ],
  "x-api-key-prefix": "oriann_sk_",
  "x-rate-limits": {
    "read": "120 requests per minute per API key",
    "template_send": "30 requests per minute per API key",
    "pre_auth": "Pre-authentication traffic is throttled by source"
  },
  "x-response-headers": {
    "RateLimit-Limit": "Authenticated bucket limit",
    "RateLimit-Remaining": "Requests remaining in the current bucket",
    "RateLimit-Reset": "Unix seconds when the current bucket resets",
    "Retry-After": "Present on 429 responses",
    "Deprecation": "Present on legacy aliases"
  },
  "x-scopes": [
    "tickets:read",
    "contacts:read",
    "conversations:read",
    "messages:read",
    "templates:read",
    "templates:send"
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Use Authorization: Bearer <api_key>. API keys start with oriann_sk_."
      }
    },
    "parameters": {
      "Limit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 50
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 1024
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "pattern": "^[\\x20-\\x7E]+$"
        },
        "description": "Required idempotency key scoped by agent and operation."
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "additionalProperties": true,
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "additionalProperties": true,
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "invalid_request",
                  "invalid_cursor",
                  "unauthorized",
                  "forbidden_scope",
                  "not_found",
                  "idempotency_key_mismatch",
                  "idempotency_key_processing",
                  "idempotency_outcome_unknown",
                  "request_too_large",
                  "unsupported_media_type",
                  "validation_error",
                  "invalid_template_parameters",
                  "template_not_sendable",
                  "whatsapp_connection_not_ready",
                  "template_not_approved",
                  "provider_send_failed",
                  "rate_limited",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": ["field", "reason"],
                  "additionalProperties": false,
                  "properties": {
                    "field": { "type": "string" },
                    "reason": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": ["cursor", "hasMore"],
        "additionalProperties": true,
        "properties": {
          "cursor": {
            "type": ["string", "null"]
          },
          "hasMore": {
            "type": "boolean"
          }
        }
      },
      "TicketChangePagination": {
        "type": "object",
        "required": ["cursor", "after", "hasMore"],
        "additionalProperties": true,
        "properties": {
          "cursor": {
            "type": ["string", "null"],
            "deprecated": true,
            "description": "Alias transitorio de after."
          },
          "after": {
            "type": "string",
            "description": "Watermark que debe enviarse como after en la siguiente pagina, incluso cuando hasMore es false."
          },
          "hasMore": { "type": "boolean" }
        }
      },
      "Contact": {
        "type": "object",
        "required": [
          "id",
          "conversationId",
          "channel",
          "displayName",
          "phone",
          "phoneNormalized",
          "email",
          "preferredFollowupChannel",
          "createdAt",
          "updatedAt",
          "lastSeenAt"
        ],
        "additionalProperties": true,
        "properties": {
          "id": { "type": "string" },
          "conversationId": { "type": "string" },
          "channel": { "$ref": "#/components/schemas/Channel" },
          "displayName": { "type": ["string", "null"] },
          "phone": { "type": ["string", "null"] },
          "phoneNormalized": { "type": ["string", "null"] },
          "email": { "type": ["string", "null"] },
          "preferredFollowupChannel": { "type": ["string", "null"] },
          "createdAt": { "type": "number" },
          "updatedAt": { "type": "number" },
          "lastSeenAt": { "type": ["number", "null"] }
        }
      },
      "Conversation": {
        "type": "object",
        "required": [
          "id",
          "remoteJid",
          "remoteName",
          "channel",
          "crmStatus",
          "unreadCount",
          "hasUnread",
          "botPaused",
          "lastCustomerMessageAt",
          "lastOutboundAt",
          "windowExpiresAt",
          "lastMessageAt",
          "messageCount",
          "createdAt"
        ],
        "additionalProperties": true,
        "properties": {
          "id": { "type": "string" },
          "remoteJid": { "type": "string" },
          "remoteName": { "type": ["string", "null"] },
          "channel": { "$ref": "#/components/schemas/ChannelNullable" },
          "crmStatus": { "$ref": "#/components/schemas/CrmStatus" },
          "unreadCount": { "type": "number" },
          "hasUnread": { "type": "boolean" },
          "botPaused": { "type": "boolean" },
          "lastCustomerMessageAt": { "type": ["number", "null"] },
          "lastOutboundAt": { "type": ["number", "null"] },
          "windowExpiresAt": { "type": ["number", "null"] },
          "lastMessageAt": { "type": ["number", "null"] },
          "messageCount": { "type": "number" },
          "createdAt": { "type": "number" }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "id",
          "conversationId",
          "role",
          "content",
          "channel",
          "actor",
          "messageType",
          "deliveryStatus",
          "templateName",
          "templateLanguage",
          "templateBodyParameters",
          "mediaType",
          "mediaCaption",
          "createdAt"
        ],
        "additionalProperties": true,
        "properties": {
          "id": { "type": "string" },
          "conversationId": { "type": "string" },
          "role": { "type": "string", "enum": ["user", "assistant", "system"] },
          "content": { "type": "string" },
          "channel": { "$ref": "#/components/schemas/ChannelNullable" },
          "actor": { "type": ["string", "null"] },
          "messageType": { "type": "string" },
          "deliveryStatus": { "type": ["string", "null"] },
          "templateName": { "type": ["string", "null"] },
          "templateLanguage": { "type": ["string", "null"] },
          "templateBodyParameters": {
            "type": ["array", "null"],
            "items": { "type": "string" }
          },
          "mediaType": { "type": ["string", "null"] },
          "mediaCaption": { "type": ["string", "null"] },
          "createdAt": { "type": "number" }
        }
      },
      "Template": {
        "type": "object",
        "required": [
          "id",
          "templateName",
          "language",
          "category",
          "status",
          "parameterFormat",
          "components",
          "lastSyncedAt"
        ],
        "additionalProperties": true,
        "properties": {
          "id": { "type": "string" },
          "templateName": { "type": "string" },
          "language": { "type": "string" },
          "category": { "type": ["string", "null"] },
          "status": { "type": "string" },
          "parameterFormat": {
            "type": "string",
            "enum": ["positional", "named"]
          },
          "components": {},
          "capabilities": {
            "type": "object",
            "additionalProperties": true
          },
          "componentSupport": {
            "type": "object",
            "additionalProperties": true
          },
          "sendContract": {
            "type": ["object", "null"],
            "additionalProperties": true
          },
          "lastSyncedAt": { "type": ["number", "null"] }
        }
      },
      "TemplateSendRequest": {
        "type": "object",
        "required": ["phoneNormalized", "templateName", "templateLanguage"],
        "additionalProperties": false,
        "properties": {
          "phoneNormalized": {
            "type": "string",
            "pattern": "^\\d{8,15}$"
          },
          "templateName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "pattern": "^[a-z0-9_]+$"
          },
          "templateLanguage": {
            "type": "string",
            "minLength": 2,
            "maxLength": 10,
            "pattern": "^[a-z]{2,3}(?:_[A-Z]{2})?$"
          },
          "parameters": {
            "type": "object",
            "description": "Structured template parameters validated against the template sendContract. Supports BODY text, HEADER text, HEADER media id/link, and dynamic URL buttons by index.",
            "additionalProperties": false,
            "properties": {
              "body": {
                "oneOf": [
                  {
                    "type": "object",
                    "propertyNames": { "pattern": "^[a-z][a-z0-9_]*$" },
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 512
                    }
                  },
                  {
                    "type": "array",
                    "items": { "type": "string", "maxLength": 512 }
                  }
                ],
                "description": "Objeto nombrado para templates named o array posicional para templates positional."
              },
              "header": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "text": {
                    "oneOf": [
                      {
                        "type": "object",
                        "propertyNames": { "pattern": "^[a-z][a-z0-9_]*$" },
                        "additionalProperties": {
                          "type": "string",
                          "maxLength": 512
                        }
                      },
                      {
                        "type": "array",
                        "items": { "type": "string", "maxLength": 512 }
                      }
                    ],
                    "description": "Objeto nombrado o array posicional según parameterFormat."
                  },
                  "image": {
                    "$ref": "#/components/schemas/HeaderMediaParameter"
                  },
                  "video": {
                    "$ref": "#/components/schemas/HeaderMediaParameter"
                  },
                  "document": {
                    "$ref": "#/components/schemas/HeaderDocumentMediaParameter"
                  }
                }
              },
              "buttons": {
                "type": "array",
                "description": "Only dynamic URL buttons are accepted. QUICK_REPLY payloads are not part of the public contract.",
                "maxItems": 10,
                "items": {
                  "type": "object",
                  "required": ["index", "text"],
                  "additionalProperties": false,
                  "properties": {
                    "index": { "type": "integer", "minimum": 0, "maximum": 9 },
                    "text": { "type": "string", "maxLength": 512 }
                  }
                }
              }
            }
          }
        }
      },
      "HeaderMediaParameter": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": { "type": "string", "minLength": 1 },
          "link": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "pattern": "^https://"
          }
        },
        "oneOf": [
          { "required": ["id"], "not": { "required": ["link"] } },
          { "required": ["link"], "not": { "required": ["id"] } }
        ]
      },
      "HeaderDocumentMediaParameter": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": { "type": "string", "minLength": 1 },
          "link": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048,
            "pattern": "^https://"
          },
          "filename": { "type": "string", "minLength": 1, "maxLength": 255 }
        },
        "oneOf": [
          { "required": ["id"], "not": { "required": ["link"] } },
          { "required": ["link"], "not": { "required": ["id"] } }
        ]
      },
      "TemplateSendResponse": {
        "type": "object",
        "required": ["messageId", "conversationId", "templateSendId", "status"],
        "additionalProperties": true,
        "properties": {
          "messageId": { "type": "string" },
          "conversationId": { "type": "string" },
          "templateSendId": { "type": "string" },
          "providerMessageId": { "type": "string" },
          "status": { "type": "string", "enum": ["accepted"] }
        }
      },
      "TicketAttribute": {
        "type": "object",
        "required": ["id", "type", "value", "queryable"],
        "additionalProperties": false,
        "properties": {
          "id": { "type": "string" },
          "type": {
            "type": "string",
            "enum": [
              "string",
              "enum",
              "boolean",
              "number",
              "percentage",
              "date",
              "datetime"
            ]
          },
          "value": {
            "type": ["string", "number", "boolean", "null"]
          },
          "queryable": { "type": "boolean" }
        }
      },
      "TicketOutcome": {
        "type": "object",
        "required": ["code", "summary"],
        "additionalProperties": false,
        "properties": {
          "code": { "type": "string" },
          "summary": { "type": "string" }
        }
      },
      "TicketSnapshot": {
        "type": "object",
        "required": [
          "object",
          "id",
          "agentId",
          "conversationId",
          "flowId",
          "status",
          "ticketVersion",
          "attributes",
          "outcome",
          "createdAt",
          "updatedAt",
          "resolvedAt"
        ],
        "additionalProperties": false,
        "properties": {
          "object": { "type": "string", "const": "ticket" },
          "id": { "type": "string" },
          "agentId": { "type": "string" },
          "conversationId": { "type": "string" },
          "leadId": { "type": "string" },
          "flowId": { "type": "string" },
          "status": {
            "type": "string",
            "enum": ["open", "resolved", "reopened"]
          },
          "ticketVersion": { "type": "integer", "minimum": 1 },
          "attributes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TicketAttribute" }
          },
          "outcome": {
            "oneOf": [
              { "$ref": "#/components/schemas/TicketOutcome" },
              { "type": "null" }
            ]
          },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" },
          "resolvedAt": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "TicketTombstone": {
        "type": "object",
        "required": ["object", "id", "deletedAt"],
        "additionalProperties": false,
        "properties": {
          "object": { "type": "string", "const": "ticket_tombstone" },
          "id": { "type": "string" },
          "deletedAt": { "type": "string", "format": "date-time" }
        }
      },
      "TicketChange": {
        "type": "object",
        "required": ["position", "object"],
        "additionalProperties": false,
        "properties": {
          "position": {
            "type": "string",
            "description": "Posicion monotona opaca para reconciliacion."
          },
          "object": {
            "oneOf": [
              { "$ref": "#/components/schemas/TicketSnapshot" },
              { "$ref": "#/components/schemas/TicketTombstone" }
            ]
          }
        }
      },
      "Channel": {
        "type": "string",
        "enum": ["whatsapp", "instagram", "facebook", "web_test", "web_widget"]
      },
      "ChannelNullable": {
        "type": ["string", "null"],
        "enum": [
          "whatsapp",
          "instagram",
          "facebook",
          "web_test",
          "web_widget",
          null
        ]
      },
      "CrmStatus": {
        "type": "string",
        "enum": ["open", "resolved", "spam"]
      },
      "PaginatedContacts": {
        "type": "object",
        "required": ["data", "pagination"],
        "additionalProperties": true,
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Contact" }
          },
          "pagination": { "$ref": "#/components/schemas/Pagination" }
        }
      },
      "PaginatedConversations": {
        "type": "object",
        "required": ["data", "pagination"],
        "additionalProperties": true,
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Conversation" }
          },
          "pagination": { "$ref": "#/components/schemas/Pagination" }
        }
      },
      "PaginatedMessages": {
        "type": "object",
        "required": ["data", "pagination"],
        "additionalProperties": true,
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Message" }
          },
          "pagination": { "$ref": "#/components/schemas/Pagination" }
        }
      },
      "PaginatedTickets": {
        "type": "object",
        "required": ["data", "pagination"],
        "additionalProperties": false,
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TicketSnapshot" }
          },
          "pagination": { "$ref": "#/components/schemas/Pagination" }
        }
      },
      "TicketResponse": {
        "type": "object",
        "required": ["data"],
        "additionalProperties": false,
        "properties": {
          "data": { "$ref": "#/components/schemas/TicketSnapshot" }
        }
      },
      "PaginatedTicketChanges": {
        "type": "object",
        "required": ["data", "pagination"],
        "additionalProperties": false,
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/TicketChange" }
          },
          "pagination": {
            "$ref": "#/components/schemas/TicketChangePagination"
          }
        }
      },
      "TemplatesResponse": {
        "type": "object",
        "required": ["data", "pagination"],
        "additionalProperties": true,
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Template" }
          },
          "pagination": { "$ref": "#/components/schemas/Pagination" }
        }
      },
      "TemplateSendEnvelope": {
        "type": "object",
        "required": ["data"],
        "additionalProperties": true,
        "properties": {
          "data": { "$ref": "#/components/schemas/TemplateSendResponse" }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "API key invalida o ausente.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "ForbiddenScope": {
        "description": "La API key no tiene el scope requerido.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit excedido.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "ValidationError": {
        "description": "Parametros o body invalidos.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      },
      "InternalError": {
        "description": "Error interno generico.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      }
    }
  },
  "paths": {
    "/tickets": {
      "get": {
        "operationId": "listTickets",
        "tags": ["Tickets"],
        "summary": "List current Ticket snapshots",
        "description": "Lista el Snapshot actual de cada Ticket del agente. Usa cursor para backfill y como maximo un filtro de atributo tipado por request. No expone historial, OAD, reglas, prompts, secretos, trazas, rutas ni attempts.",
        "x-required-scope": "tickets:read",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["open", "resolved", "reopened"]
            }
          },
          {
            "name": "conversationId",
            "in": "query",
            "schema": { "type": "string", "minLength": 1, "maxLength": 256 }
          },
          {
            "name": "leadId",
            "in": "query",
            "schema": { "type": "string", "minLength": 1, "maxLength": 256 }
          },
          {
            "name": "flowId",
            "in": "query",
            "schema": { "type": "string", "minLength": 1, "maxLength": 256 }
          },
          {
            "name": "updatedAfter",
            "in": "query",
            "schema": { "type": "string", "format": "date-time" }
          },
          {
            "name": "updatedBefore",
            "in": "query",
            "schema": { "type": "string", "format": "date-time" }
          },
          {
            "name": "attributeId",
            "in": "query",
            "description": "Requiere tambien attributeType, attributeOperator y attributeValue.",
            "schema": { "type": "string", "minLength": 1, "maxLength": 256 }
          },
          {
            "name": "attributeType",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "string",
                "enum",
                "boolean",
                "number",
                "percentage",
                "date",
                "datetime"
              ]
            }
          },
          {
            "name": "attributeOperator",
            "in": "query",
            "description": "string, enum y boolean solo admiten eq.",
            "schema": { "type": "string", "enum": ["eq", "gte", "lte"] }
          },
          {
            "name": "attributeValue",
            "in": "query",
            "schema": { "type": "string", "maxLength": 1024 }
          }
        ],
        "responses": {
          "200": {
            "description": "Pagina de Snapshots actuales.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedTickets" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/tickets/{ticketId}": {
      "get": {
        "operationId": "getTicket",
        "tags": ["Tickets"],
        "summary": "Get current Ticket snapshot",
        "description": "Obtiene el Snapshot actual autoritativo. No existe un subrecurso publico /versions en V1.",
        "x-required-scope": "tickets:read",
        "parameters": [
          {
            "name": "ticketId",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "minLength": 1, "maxLength": 256 }
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot actual.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TicketResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "404": {
            "description": "Ticket no encontrado dentro del scope del agente.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/ticket-changes": {
      "get": {
        "operationId": "listTicketChanges",
        "tags": ["Tickets"],
        "summary": "Reconcile Ticket changes",
        "description": "Lista cambios ordenados por posicion monotona. Incluye Snapshots actuales y tombstones para recuperar cambios perdidos por webhooks. Conserva after y continua con cursor hasta hasMore=false.",
        "x-required-scope": "tickets:read",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          {
            "name": "after",
            "in": "query",
            "description": "Ultima position confirmada por el consumidor.",
            "schema": {
              "type": "string",
              "pattern": "^(?:0|[1-9]\\d{0,14}|[1-8]\\d{15}|900(?:[0-6]\\d{12}|7(?:0\\d{11}|1(?:[0-8]\\d{10}|9(?:[0-8]\\d{9}|9(?:[0-1]\\d{8}|2(?:[0-4]\\d{7}|5(?:[0-3]\\d{6}|4(?:[0-6]\\d{5}|7(?:[0-3]\\d{4}|40(?:[0-8]\\d{2}|9(?:[0-8]\\d{1}|9(?:0|1)))))))))))))$",
              "maxLength": 16
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pagina ordenada de cambios.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedTicketChanges"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/contacts": {
      "get": {
        "operationId": "listContacts",
        "tags": ["Contacts"],
        "summary": "List contacts",
        "description": "Lista contactos del agente asociado a la API key.",
        "x-required-scope": "contacts:read",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" }
        ],
        "responses": {
          "200": {
            "description": "Pagina de contactos.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedContacts" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/conversations": {
      "get": {
        "operationId": "listConversations",
        "tags": ["Conversations"],
        "summary": "List conversations",
        "description": "Lista conversaciones del agente asociado a la API key.",
        "x-required-scope": "conversations:read",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" },
          {
            "name": "channel",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/Channel" }
          },
          {
            "name": "crmStatus",
            "in": "query",
            "schema": { "$ref": "#/components/schemas/CrmStatus" }
          }
        ],
        "responses": {
          "200": {
            "description": "Pagina de conversaciones.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedConversations"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/conversations/{conversationId}/messages": {
      "get": {
        "operationId": "listConversationMessages",
        "tags": ["Messages"],
        "summary": "List conversation messages",
        "description": "Lista cronologicamente los mensajes de una conversacion dentro del agente asociado a la API key.",
        "x-required-scope": "messages:read",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" },
          {
            "name": "conversationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 256
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pagina de mensajes.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedMessages" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "404": {
            "description": "Conversacion no encontrada para el agente de la API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/messages": {
      "get": {
        "operationId": "listMessagesLegacy",
        "deprecated": true,
        "tags": ["Messages"],
        "summary": "List messages",
        "description": "Alias deprecado. Usa /conversations/{conversationId}/messages.",
        "x-required-scope": "messages:read",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" },
          {
            "name": "conversationId",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "minLength": 1 }
          }
        ],
        "responses": {
          "200": {
            "description": "Pagina de mensajes.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PaginatedMessages" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "404": {
            "description": "Conversacion no encontrada para el agente de la API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/templates": {
      "get": {
        "operationId": "listTemplates",
        "tags": ["Templates"],
        "summary": "List WhatsApp templates",
        "description": "Lista plantillas WhatsApp sincronizadas para el agente. Sin query conserva el maximo historico de 200; con limit/cursor el maximo es 100.",
        "x-required-scope": "templates:read",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Cursor" }
        ],
        "responses": {
          "200": {
            "description": "Plantillas WhatsApp.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/TemplatesResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    },
    "/template-sends": {
      "post": {
        "operationId": "createTemplateSend",
        "tags": ["Templates"],
        "summary": "Create a WhatsApp template send",
        "description": "Crea un envio idempotente de una plantilla WhatsApp aprobada y devuelve 202 cuando el proveedor lo acepta.",
        "x-required-scope": "templates:send",
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TemplateSendRequest" }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Envio aceptado por WhatsApp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateSendEnvelope"
                }
              }
            }
          },
          "400": {
            "description": "JSON invalido.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "409": {
            "description": "Idempotency key processing or outcome unknown.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "413": {
            "description": "Body mayor a 16 KB.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "415": {
            "description": "Content-Type debe ser application/json.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "502": {
            "description": "WhatsApp provider send failed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          }
        }
      }
    },
    "/templates/send": {
      "post": {
        "operationId": "createTemplateSendLegacy",
        "deprecated": true,
        "tags": ["Templates"],
        "summary": "Send a WhatsApp template",
        "description": "Envia una plantilla aprobada y enviable de WhatsApp a un telefono normalizado. Requiere Idempotency-Key en header. Usa parameters con objetos para variables named o arrays para variables positional; el formato se indica en GET /templates.",
        "x-required-scope": "templates:send",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200,
              "pattern": "^[\\x20-\\x7E]+$"
            },
            "description": "Required idempotency key scoped by agent and operation."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TemplateSendRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Plantilla aceptada por WhatsApp.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "additionalProperties": true,
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/TemplateSendResponse"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "JSON invalido.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/ForbiddenScope" },
          "409": {
            "description": "Idempotency key processing or outcome unknown.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "413": {
            "description": "Body mayor a 16 KB.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "415": {
            "description": "Content-Type debe ser application/json.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "502": {
            "description": "WhatsApp provider send failed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" }
        }
      }
    }
  }
}
