{
  "openapi": "3.1.0",
  "info": {
    "title": "Wazapi Public API",
    "version": "1.8.0",
    "description": "Server-to-server API for connecting ecommerce platforms, websites, and ERPs to Wazapi.",
    "license": {
      "name": "Proprietary",
      "identifier": "LicenseRef-Wazapi-Proprietary"
    },
    "contact": {
      "name": "Wazapi",
      "url": "https://wazapi.io"
    }
  },
  "servers": [
    {
      "url": "https://wazapi.io/api/v1"
    }
  ],
  "security": [
    {
      "WazapiApiKey": []
    }
  ],
  "paths": {
    "/channels": {
      "get": {
        "summary": "List WhatsApp channels",
        "operationId": "listChannels",
        "tags": [
          "Channels"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/ChannelList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Lists the WhatsApp channels available to this token, with the capabilities each one supports. The `uuid` returned here is the `channel_uuid` sends accept; it is also shown with a copy button in the dashboard under Settings > API. When the company has a single channel, sends may omit `channel_uuid` altogether."
      }
    },
    "/contacts": {
      "get": {
        "summary": "List contacts",
        "operationId": "listContacts",
        "tags": [
          "Contacts"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/ContactList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Lists contacts in the workspace. `external_id` is echoed for contacts linked to this integration."
      }
    },
    "/contacts/{contact_uuid}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ContactUuid"
        }
      ],
      "get": {
        "summary": "Get a contact",
        "operationId": "getContact",
        "tags": [
          "Contacts"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Contact"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Reads a single contact by its Wazapi uuid."
      },
      "patch": {
        "summary": "Update a contact",
        "operationId": "updateContact",
        "tags": [
          "Contacts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactWrite"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Contact"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Updates name, email, tags or custom fields of an existing contact. Fields left out are preserved; `custom_fields` is merged, not replaced."
      }
    },
    "/contacts/external/{external_id}": {
      "put": {
        "summary": "Create or update a contact by external ID",
        "operationId": "upsertExternalContact",
        "tags": [
          "Contacts"
        ],
        "parameters": [
          {
            "name": "external_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/ContactWrite"
                  },
                  {
                    "type": "object",
                    "required": [
                      "phone"
                    ],
                    "properties": {
                      "phone": {
                        "type": "string",
                        "examples": [
                          "+5511999999999"
                        ]
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Contact"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Creates or updates a contact keyed by your own system's identifier, and links it to this integration so later payloads echo `external_id` back. Idempotent — safe to call on every sync."
      }
    },
    "/flows": {
      "get": {
        "summary": "List flows",
        "operationId": "listFlows",
        "tags": [
          "Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "active"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/FlowList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Lists the flows in the workspace. Only flows with status `active` can be executed."
      }
    },
    "/flows/{flow_uuid}": {
      "get": {
        "summary": "Get a flow",
        "operationId": "getFlow",
        "tags": [
          "Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FlowUuid"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Flow"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Reads a single flow by uuid."
      }
    },
    "/flows/{flow_uuid}/executions": {
      "post": {
        "summary": "Start a flow execution",
        "operationId": "executeFlow",
        "tags": [
          "Flows"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/FlowUuid"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "recipient"
                ],
                "properties": {
                  "channel_uuid": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Optional when the company has a single WhatsApp channel (or a single connected one): the API resolves it. With several channels it is required and its absence answers `422 channel_required`. Discover values with `GET /channels`."
                  },
                  "recipient": {
                    "$ref": "#/components/schemas/Recipient"
                  },
                  "variables": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Arbitrary variables injected into the flow session, readable inside the flow as {{vars.<key>}} and usable in branch conditions. Use it to pass marketing attribution (utm_source, utm_campaign, gclid, ...) when triggering the flow; a set_field action block can persist them onto the contact's custom_fields."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/Accepted"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Starts a flow execution for one recipient. Asynchronous: returns `202` with a `Location` header — poll the operation for the outcome. If `recipient.external_id` is already linked to a contact with a different phone, the operation fails with `external_contact_conflict` instead of moving the record — repointing a contact is a contact write, and belongs to `PUT /contacts/external/{external_id}` under the `contacts:write` scope."
      }
    },
    "/templates": {
      "get": {
        "summary": "List WhatsApp templates",
        "description": "Discover the templates available for sending via POST /messages with type=template. Defaults to APPROVED templates; pass status to inspect others. Each item exposes the variable shape (body_parameter_count and any named parameters) so integrations can build the parameters array with the exact count.",
        "operationId": "listTemplates",
        "tags": [
          "Templates"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 120
            }
          },
          {
            "name": "channel_uuid",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Defaults to APPROVED.",
            "schema": {
              "type": "string",
              "enum": [
                "APPROVED",
                "PENDING",
                "REJECTED",
                "PAUSED",
                "DISABLED",
                "IN_APPEAL",
                "DRAFT"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/TemplateList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/templates/{name}": {
      "get": {
        "summary": "Get a WhatsApp template by name",
        "description": "Returns the best match for the template name, preferring an APPROVED version.",
        "operationId": "getTemplate",
        "tags": [
          "Templates"
        ],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 512
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Template"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/messages": {
      "post": {
        "summary": "Send a WhatsApp message",
        "operationId": "sendMessage",
        "tags": [
          "Messages"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "$ref": "#/components/responses/Accepted"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Sends a text or an approved template. Asynchronous: returns `202` with a `Location` header pointing at the operation to poll. Template payloads are validated synchronously, so a bad template name, language or parameter count is rejected here with 4xx instead of failing later. Send a unique `Idempotency-Key`: retries with the same key and body return the original operation instead of sending twice. If `recipient.external_id` is already linked to a contact with a different phone, the operation fails with `external_contact_conflict` instead of moving the record — repointing a contact is a contact write, and belongs to `PUT /contacts/external/{external_id}` under the `contacts:write` scope. Compliance gates apply to templates: MARKETING sending must be enabled by a company owner (`403 marketing_sends_disabled`), the recipient must not have opted out (`422 recipient_opted_out` — recipients opt out by replying PARAR/STOP or via the native WhatsApp control), a MARKETING template is not sent to a recipient whose previous MARKETING delivery failed with Meta error 131049 (per-user marketing limit) in the last 24h (`422 recipient_marketing_limit_reached`, with `details.retry_after_seconds`), a MARKETING template is not resent to the same recipient within 24h, and for other categories only an identical message (same template and parameters) is rejected in that window (`422 duplicate_template_send`, with `details.retry_after_seconds`), per-contact and per-company MARKETING frequency caps are enforced — sends made while the recipient's 24h customer service window is open do not count toward the per-contact caps (`422 template_frequency_cap_exceeded`, `422 company_daily_marketing_cap_exceeded`), and a channel whose quality Meta flagged pauses MARKETING (`422 channel_marketing_paused`). Delivery is paced per channel to protect number quality, so a `202` may take longer to complete under load; an operation that cannot be delivered within the pacing window fails with `send_pacing_timeout`. These codes also appear as `error.code` on the polled operation, along with `template_quality_blocked` and `template_sends_disabled`. `channel_uuid` may be omitted when the company has a single WhatsApp channel; with several, omitting it answers `422 channel_required`."
      }
    },
    "/operations/{operation_uuid}": {
      "get": {
        "summary": "Get an asynchronous operation",
        "operationId": "getOperation",
        "tags": [
          "Operations"
        ],
        "parameters": [
          {
            "name": "operation_uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Operation"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Reads the current state of an asynchronous operation. Poll until `status` is `succeeded` or `failed`."
      }
    },
    "/conversations": {
      "get": {
        "summary": "List conversations",
        "operationId": "listConversations",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "pending",
                "resolved"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/ConversationList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Lists conversations, most recently active first."
      }
    },
    "/conversations/{conversation_uuid}": {
      "get": {
        "summary": "Get a conversation",
        "operationId": "getConversation",
        "tags": [
          "Conversations"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ConversationUuid"
          },
          {
            "name": "include",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "messages"
              ]
            },
            "description": "Set to `messages` to embed the first page of messages in the response."
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/ConversationDetail"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Reads a single conversation by uuid with everything about the chat: contact (with tags), assigned agent and group, channel, status and counters. Pass `include=messages` to embed the first page of messages — audio messages carry their `transcript` as a first-level field."
      }
    },
    "/conversations/{conversation_uuid}/messages": {
      "get": {
        "summary": "List messages in a conversation",
        "operationId": "listConversationMessages",
        "tags": [
          "Messages"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ConversationUuid"
          },
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/MessageList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Lists the messages exchanged in a conversation."
      }
    },
    "/store": {
      "get": {
        "summary": "Get the store summary",
        "operationId": "getStore",
        "tags": [
          "Store"
        ],
        "description": "Storefront status, public URL and product/order counts. All store endpoints require the storefront to be available on the current plan (403 `storefront_not_allowed` otherwise).",
        "responses": {
          "200": {
            "$ref": "#/components/responses/StoreSummary"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/store/products": {
      "get": {
        "summary": "List store products",
        "operationId": "listStoreProducts",
        "tags": [
          "Store"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "query",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Search by name or description."
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/StoreProductList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "summary": "Create a store product",
        "operationId": "createStoreProduct",
        "tags": [
          "Store"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreProductWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "$ref": "#/components/responses/StoreProduct"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        },
        "description": "Creates a product. `422` codes: `promo_price_invalid`, `variant_duplicated`, `product_image_invalid` (an `image_urls` entry could not be downloaded as a public image — the reason is deliberately not detailed), `product_limit_reached` (5000 products per store)."
      }
    },
    "/store/products/batch": {
      "post": {
        "summary": "Create or update store products in batch",
        "operationId": "batchStoreProducts",
        "tags": [
          "Store"
        ],
        "description": "Up to 100 products per call, with a per-item result — one invalid product does not fail the batch. Items whose `import_handle` matches an existing product UPDATE it instead of creating a duplicate, which is how an external catalog (Shopify, an ERP) migrates and re-syncs idempotently.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "products"
                ],
                "properties": {
                  "products": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 100,
                    "items": {
                      "$ref": "#/components/schemas/StoreProductWrite"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-item batch result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreProductBatchResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/store/products/{product_uuid}": {
      "get": {
        "summary": "Get a store product",
        "operationId": "getStoreProduct",
        "tags": [
          "Store"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ProductUuid"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/StoreProduct"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "summary": "Update a store product",
        "operationId": "updateStoreProduct",
        "tags": [
          "Store"
        ],
        "description": "Partial update since API 1.6: omitted fields keep their current value (before 1.6 they were reset to their defaults, which reactivated the product and deleted its variants). `variants`, when sent, replaces the list.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProductUuid"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StoreProductPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/StoreProduct"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "summary": "Delete a store product",
        "operationId": "deleteStoreProduct",
        "tags": [
          "Store"
        ],
        "description": "Permanently deletes the product, its variants and its hosted images. Past orders are unaffected — they keep a snapshot of their items. Requires `store:write`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProductUuid"
          }
        ],
        "responses": {
          "204": {
            "description": "Product deleted"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/store/categories": {
      "get": {
        "summary": "List store categories",
        "operationId": "listStoreCategories",
        "tags": [
          "Store"
        ],
        "description": "Categories of the store, to discover the `category_uuid` accepted by the product endpoints.",
        "responses": {
          "200": {
            "description": "Store categories",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/StoreCategory"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/store/orders": {
      "get": {
        "summary": "List store orders",
        "operationId": "listStoreOrders",
        "tags": [
          "Store"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/After"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "novo",
                "confirmado",
                "pago",
                "entregue",
                "cancelado"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/StoreOrderList"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/store/orders/{order_uuid}": {
      "get": {
        "summary": "Get a store order",
        "operationId": "getStoreOrder",
        "tags": [
          "Store"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OrderUuid"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/StoreOrder"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/store/orders/{order_uuid}/status": {
      "post": {
        "summary": "Transition an order status",
        "operationId": "updateStoreOrderStatus",
        "tags": [
          "Store"
        ],
        "description": "State machine: novo→confirmado|cancelado, confirmado→pago|cancelado, pago→entregue|cancelado. An invalid transition returns 422 `invalid_status_transition`. Cancelling restores tracked stock.",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrderUuid"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "confirmado",
                      "pago",
                      "entregue",
                      "cancelado"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/StoreOrder"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "422": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "webhooks": {
    "wazapiEvent": {
      "post": {
        "summary": "Receive an event from Wazapi",
        "description": "Wazapi signs the exact request body with HMAC-SHA256. Compute the digest over `{Wazapi-Timestamp}.{rawBody}` using the integration webhook secret and accept a matching `v1` value in the comma-separated `Wazapi-Signature` header. During the 24-hour rotation overlap deliveries contain signatures for both the current and previous secret. Delivery is at-least-once; deduplicate using `Wazapi-Event-Id`.",
        "operationId": "receiveWazapiEvent",
        "tags": [
          "Webhooks"
        ],
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookEventId"
          },
          {
            "$ref": "#/components/parameters/WebhookEventType"
          },
          {
            "$ref": "#/components/parameters/WebhookDeliveryId"
          },
          {
            "$ref": "#/components/parameters/WebhookTimestamp"
          },
          {
            "$ref": "#/components/parameters/WebhookSignature"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event accepted"
          },
          "400": {
            "description": "Invalid payload or signature"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "WazapiApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "waz_api_..."
      }
    },
    "parameters": {
      "After": {
        "name": "after",
        "in": "query",
        "schema": {
          "type": "string"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 50
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        }
      },
      "ContactUuid": {
        "name": "contact_uuid",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "FlowUuid": {
        "name": "flow_uuid",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ConversationUuid": {
        "name": "conversation_uuid",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "WebhookEventId": {
        "name": "Wazapi-Event-Id",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "WebhookEventType": {
        "name": "Wazapi-Event",
        "in": "header",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/WebhookEventType"
        }
      },
      "WebhookDeliveryId": {
        "name": "Wazapi-Delivery-Id",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "WebhookTimestamp": {
        "name": "Wazapi-Timestamp",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[0-9]+$"
        }
      },
      "WebhookSignature": {
        "description": "Comma-separated v1 HMAC-SHA256 signatures. Accept any matching digest. During the 24-hour secret rotation window both current and previous secrets sign each delivery.",
        "name": "Wazapi-Signature",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^v1=[a-f0-9]{64}(,v1=[a-f0-9]{64})?$"
        }
      },
      "ProductUuid": {
        "name": "product_uuid",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "OrderUuid": {
        "name": "order_uuid",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "schemas": {
      "PaginationMeta": {
        "type": "object",
        "required": [
          "next_cursor"
        ],
        "properties": {
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "example": {
          "next_cursor": "MTQ3"
        }
      },
      "Channel": {
        "type": "object",
        "required": [
          "uuid",
          "provider",
          "status",
          "capabilities"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "provider": {
            "type": "string",
            "const": "whatsapp"
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "capabilities": {
            "type": "object",
            "required": [
              "send_text",
              "send_template",
              "start_flow"
            ],
            "properties": {
              "send_text": {
                "type": "boolean"
              },
              "send_template": {
                "type": "boolean"
              },
              "start_flow": {
                "type": "boolean"
              }
            }
          }
        },
        "example": {
          "uuid": "123e4567-e89b-12d3-a456-426614174000",
          "provider": "whatsapp",
          "display_name": "Atendimento",
          "phone_number": "+5511999990000",
          "status": "connected",
          "capabilities": {
            "send_text": true,
            "send_template": true,
            "start_flow": true
          }
        }
      },
      "Contact": {
        "type": "object",
        "required": [
          "uuid",
          "external_id",
          "phone",
          "tags",
          "custom_fields"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": true,
            "description": "Arbitrary key/value data stored on the contact. Marketing attribution follows the utm_*/click-ID convention (see ContactWrite). Wazapi itself records ad attribution here on first touch (ctwa_clid, ad_id, referral_source) when a contact arrives from a Click-to-WhatsApp ad."
          },
          "marketing_opted_out": {
            "type": "boolean",
            "description": "True when the contact opted out of marketing messages (reply keyword, native WhatsApp control, or manual suppression). Sending a MARKETING template to an opted-out contact fails with recipient_opted_out."
          },
          "marketing_opt_out_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_interaction_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "example": {
          "uuid": "9c2e4f31-7a55-4d0b-8f6a-2c9d1e5b7a03",
          "external_id": "customer-1847",
          "phone": "+5511999998888",
          "name": "Maria Silva",
          "email": "maria@exemplo.com.br",
          "tags": [
            "cliente",
            "vip"
          ],
          "custom_fields": {
            "tier": "gold"
          },
          "last_interaction_at": "2026-08-25T14:31:09.412-03:00",
          "created_at": "2026-07-02T09:12:44.001-03:00",
          "updated_at": "2026-08-25T14:31:09.412-03:00"
        }
      },
      "Flow": {
        "type": "object",
        "required": [
          "uuid",
          "name",
          "status",
          "supported_providers"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active"
            ]
          },
          "supported_providers": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "example": {
          "uuid": "5a2d8e17-4c93-4f60-8b21-7e3a9c0d6f45",
          "name": "Rastreio de pedido",
          "status": "active",
          "supported_providers": [
            "whatsapp"
          ],
          "created_at": "2026-06-18T11:03:20.114-03:00",
          "updated_at": "2026-08-20T16:45:02.900-03:00"
        }
      },
      "Template": {
        "type": "object",
        "required": [
          "uuid",
          "name",
          "language",
          "status",
          "category",
          "variables"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Use this as content.name when sending."
          },
          "language": {
            "type": "string",
            "description": "Approved language/locale code, e.g. pt_BR."
          },
          "status": {
            "type": "string",
            "enum": [
              "APPROVED",
              "PENDING",
              "REJECTED",
              "PAUSED",
              "DISABLED",
              "IN_APPEAL",
              "DRAFT"
            ]
          },
          "category": {
            "type": "string",
            "enum": [
              "AUTHENTICATION",
              "MARKETING",
              "UTILITY"
            ]
          },
          "channel_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "variables": {
            "type": "object",
            "required": [
              "body_parameter_count",
              "body_named_parameters",
              "has_dynamic_buttons"
            ],
            "description": "Describes the variables the template expects. When sending, content.parameters must have exactly body_parameter_count string entries, in order of the {{1}}..{{n}} placeholders in the body. Templates with a media/variable header (header.has_variable) or dynamic URL buttons (has_dynamic_buttons) are not yet fully supported by POST /messages.",
            "properties": {
              "body_parameter_count": {
                "type": "integer",
                "description": "Number of positional {{n}} placeholders in the body."
              },
              "body_named_parameters": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Named placeholders ({{name}}) found in the body, if any."
              },
              "header": {
                "oneOf": [
                  {
                    "type": "object",
                    "required": [
                      "format",
                      "has_variable"
                    ],
                    "properties": {
                      "format": {
                        "type": "string",
                        "enum": [
                          "TEXT",
                          "IMAGE",
                          "VIDEO",
                          "DOCUMENT",
                          "LOCATION"
                        ]
                      },
                      "has_variable": {
                        "type": "boolean"
                      }
                    }
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "has_dynamic_buttons": {
                "type": "boolean"
              }
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "example": {
          "uuid": "c81f2d64-9a0e-42b7-8e35-1f7d4b2c6a90",
          "name": "order_confirmed",
          "language": "pt_BR",
          "status": "APPROVED",
          "category": "UTILITY",
          "channel_uuid": "123e4567-e89b-12d3-a456-426614174000",
          "variables": {
            "body_parameter_count": 2,
            "body_named_parameters": [],
            "header": {
              "format": "TEXT",
              "has_variable": false
            },
            "has_dynamic_buttons": false
          },
          "created_at": "2026-07-10T10:00:00.000-03:00",
          "updated_at": "2026-08-01T08:30:00.000-03:00"
        }
      },
      "Conversation": {
        "type": "object",
        "required": [
          "uuid",
          "status",
          "channel_uuid",
          "unread_count"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string"
          },
          "channel_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "contact": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Contact"
              },
              {
                "type": "null"
              }
            ]
          },
          "unread_count": {
            "type": "integer"
          },
          "last_message_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "example": {
          "uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
          "status": "open",
          "channel_uuid": "123e4567-e89b-12d3-a456-426614174000",
          "unread_count": 2,
          "last_message_at": "2026-08-25T14:31:09.412-03:00",
          "created_at": "2026-08-25T14:20:00.000-03:00",
          "updated_at": "2026-08-25T14:31:09.412-03:00"
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "uuid",
          "direction",
          "type",
          "status",
          "content"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ]
          },
          "type": {
            "type": "string",
            "description": "Message kind (`text`, `image`, `template`, ...). `note` is an internal note written by the team in the inbox: it is never sent to the contact and never triggers a webhook. Filter it out before showing a conversation to the end customer. `system_notice` is a notice recorded by Wazapi in the conversation (for example, the contact edited a WhatsApp message but WhatsApp did not send the new text): it is not a message from either party and has no `content` beyond `kind`."
          },
          "status": {
            "type": "string",
            "description": "Delivery status. `note` marks internal records that never reach the provider — team notes (`type: note`) and store order cards (`type: store_order`)."
          },
          "content": {
            "type": "object",
            "additionalProperties": true
          },
          "provider_message_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "transcript": {
            "type": [
              "string",
              "null"
            ],
            "description": "Transcription of an inbound audio message, when available. Populated asynchronously after the audio is transcribed; also delivered via the `message.transcribed` webhook. `null` for non-audio messages and audios not yet transcribed."
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the message was deleted by the contact or from the WhatsApp Business app. `content` is then empty apart from `deleted`. Also delivered via the `message.deleted` webhook."
          },
          "deleted_by": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "contact",
              "business_app",
              null
            ],
            "description": "Who deleted the message. `null` when not deleted."
          },
          "edited_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the text or caption was last edited. `content` holds the current value. Also delivered via the `message.updated` webhook."
          }
        },
        "example": {
          "uuid": "0f6f7a4e-3b1d-4a9c-9f2b-6d1f0c4a51e7",
          "direction": "inbound",
          "type": "text",
          "status": "received",
          "content": {
            "text": "Quero rastrear meu pedido"
          },
          "provider_message_id": "wamid.HBgNNTUxMTk5OTk5ODg4OBUCABIYFDNBM0Y5",
          "created_at": "2026-08-25T14:31:09.412-03:00",
          "updated_at": "2026-08-25T14:31:09.412-03:00",
          "transcript": null
        }
      },
      "Operation": {
        "type": "object",
        "required": [
          "uuid",
          "type",
          "status",
          "result",
          "error"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "message.send",
              "flow.execute"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "waiting",
              "succeeded",
              "failed"
            ]
          },
          "result": {
            "type": [
              "object",
              "null"
            ],
            "description": "Set when the operation succeeds. For `message.send`: `message_uuid`, `conversation_uuid`, `contact_uuid`, `status` and, since 1.3, `text` — the message as delivered (template body already interpolated), or `null` when the message has no text body.",
            "additionalProperties": true
          },
          "error": {
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "code",
                  "message"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Human-readable explanation, always in English since API 1.7. Branch on `code`, never on this text."
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "example": {
          "uuid": "7d3a1c05-2f88-4b6e-9a10-5c7e2b4d8f31",
          "type": "message.send",
          "status": "succeeded",
          "result": {
            "message_uuid": "0f6f7a4e-3b1d-4a9c-9f2b-6d1f0c4a51e7",
            "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
            "contact_uuid": "9c2e4f31-7a55-4d0b-8f6a-2c9d1e5b7a03",
            "status": "sent",
            "text": "Olá, Igor! A aula foi adiada."
          },
          "error": null
        }
      },
      "WebhookEventType": {
        "type": "string",
        "enum": [
          "message.received",
          "message.status.updated",
          "message.transcribed",
          "message.updated",
          "message.deleted",
          "conversation.created",
          "conversation.updated",
          "flow.execution.updated",
          "webhook.test",
          "order.created"
        ]
      },
      "WebhookEvent": {
        "description": "Envelope delivered to the integration webhook. `type` discriminates the shape of `data`.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/MessageReceivedEvent"
          },
          {
            "$ref": "#/components/schemas/MessageStatusUpdatedEvent"
          },
          {
            "$ref": "#/components/schemas/MessageTranscribedEvent"
          },
          {
            "$ref": "#/components/schemas/MessageUpdatedEvent"
          },
          {
            "$ref": "#/components/schemas/MessageDeletedEvent"
          },
          {
            "$ref": "#/components/schemas/ConversationCreatedEvent"
          },
          {
            "$ref": "#/components/schemas/ConversationUpdatedEvent"
          },
          {
            "$ref": "#/components/schemas/FlowExecutionUpdatedEvent"
          },
          {
            "$ref": "#/components/schemas/WebhookTestEvent"
          },
          {
            "$ref": "#/components/schemas/OrderCreatedEvent"
          }
        ],
        "discriminator": {
          "propertyName": "type",
          "mapping": {
            "message.received": "#/components/schemas/MessageReceivedEvent",
            "message.status.updated": "#/components/schemas/MessageStatusUpdatedEvent",
            "message.transcribed": "#/components/schemas/MessageTranscribedEvent",
            "message.updated": "#/components/schemas/MessageUpdatedEvent",
            "message.deleted": "#/components/schemas/MessageDeletedEvent",
            "conversation.created": "#/components/schemas/ConversationCreatedEvent",
            "conversation.updated": "#/components/schemas/ConversationUpdatedEvent",
            "flow.execution.updated": "#/components/schemas/FlowExecutionUpdatedEvent",
            "webhook.test": "#/components/schemas/WebhookTestEvent",
            "order.created": "#/components/schemas/OrderCreatedEvent"
          }
        }
      },
      "Recipient": {
        "type": "object",
        "required": [
          "phone"
        ],
        "properties": {
          "phone": {
            "type": "string",
            "examples": [
              "+5511999999999"
            ]
          },
          "external_id": {
            "type": "string",
            "maxLength": 128
          }
        },
        "example": {
          "phone": "+5511999998888",
          "external_id": "customer-1847"
        }
      },
      "ContactWrite": {
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 220
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 50
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": true,
            "description": "Arbitrary key/value data merged into the contact (shallow merge: keys are added or overwritten, never removed). Tracking convention: send marketing attribution under utm_* keys (utm_source, utm_medium, utm_campaign, utm_term, utm_content) and click IDs (gclid, gbraid, wbraid, fbclid, msclkid, ttclid). These keys are readable inside flows as {{contact.field.<key>}} and are forwarded to outbound webhooks as data.tracking."
          }
        },
        "example": {
          "name": "Maria Silva",
          "email": "maria@exemplo.com.br",
          "tags": [
            "cliente"
          ],
          "custom_fields": {
            "tier": "gold"
          }
        }
      },
      "MessageRequest": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "recipient",
              "type",
              "content"
            ],
            "properties": {
              "channel_uuid": {
                "type": "string",
                "format": "uuid",
                "description": "Optional when the company has a single WhatsApp channel (or a single connected one): the API resolves it. With several channels it is required and its absence answers `422 channel_required`. Discover values with `GET /channels`."
              },
              "recipient": {
                "$ref": "#/components/schemas/Recipient"
              },
              "type": {
                "const": "text"
              },
              "content": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4096
                  }
                }
              }
            }
          },
          {
            "type": "object",
            "required": [
              "recipient",
              "type",
              "content"
            ],
            "properties": {
              "channel_uuid": {
                "type": "string",
                "format": "uuid",
                "description": "Optional when the company has a single WhatsApp channel (or a single connected one): the API resolves it. With several channels it is required and its absence answers `422 channel_required`. Discover values with `GET /channels`."
              },
              "recipient": {
                "$ref": "#/components/schemas/Recipient"
              },
              "type": {
                "const": "template"
              },
              "content": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Name of an APPROVED template. Discover it via GET /templates."
                  },
                  "language": {
                    "type": "string",
                    "description": "Optional. When provided, an APPROVED template must exist in exactly this language, otherwise the request is rejected with template_language_unavailable. When omitted, pt_BR is preferred, then the most recent approved language."
                  },
                  "parameters": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Positional values for the body {{1}}..{{n}} placeholders, in order. The array length must equal variables.body_parameter_count from GET /templates; a mismatch is rejected synchronously with template_parameter_count_mismatch."
                  }
                }
              }
            }
          }
        ]
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "request_id"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable, machine-readable error code. Branch on this, never on `message`."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation, always in English since API 1.7 (it no longer follows Accept-Language or the company language). Wording may change without a version bump."
              },
              "details": {},
              "request_id": {
                "type": "string"
              }
            }
          }
        },
        "example": {
          "error": {
            "code": "insufficient_scope",
            "message": "The token requires the messages:write scope.",
            "request_id": "01J9Z2K7Q4X8M3N5P6R7S8T9V0"
          }
        }
      },
      "WebhookTracking": {
        "type": "object",
        "additionalProperties": true,
        "description": "Allowlisted attribution subset of the contact's and conversation's custom_fields (utm_* keys, click IDs such as gclid/gbraid/wbraid/fbclid/msclkid/ttclid/ctwa_clid, and ad referral fields ad_*/referral_*). Conversation values win over contact values (last touch over first touch). Present only when at least one field was captured; other custom field keys are never forwarded.",
        "example": {
          "utm_source": "google",
          "utm_medium": "cpc",
          "utm_campaign": "black-friday",
          "gclid": "Cj0KCQjw_pKzBhDMARIsAML..."
        }
      },
      "MessageReceivedData": {
        "type": "object",
        "required": [
          "message_uuid",
          "conversation_uuid",
          "contact_uuid",
          "channel_uuid",
          "type",
          "content",
          "status"
        ],
        "properties": {
          "message_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "conversation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "contact_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "channel_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "description": "Message type as received from the provider (text, image, audio, document, interactive, ...)."
          },
          "content": {
            "type": "object",
            "additionalProperties": true,
            "description": "Provider payload for the message. For text messages it carries `text`."
          },
          "status": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "description": "Your own identifier for the contact, echoed back when it was linked through PUT /contacts/external/{external_id}. Absent when the contact has no link for this integration."
          },
          "tracking": {
            "$ref": "#/components/schemas/WebhookTracking"
          }
        },
        "example": {
          "message_uuid": "0f6f7a4e-3b1d-4a9c-9f2b-6d1f0c4a51e7",
          "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
          "contact_uuid": "9c2e4f31-7a55-4d0b-8f6a-2c9d1e5b7a03",
          "channel_uuid": "123e4567-e89b-12d3-a456-426614174000",
          "type": "text",
          "content": {
            "text": "Quero rastrear meu pedido"
          },
          "status": "received",
          "external_id": "customer-1847",
          "tracking": {
            "utm_source": "google",
            "utm_medium": "cpc",
            "gclid": "Cj0KCQ..."
          }
        }
      },
      "MessageStatusUpdatedData": {
        "type": "object",
        "required": [
          "message_uuid",
          "status"
        ],
        "description": "Emitted both for provider status callbacks on any outbound message and for messages sent through POST /messages. `provider_message_id` is present on the provider callback; `operation_uuid` and `conversation_uuid` are present when the message originated from the public API. `error` is present only when `status` is `failed`: the provider's reason (e.g. Meta 131042 when the WhatsApp Business Account has no payment method), or null when the provider gave none.",
        "properties": {
          "message_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "description": "Provider delivery status (sent, delivered, read, failed)."
          },
          "provider_message_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "operation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "conversation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "error": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MessageDeliveryError"
              },
              {
                "type": "null"
              }
            ],
            "description": "Provider failure reason. Only present when `status` is `failed`."
          },
          "tracking": {
            "$ref": "#/components/schemas/WebhookTracking"
          }
        },
        "example": {
          "message_uuid": "0f6f7a4e-3b1d-4a9c-9f2b-6d1f0c4a51e7",
          "status": "failed",
          "provider_message_id": "wamid.HBgN...",
          "error": {
            "code": 131042,
            "title": "Business eligibility payment issue",
            "message": "Business eligibility payment issue",
            "details": "Message failed to send because no payment method is set up for your WhatsApp Business account."
          }
        }
      },
      "MessageTranscribedEvent": {
        "type": "object",
        "title": "message.transcribed",
        "description": "An inbound audio message was transcribed (company with an OpenAI key connected and transcription enabled).",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "message.transcribed"
          },
          "data": {
            "$ref": "#/components/schemas/MessageTranscribedData"
          }
        }
      },
      "MessageTranscribedData": {
        "type": "object",
        "required": [
          "message_uuid",
          "conversation_uuid",
          "transcript"
        ],
        "properties": {
          "message_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "conversation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "transcript": {
            "type": "string"
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "Language detected by the transcription model, when reported."
          },
          "tracking": {
            "$ref": "#/components/schemas/WebhookTracking"
          }
        },
        "example": {
          "message_uuid": "0f6f7a4e-3b1d-4a9c-9f2b-6d1f0c4a51e7",
          "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
          "transcript": "Oi, queria saber o prazo de entrega",
          "language": "pt"
        }
      },
      "MessageUpdatedEvent": {
        "type": "object",
        "title": "message.updated",
        "description": "A message was edited after it was sent: by the contact, or by the business from the WhatsApp Business app (coexistence). Opt-in: only endpoints that select this event receive it.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "message.updated"
          },
          "data": {
            "$ref": "#/components/schemas/MessageUpdatedData"
          }
        }
      },
      "MessageUpdatedData": {
        "type": "object",
        "required": [
          "message_uuid",
          "conversation_uuid",
          "channel_uuid",
          "direction",
          "type",
          "edited_at"
        ],
        "description": "Carries only the edited field with its new value - `text` for text messages, `caption` for media. The previous value is not sent; it was delivered in `message.received`. Sources today: WhatsApp `edit` (coexistence numbers) and Messenger `message_edits`. Instagram does not report edits.",
        "properties": {
          "message_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "conversation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "contact_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "channel_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "description": "`outbound` when the business edited or deleted from the WhatsApp Business app on the phone (coexistence numbers)."
          },
          "type": {
            "type": "string",
            "description": "Original message type (`text`, `image`, ...). Kept after deletion."
          },
          "text": {
            "type": "string",
            "description": "New text. Present when the text body was edited."
          },
          "caption": {
            "type": "string",
            "description": "New caption. Present when a media caption was edited."
          },
          "edited_at": {
            "type": "string",
            "format": "date-time"
          },
          "tracking": {
            "$ref": "#/components/schemas/WebhookTracking"
          }
        },
        "example": {
          "message_uuid": "0f6f7a4e-3b1d-4a9c-9f2b-6d1f0c4a51e7",
          "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
          "contact_uuid": "9c2e4f31-7a55-4d0b-8f6a-2c9d1e5b7a03",
          "channel_uuid": "123e4567-e89b-12d3-a456-426614174000",
          "direction": "inbound",
          "type": "text",
          "text": "Na verdade, quero trocar o tamanho",
          "edited_at": "2026-09-16T18:04:11.000-03:00"
        }
      },
      "MessageDeletedEvent": {
        "type": "object",
        "title": "message.deleted",
        "description": "A message was deleted after it was sent: by the contact, or by the business from the WhatsApp Business app (coexistence). Wazapi removes the content, including stored media. Opt-in: only endpoints that select this event receive it.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "message.deleted"
          },
          "data": {
            "$ref": "#/components/schemas/MessageDeletedData"
          }
        }
      },
      "MessageDeletedData": {
        "type": "object",
        "required": [
          "message_uuid",
          "conversation_uuid",
          "channel_uuid",
          "direction",
          "type",
          "deleted_at",
          "deleted_by"
        ],
        "description": "Never carries content. An Instagram message with several attachments is stored as one message per attachment, so deleting it emits one event per `message_uuid`. Sources today: WhatsApp `revoke` (coexistence numbers) and Instagram `is_deleted`. Messenger does not report deletions.",
        "properties": {
          "message_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "conversation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "contact_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "channel_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "description": "`outbound` when the business edited or deleted from the WhatsApp Business app on the phone (coexistence numbers)."
          },
          "type": {
            "type": "string",
            "description": "Original message type (`text`, `image`, ...). Kept after deletion."
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time"
          },
          "deleted_by": {
            "type": "string",
            "enum": [
              "contact",
              "business_app"
            ],
            "description": "`business_app` = deleted from the WhatsApp Business app on the business phone."
          },
          "tracking": {
            "$ref": "#/components/schemas/WebhookTracking"
          }
        },
        "example": {
          "message_uuid": "0f6f7a4e-3b1d-4a9c-9f2b-6d1f0c4a51e7",
          "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
          "contact_uuid": "9c2e4f31-7a55-4d0b-8f6a-2c9d1e5b7a03",
          "channel_uuid": "123e4567-e89b-12d3-a456-426614174000",
          "direction": "inbound",
          "type": "image",
          "deleted_at": "2026-09-16T18:06:40.000-03:00",
          "deleted_by": "contact"
        }
      },
      "MessageDeliveryError": {
        "type": "object",
        "description": "Delivery failure as reported by the messaging provider (Meta error codes for WhatsApp). Every field can be null when the provider omits it.",
        "required": [
          "code",
          "title",
          "message",
          "details"
        ],
        "properties": {
          "code": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Provider error code (Meta: 131042 payment issue, 131050 recipient opted out, 131047 re-engagement required, 131026 undeliverable...)."
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "details": {
            "type": [
              "string",
              "null"
            ],
            "description": "Long-form explanation from the provider, when any."
          }
        }
      },
      "ConversationCreatedData": {
        "type": "object",
        "required": [
          "conversation_uuid",
          "contact_uuid",
          "channel_uuid",
          "status"
        ],
        "properties": {
          "conversation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "contact_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "channel_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string"
          },
          "external_id": {
            "type": "string",
            "description": "Your own identifier for the contact, echoed back when it was linked through PUT /contacts/external/{external_id}. Absent when the contact has no link for this integration."
          },
          "tracking": {
            "$ref": "#/components/schemas/WebhookTracking"
          }
        },
        "example": {
          "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
          "contact_uuid": "9c2e4f31-7a55-4d0b-8f6a-2c9d1e5b7a03",
          "channel_uuid": "123e4567-e89b-12d3-a456-426614174000",
          "status": "open"
        }
      },
      "ConversationUpdatedData": {
        "type": "object",
        "required": [
          "conversation_uuid",
          "contact_uuid",
          "channel_uuid",
          "status"
        ],
        "description": "`unread_count` is present when the update was triggered by an inbound message; `last_message_at` is present on both the inbound and the API-send paths.",
        "properties": {
          "conversation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "contact_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "channel_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string"
          },
          "unread_count": {
            "type": "integer"
          },
          "last_message_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "external_id": {
            "type": "string",
            "description": "Your own identifier for the contact, echoed back when it was linked through PUT /contacts/external/{external_id}. Absent when the contact has no link for this integration."
          },
          "tracking": {
            "$ref": "#/components/schemas/WebhookTracking"
          }
        },
        "example": {
          "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22",
          "contact_uuid": "9c2e4f31-7a55-4d0b-8f6a-2c9d1e5b7a03",
          "channel_uuid": "123e4567-e89b-12d3-a456-426614174000",
          "status": "open",
          "unread_count": 2,
          "last_message_at": "2026-08-25T14:31:09.412-03:00"
        }
      },
      "FlowExecutionUpdatedData": {
        "type": "object",
        "required": [
          "operation_uuid",
          "operation_type",
          "status",
          "result",
          "error"
        ],
        "properties": {
          "operation_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "operation_type": {
            "type": "string",
            "enum": [
              "flow.execute"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "waiting",
              "succeeded",
              "failed"
            ]
          },
          "result": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Carries `flow_status` (`completed`, `superseded`, ...) plus the identifiers resolved for the run."
          },
          "error": {
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "code",
                  "message"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "message": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Human-readable explanation, always in English since API 1.7. Branch on `code`, never on this text."
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "example": {
          "operation_uuid": "7d3a1c05-2f88-4b6e-9a10-5c7e2b4d8f31",
          "operation_type": "flow.execute",
          "status": "succeeded",
          "result": {
            "flow_status": "completed",
            "conversation_uuid": "2b7c1a90-95f3-4a1e-bb0e-1d4b6f0f9c22"
          },
          "error": null
        }
      },
      "WebhookTestData": {
        "type": "object",
        "required": [
          "integration_uuid",
          "message"
        ],
        "description": "Sent by the Send test button in Settings -> Wazapi API. Always delivered, regardless of which events the endpoint subscribes to.",
        "properties": {
          "integration_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "message": {
            "type": "string"
          }
        },
        "example": {
          "integration_uuid": "4f1c9b22-8d70-4e33-9c51-0a7b3e6d2f14",
          "message": "Wazapi webhook test"
        }
      },
      "MessageReceivedEvent": {
        "type": "object",
        "title": "message.received",
        "description": "An inbound message arrived on a WhatsApp channel.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "message.received"
          },
          "data": {
            "$ref": "#/components/schemas/MessageReceivedData"
          }
        }
      },
      "MessageStatusUpdatedEvent": {
        "type": "object",
        "title": "message.status.updated",
        "description": "The delivery status of an outbound message changed.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "message.status.updated"
          },
          "data": {
            "$ref": "#/components/schemas/MessageStatusUpdatedData"
          }
        }
      },
      "ConversationCreatedEvent": {
        "type": "object",
        "title": "conversation.created",
        "description": "A new conversation was opened.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "conversation.created"
          },
          "data": {
            "$ref": "#/components/schemas/ConversationCreatedData"
          }
        }
      },
      "ConversationUpdatedEvent": {
        "type": "object",
        "title": "conversation.updated",
        "description": "An existing conversation changed.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "conversation.updated"
          },
          "data": {
            "$ref": "#/components/schemas/ConversationUpdatedData"
          }
        }
      },
      "FlowExecutionUpdatedEvent": {
        "type": "object",
        "title": "flow.execution.updated",
        "description": "A flow execution started through POST /flows/{uuid}/executions reached a new state.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "flow.execution.updated"
          },
          "data": {
            "$ref": "#/components/schemas/FlowExecutionUpdatedData"
          }
        }
      },
      "WebhookTestEvent": {
        "type": "object",
        "title": "webhook.test",
        "description": "Test event triggered from the dashboard.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "webhook.test"
          },
          "data": {
            "$ref": "#/components/schemas/WebhookTestData"
          }
        }
      },
      "ConversationDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Conversation"
          },
          {
            "type": "object",
            "properties": {
              "channel_provider": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Provider of the channel (e.g. whatsapp)."
              },
              "assigned_agent": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "uuid": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              },
              "assigned_group": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "uuid": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              },
              "message_count": {
                "type": "integer",
                "description": "Every message stored in the conversation, including internal notes (`type: note`) and store order cards (`type: store_order`)."
              },
              "messages": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Message"
                },
                "description": "Present only when `include=messages` is passed: the first page of messages (ascending). Use `GET /conversations/{uuid}/messages` with `meta.messages_next_cursor` to continue."
              }
            }
          }
        ]
      },
      "StoreProductVariant": {
        "type": "object",
        "required": [
          "uuid",
          "label"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "label": {
            "type": "string"
          },
          "price_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "stock": {
            "type": [
              "integer",
              "null"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "position": {
            "type": "integer"
          }
        }
      },
      "StoreProduct": {
        "type": "object",
        "required": [
          "uuid",
          "name",
          "price_cents",
          "active"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "category_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "price_cents": {
            "type": "integer"
          },
          "promo_price_cents": {
            "type": [
              "integer",
              "null"
            ]
          },
          "effective_price_cents": {
            "type": "integer"
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "highlighted": {
            "type": "boolean"
          },
          "track_stock": {
            "type": "boolean"
          },
          "stock": {
            "type": [
              "integer",
              "null"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "position": {
            "type": "integer"
          },
          "import_handle": {
            "type": [
              "string",
              "null"
            ],
            "description": "External catalog handle (e.g. Shopify Handle). Products sharing the same handle are updated on re-import instead of duplicated."
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StoreProductVariant"
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "StoreProductWrite": {
        "type": "object",
        "required": [
          "name",
          "price_cents"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 140
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "category_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "price_cents": {
            "type": "integer",
            "minimum": 0
          },
          "promo_price_cents": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Must be greater than zero and lower than `price_cents`, otherwise `422 promo_price_invalid`."
          },
          "highlighted": {
            "type": "boolean"
          },
          "track_stock": {
            "type": "boolean"
          },
          "stock": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "active": {
            "type": "boolean"
          },
          "position": {
            "type": "integer",
            "minimum": 0
          },
          "import_handle": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255
          },
          "variants": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "required": [
                "label"
              ],
              "properties": {
                "uuid": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "uuid",
                  "description": "On update, keeps the existing variant; omitted variants are deleted."
                },
                "label": {
                  "type": "string",
                  "maxLength": 80
                },
                "price_cents": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 0
                },
                "stock": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 0
                },
                "active": {
                  "type": "boolean"
                }
              }
            }
          },
          "image_urls": {
            "type": "array",
            "maxItems": 4,
            "items": {
              "type": "string",
              "format": "uri",
              "maxLength": 2048
            },
            "description": "Public http(s) URLs of JPEG, PNG or WebP images up to 5 MB each. Wazapi downloads and re-hosts them; the first one is the cover. Omit to keep the current images, send `[]` to remove them all. Private, loopback and link-local addresses are refused, redirects included. On the batch endpoint the download runs in the background."
          }
        }
      },
      "StoreOrderItem": {
        "type": "object",
        "properties": {
          "product_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "variant_label": {
            "type": [
              "string",
              "null"
            ]
          },
          "quantity": {
            "type": "integer"
          },
          "unit_price_cents": {
            "type": "integer"
          },
          "total_cents": {
            "type": "integer"
          }
        }
      },
      "StoreOrder": {
        "type": "object",
        "required": [
          "uuid",
          "ref",
          "status",
          "customer_name",
          "customer_phone",
          "items",
          "total_cents",
          "payment_method"
        ],
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "ref": {
            "type": "string",
            "description": "Short human reference (first 8 chars of the uuid) shown to the customer."
          },
          "status": {
            "type": "string",
            "enum": [
              "novo",
              "confirmado",
              "pago",
              "entregue",
              "cancelado"
            ]
          },
          "customer_name": {
            "type": "string"
          },
          "customer_phone": {
            "type": "string"
          },
          "contact_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "conversation_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Inbox conversation opened by the order automation, when available."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StoreOrderItem"
            }
          },
          "subtotal_cents": {
            "type": "integer"
          },
          "shipping_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "shipping_cents": {
            "type": "integer"
          },
          "total_cents": {
            "type": "integer"
          },
          "payment_method": {
            "type": "string",
            "enum": [
              "pix",
              "link",
              "on_delivery",
              "catalog"
            ]
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "source": {
            "type": "string",
            "enum": [
              "storefront",
              "whatsapp_catalog"
            ],
            "description": "Where the order was placed: the public storefront checkout, or the native WhatsApp catalog (inbound order webhook)."
          },
          "provider_order_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Provider-side id for orders that originated outside the storefront (WhatsApp catalog order message id)."
          },
          "tracking": {
            "type": [
              "object",
              "null"
            ],
            "description": "Allowlisted attribution subset stamped on the order at creation (utm_*, click IDs incl. ctwa_clid, ad_*/referral_*). Conversation values win over contact values (last touch over first touch). Null when the order has no attributable source.",
            "additionalProperties": true
          }
        }
      },
      "StoreSummary": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "mode": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "links_only",
              "store_only",
              "both",
              null
            ]
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Absolute public storefront URL."
          },
          "product_count": {
            "type": "integer"
          },
          "order_count": {
            "type": "integer"
          }
        }
      },
      "StoreProductBatchResult": {
        "type": "object",
        "required": [
          "data",
          "meta"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "index",
                "status"
              ],
              "properties": {
                "index": {
                  "type": "integer"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "created",
                    "updated",
                    "error"
                  ]
                },
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable explanation, always in English since API 1.7. Branch on `code`, never on this text."
                    }
                  }
                },
                "images": {
                  "type": "string",
                  "enum": [
                    "queued",
                    "not_queued"
                  ],
                  "description": "Present when the item carried `image_urls`. `queued`: the images are downloaded in the background and show up on the product shortly; an image that cannot be downloaded is skipped. `not_queued`: the product was saved but the download could not be scheduled — resend the item."
                }
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "created": {
                "type": "integer"
              },
              "updated": {
                "type": "integer"
              },
              "failed": {
                "type": "integer"
              }
            }
          }
        }
      },
      "OrderCreatedData": {
        "type": "object",
        "description": "A store order was created (storefront checkout). Includes the order snapshot; `data.tracking` (allowlisted UTM/click-id attribution) is injected at delivery time like on other events.",
        "required": [
          "order_uuid",
          "status",
          "items",
          "total_cents"
        ],
        "properties": {
          "order_uuid": {
            "type": "string",
            "format": "uuid"
          },
          "ref": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "customer_name": {
            "type": "string"
          },
          "customer_phone": {
            "type": "string"
          },
          "contact_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StoreOrderItem"
            }
          },
          "subtotal_cents": {
            "type": "integer"
          },
          "shipping_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "shipping_cents": {
            "type": "integer"
          },
          "total_cents": {
            "type": "integer"
          },
          "payment_method": {
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "source": {
            "type": "string",
            "enum": [
              "storefront",
              "whatsapp_catalog"
            ]
          },
          "tracking": {
            "type": [
              "object",
              "null"
            ],
            "description": "Allowlisted attribution subset stamped on the order at creation (utm_*, click IDs incl. ctwa_clid, ad_*/referral_*). Conversation values win over contact values (last touch over first touch). Null when the order has no attributable source.",
            "additionalProperties": true
          }
        }
      },
      "OrderCreatedEvent": {
        "type": "object",
        "title": "order.created",
        "description": "A store order was created via the storefront checkout.",
        "required": [
          "id",
          "type",
          "api_version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique event id. Delivery is at-least-once - deduplicate on this value."
          },
          "api_version": {
            "type": "string",
            "const": "v1"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "const": "order.created"
          },
          "data": {
            "$ref": "#/components/schemas/OrderCreatedData"
          }
        }
      },
      "StoreProductPatch": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 140
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 2000
          },
          "category_uuid": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "price_cents": {
            "type": "integer",
            "minimum": 0
          },
          "promo_price_cents": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Must be greater than zero and lower than `price_cents`, otherwise `422 promo_price_invalid`."
          },
          "highlighted": {
            "type": "boolean"
          },
          "track_stock": {
            "type": "boolean"
          },
          "stock": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "active": {
            "type": "boolean"
          },
          "position": {
            "type": "integer",
            "minimum": 0
          },
          "import_handle": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255
          },
          "variants": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "required": [
                "label"
              ],
              "properties": {
                "uuid": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "uuid",
                  "description": "On update, keeps the existing variant; omitted variants are deleted."
                },
                "label": {
                  "type": "string",
                  "maxLength": 80
                },
                "price_cents": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 0
                },
                "stock": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 0
                },
                "active": {
                  "type": "boolean"
                }
              }
            },
            "description": "When present, replaces the variant list: variants whose `uuid` is sent are kept/updated, new ones are created, the rest are deleted. Omit to leave variants untouched."
          },
          "image_urls": {
            "type": "array",
            "maxItems": 4,
            "items": {
              "type": "string",
              "format": "uri",
              "maxLength": 2048
            },
            "description": "Public http(s) URLs of JPEG, PNG or WebP images up to 5 MB each. Wazapi downloads and re-hosts them; the first one is the cover. Omit to keep the current images, send `[]` to remove them all. Private, loopback and link-local addresses are refused, redirects included. On the batch endpoint the download runs in the background."
          }
        },
        "description": "Partial update: an omitted field keeps its current value, `null` clears a nullable one."
      },
      "StoreCategory": {
        "type": "object",
        "properties": {
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "position": {
            "type": "integer"
          }
        }
      }
    },
    "responses": {
      "ChannelList": {
        "description": "WhatsApp channels available to the integration",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Channel"
                  }
                }
              }
            }
          }
        }
      },
      "ContactList": {
        "description": "Paginated contacts",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "meta"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Contact"
                  }
                },
                "meta": {
                  "$ref": "#/components/schemas/PaginationMeta"
                }
              }
            }
          }
        }
      },
      "Contact": {
        "description": "Contact response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          }
        }
      },
      "FlowList": {
        "description": "Paginated flows",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "meta"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Flow"
                  }
                },
                "meta": {
                  "$ref": "#/components/schemas/PaginationMeta"
                }
              }
            }
          }
        }
      },
      "Flow": {
        "description": "Flow response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Flow"
                }
              }
            }
          }
        }
      },
      "TemplateList": {
        "description": "Paginated templates",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "meta"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Template"
                  }
                },
                "meta": {
                  "$ref": "#/components/schemas/PaginationMeta"
                }
              }
            }
          }
        }
      },
      "Template": {
        "description": "Template response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          }
        }
      },
      "ConversationList": {
        "description": "Paginated conversations",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "meta"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Conversation"
                  }
                },
                "meta": {
                  "$ref": "#/components/schemas/PaginationMeta"
                }
              }
            }
          }
        }
      },
      "Conversation": {
        "description": "Conversation response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Conversation"
                }
              }
            }
          }
        }
      },
      "MessageList": {
        "description": "Paginated messages",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data",
                "meta"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Message"
                  }
                },
                "meta": {
                  "$ref": "#/components/schemas/PaginationMeta"
                }
              }
            }
          }
        }
      },
      "Operation": {
        "description": "Asynchronous operation",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            }
          }
        }
      },
      "Accepted": {
        "description": "Operation accepted",
        "headers": {
          "Location": {
            "schema": {
              "type": "string"
            }
          },
          "Idempotent-Replayed": {
            "description": "Present and true when this is a replay of a previously accepted request.",
            "schema": {
              "type": "string",
              "const": "true"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/Operation"
                }
              }
            }
          }
        }
      },
      "Error": {
        "description": "Error response",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ConversationDetail": {
        "description": "Conversation detail response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/ConversationDetail"
                },
                "meta": {
                  "type": "object",
                  "properties": {
                    "messages_next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      },
      "StoreProductList": {
        "description": "Store product list",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StoreProduct"
                  }
                },
                "meta": {
                  "$ref": "#/components/schemas/PaginationMeta"
                }
              }
            }
          }
        }
      },
      "StoreProduct": {
        "description": "Store product response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/StoreProduct"
                }
              }
            }
          }
        }
      },
      "StoreOrderList": {
        "description": "Store order list",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StoreOrder"
                  }
                },
                "meta": {
                  "$ref": "#/components/schemas/PaginationMeta"
                }
              }
            }
          }
        }
      },
      "StoreOrder": {
        "description": "Store order response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/StoreOrder"
                }
              }
            }
          }
        }
      },
      "StoreSummary": {
        "description": "Store summary response",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "data"
              ],
              "properties": {
                "data": {
                  "$ref": "#/components/schemas/StoreSummary"
                }
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Channels",
      "description": "Discover the WhatsApp channels the token can send from. Start here: every send needs a `channel_uuid`."
    },
    {
      "name": "Templates",
      "description": "Discover approved templates and the exact variable shape each one expects, before sending."
    },
    {
      "name": "Messages",
      "description": "Send text and template messages, and read a conversation's history. Sends are asynchronous."
    },
    {
      "name": "Contacts",
      "description": "List, read and update contacts, or upsert them by your own system's identifier."
    },
    {
      "name": "Conversations",
      "description": "List and read conversations."
    },
    {
      "name": "Flows",
      "description": "Discover active flows and start an execution for a contact."
    },
    {
      "name": "Operations",
      "description": "Poll the result of an asynchronous send or flow execution."
    },
    {
      "name": "Webhooks",
      "description": "Events Wazapi delivers to the HTTPS endpoint registered for the integration. You implement this endpoint; Wazapi calls it."
    },
    {
      "name": "Store",
      "description": "Read and write the tenant storefront: products (create, partial update, delete, images by URL, batch create/update for catalog migration from Shopify or an ERP), categories and orders. Scopes: store:read / store:write (write includes delete)."
    }
  ],
  "externalDocs": {
    "description": "Guides and reference",
    "url": "https://doc.wazapi.io"
  }
}
