{
  "openapi": "3.1.2",
  "info": {
    "title": "ACE SEND API",
    "version": "1.0.0",
    "description": "The ACE SEND API sends WhatsApp and SMS messages, reports their statuses and keeps contacts in sync.\n\n- Base URL: `https://api.ace-send.com/v1`\n- Authentication: `Authorization: Bearer <API key>` — create keys in the console, *Settings → API and webhooks*.\n  A test key (`ak_test_…`) sends through a free sandbox; a live key (`ak_live_…`) sends for real.\n- Requests and responses are JSON; errors are `application/problem+json` (RFC 9457) with a stable `code`.\n- Limits per key: 50 requests a second to send, 20 to read.\n- Statuses come as signed webhooks (Standard Webhooks), described under `webhooks`.\n\nGuides, examples and the webhook signature check: https://docs.ace-send.com"
  },
  "servers": [
    {
      "url": "https://api.ace-send.com/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "paths": {
    "/fields": {
      "get": {
        "operationId": "fields.index",
        "description": "The custom fields of the account in their order: `key` — the variable {{key}} of templates and the key in the\n`fields` of a contact; `type` — text, number, money (in the account currency) or date; `fallback` — what a\ncontact without a value gets when the text has no fallback (null — none). Keys with the `contacts` permission.",
        "summary": "List the custom fields",
        "tags": [
          "Contacts"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "type": {
                            "type": "string",
                            "enum": [
                              "text",
                              "number",
                              "money",
                              "date"
                            ]
                          },
                          "fallback": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "key",
                          "label",
                          "type",
                          "fallback"
                        ]
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "examples": {
                  "fields": {
                    "summary": "Custom fields",
                    "value": {
                      "data": [
                        {
                          "key": "promo_code",
                          "label": "Promo code",
                          "type": "text",
                          "fallback": "BONUS10"
                        },
                        {
                          "key": "amount",
                          "label": "Deposit amount",
                          "type": "money",
                          "fallback": null
                        },
                        {
                          "key": "last_deposit",
                          "label": "Last deposit",
                          "type": "money",
                          "fallback": null
                        },
                        {
                          "key": "days_idle",
                          "label": "Days idle",
                          "type": "number",
                          "fallback": null
                        },
                        {
                          "key": "vip_since",
                          "label": "VIP since",
                          "type": "date",
                          "fallback": null
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Problem Details (RFC 9457)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "api_key_invalid": {
                    "summary": "401 api_key_invalid",
                    "value": {
                      "type": "about:blank",
                      "status": 401,
                      "code": "api_key_invalid",
                      "title": "The API key is missing, unknown or revoked"
                    }
                  },
                  "api_key_ip_denied": {
                    "summary": "403 api_key_ip_denied",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_ip_denied",
                      "title": "The API key may not be used from this address"
                    }
                  },
                  "account_suspended": {
                    "summary": "403 account_suspended",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "account_suspended",
                      "title": "The account is suspended"
                    }
                  },
                  "api_key_scope": {
                    "summary": "403 api_key_scope",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_scope",
                      "title": "The API key lacks the permission for this request"
                    }
                  },
                  "too_many_requests": {
                    "summary": "429 too_many_requests",
                    "value": {
                      "type": "about:blank",
                      "status": 429,
                      "code": "too_many_requests",
                      "title": "Too many requests. Try again later"
                    }
                  }
                }
              }
            }
          }
        },
        "x-api-key-scope": "contacts",
        "x-rate-limit": "20 requests a second per key"
      }
    },
    "/messages": {
      "get": {
        "operationId": "messages.index",
        "description": "Messages of the account, newest first, 100 a page: pass `next_cursor` as `cursor` for the next page (null on the\nlast one). Filters: `status`, `channel`, `to` (E.164), `reference` (exact), `template` (name; of the `channel`\nwhen given, else of either channel), `from` / `until` (moments of acceptance, `until` exclusive). Without\n`events`. A key sees only the messages of its mode: a test key the test ones (`test` true), a live key the live\nones. Keys with the `status` permission.",
        "summary": "List the messages",
        "tags": [
          "Messages"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "accepted",
                "queued",
                "submitted",
                "sent",
                "delivered",
                "read",
                "rejected",
                "failed",
                "expired",
                "cancelled"
              ]
            },
            "example": "delivered"
          },
          {
            "name": "to",
            "in": "query",
            "description": "The number in E.164; the + may be left out.",
            "schema": {
              "type": "string",
              "pattern": "^\\+?[1-9][0-9]{5,14}$"
            }
          },
          {
            "name": "reference",
            "in": "query",
            "description": "Your reference, exactly.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "whatsapp",
                "sms"
              ]
            }
          },
          {
            "name": "template",
            "in": "query",
            "description": "The name of a template (of the `channel` when given, else of either channel).",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "ISO 8601 moments of acceptance; a value without an offset is read in UTC. `until` is exclusive.",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "until",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "`next_cursor` of the previous page.",
            "schema": {
              "type": "string",
              "maxLength": 64
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PublicMessageResource"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "data",
                    "next_cursor"
                  ]
                },
                "examples": {
                  "page": {
                    "summary": "A page of messages",
                    "value": {
                      "data": [
                        {
                          "id": "msg_CgdWeHQN4sPaZnXfh7kP5",
                          "status": "delivered",
                          "to": "+5521998120937",
                          "from": null,
                          "country": "BR",
                          "channel": "whatsapp",
                          "template": {
                            "name": "welcome_bonus",
                            "version": 3
                          },
                          "language": "pt",
                          "reference": "crm-42",
                          "text": "Olá Ana! Seu bônus BONUS10 já está ativo.",
                          "text_masked": false,
                          "segments": 1,
                          "encoding": null,
                          "price": {
                            "amount": "0.062500",
                            "currency": "USD"
                          },
                          "error": null,
                          "test": false,
                          "campaign": null,
                          "created_at": "2026-11-02T12:00:00+00:00",
                          "updated_at": "2026-11-02T12:00:04+00:00",
                          "events": null
                        },
                        {
                          "id": "msg_CgdWeHQNnp4VN7KkfNqju",
                          "status": "delivered",
                          "to": "+5511912345678",
                          "from": "ACESEND",
                          "country": "BR",
                          "channel": "sms",
                          "template": null,
                          "language": null,
                          "reference": "otp-7781",
                          "text": "Your ACE SEND code is 482913. It expires in 10 minutes.",
                          "text_masked": false,
                          "segments": 1,
                          "encoding": "gsm7",
                          "price": {
                            "amount": "0.018000",
                            "currency": "USD"
                          },
                          "error": null,
                          "test": false,
                          "campaign": null,
                          "created_at": "2026-11-02T12:00:00+00:00",
                          "updated_at": "2026-11-02T11:58:12+00:00",
                          "events": null
                        }
                      ],
                      "next_cursor": "msg_CgdWeHQNnp4VN7KkfNqju"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Problem Details (RFC 9457)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "422 validation_failed",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "validation_failed",
                      "title": "Check the form fields",
                      "errors": [
                        {
                          "field": "variables.promo_code",
                          "code": "required",
                          "message": "Fill in this field"
                        }
                      ]
                    }
                  },
                  "api_key_invalid": {
                    "summary": "401 api_key_invalid",
                    "value": {
                      "type": "about:blank",
                      "status": 401,
                      "code": "api_key_invalid",
                      "title": "The API key is missing, unknown or revoked"
                    }
                  },
                  "api_key_ip_denied": {
                    "summary": "403 api_key_ip_denied",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_ip_denied",
                      "title": "The API key may not be used from this address"
                    }
                  },
                  "account_suspended": {
                    "summary": "403 account_suspended",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "account_suspended",
                      "title": "The account is suspended"
                    }
                  },
                  "api_key_scope": {
                    "summary": "403 api_key_scope",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_scope",
                      "title": "The API key lacks the permission for this request"
                    }
                  },
                  "too_many_requests": {
                    "summary": "429 too_many_requests",
                    "value": {
                      "type": "about:blank",
                      "status": 429,
                      "code": "too_many_requests",
                      "title": "Too many requests. Try again later"
                    }
                  }
                }
              }
            }
          }
        },
        "x-api-key-scope": "status",
        "x-rate-limit": "20 requests a second per key"
      },
      "post": {
        "operationId": "messages.store",
        "description": "Sends a WhatsApp or SMS message with a template of the account to one number. An SMS may carry an own `text` instead, when the account allows it.\n\n`202 Accepted` means the message passed every check, its price is fixed and reserved, and it is queued (`status` is `queued`). Its statuses follow as webhooks and in `GET /messages/{id}`. A refused request creates no message and costs nothing.\n\nSend an `Idempotency-Key` header to retry safely: a repeat with the same key and body within 24 hours answers the first message with the header `Idempotent-Replayed: true`. A test key sends through the sandbox: free, `price` null, `test` true, at most 1000 messages a day.\n\nGuides: https://docs.ace-send.com/guide/sending, https://docs.ace-send.com/guide/sms.",
        "summary": "Send a message",
        "tags": [
          "Messages"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "1–64 printable ASCII characters. A repeat with the same key and body within 24 hours answers the same message; another body — 409 idempotency_conflict.",
            "schema": {
              "type": "string",
              "pattern": "^[!-~]{1,64}$"
            },
            "example": "crm-42-welcome"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessageRequest"
              },
              "examples": {
                "whatsapp": {
                  "summary": "WhatsApp template",
                  "value": {
                    "to": "+5521998120937",
                    "template": "welcome_bonus",
                    "language": "pt",
                    "variables": {
                      "name": "Ana",
                      "promo_code": "BONUS10"
                    },
                    "reference": "crm-42"
                  }
                },
                "sms_template": {
                  "summary": "SMS template",
                  "value": {
                    "channel": "sms",
                    "to": "+5511912345678",
                    "template": "deposit_reminder",
                    "language": "en",
                    "variables": {
                      "name": "Ann",
                      "amount": "$50.00"
                    }
                  }
                },
                "sms_text": {
                  "summary": "SMS with an own text",
                  "value": {
                    "channel": "sms",
                    "to": "+5511912345678",
                    "text": "Your ACE SEND code is 482913. It expires in 10 minutes.",
                    "reference": "otp-7781"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "`PublicMessageResource`",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PublicMessageResource"
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "examples": {
                  "whatsapp": {
                    "summary": "WhatsApp message accepted",
                    "value": {
                      "data": {
                        "id": "msg_CgdWeHQN4sPaZnXfh7kP5",
                        "status": "queued",
                        "to": "+5521998120937",
                        "from": null,
                        "country": "BR",
                        "channel": "whatsapp",
                        "template": {
                          "name": "welcome_bonus",
                          "version": 3
                        },
                        "language": "pt",
                        "reference": "crm-42",
                        "text": "Olá Ana! Seu bônus BONUS10 já está ativo.",
                        "text_masked": false,
                        "segments": 1,
                        "encoding": null,
                        "price": {
                          "amount": "0.062500",
                          "currency": "USD"
                        },
                        "error": null,
                        "test": false,
                        "campaign": null,
                        "created_at": "2026-11-02T12:00:00+00:00",
                        "updated_at": "2026-11-02T12:00:00+00:00",
                        "events": null
                      }
                    }
                  },
                  "sms": {
                    "summary": "SMS accepted",
                    "value": {
                      "data": {
                        "id": "msg_CgdWeHQNnp4VN7KkfNqju",
                        "status": "queued",
                        "to": "+5511912345678",
                        "from": "ACESEND",
                        "country": "BR",
                        "channel": "sms",
                        "template": null,
                        "language": null,
                        "reference": "otp-7781",
                        "text": "Your ACE SEND code is 482913. It expires in 10 minutes.",
                        "text_masked": false,
                        "segments": 1,
                        "encoding": "gsm7",
                        "price": {
                          "amount": "0.018000",
                          "currency": "USD"
                        },
                        "error": null,
                        "test": false,
                        "campaign": null,
                        "created_at": "2026-11-02T12:00:00+00:00",
                        "updated_at": "2026-11-02T12:00:00+00:00",
                        "events": null
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Problem Details (RFC 9457)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "422 validation_failed",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "validation_failed",
                      "title": "Check the form fields",
                      "errors": [
                        {
                          "field": "variables.promo_code",
                          "code": "required",
                          "message": "Fill in this field"
                        }
                      ]
                    }
                  },
                  "invalid_number": {
                    "summary": "422 invalid_number",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "invalid_number",
                      "title": "The recipient's number is not valid"
                    }
                  },
                  "template_not_found": {
                    "summary": "404 template_not_found",
                    "value": {
                      "type": "about:blank",
                      "status": 404,
                      "code": "template_not_found",
                      "title": "Template not found"
                    }
                  },
                  "template_unavailable": {
                    "summary": "409 template_unavailable",
                    "value": {
                      "type": "about:blank",
                      "status": 409,
                      "code": "template_unavailable",
                      "title": "This template cannot be sent right now"
                    }
                  },
                  "free_text_not_allowed": {
                    "summary": "403 free_text_not_allowed",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "free_text_not_allowed",
                      "title": "Own SMS text is not enabled for this account: send a template"
                    }
                  },
                  "message_too_long": {
                    "summary": "422 message_too_long",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "message_too_long",
                      "title": "The SMS text has more segments than allowed",
                      "segments": 7,
                      "max_segments": 6
                    }
                  },
                  "recipient_stopped": {
                    "summary": "422 recipient_stopped",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "recipient_stopped",
                      "title": "The number is in the stop list"
                    }
                  },
                  "destination_unavailable": {
                    "summary": "422 destination_unavailable",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "destination_unavailable",
                      "title": "Messages to this destination are not available"
                    }
                  },
                  "insufficient_funds": {
                    "summary": "409 insufficient_funds",
                    "value": {
                      "type": "about:blank",
                      "status": 409,
                      "code": "insufficient_funds",
                      "title": "Not enough money on the balance",
                      "shortage": {
                        "amount": "0.042500",
                        "currency": "USD"
                      }
                    }
                  },
                  "daily_limit_reached": {
                    "summary": "429 daily_limit_reached",
                    "value": {
                      "type": "about:blank",
                      "status": 429,
                      "code": "daily_limit_reached",
                      "title": "The daily message limit is reached",
                      "retry_after": "2026-11-03T03:00:00+00:00"
                    }
                  },
                  "idempotency_conflict": {
                    "summary": "409 idempotency_conflict",
                    "value": {
                      "type": "about:blank",
                      "status": 409,
                      "code": "idempotency_conflict",
                      "title": "This key was already used for a request with other data. Reload the page and try again"
                    }
                  },
                  "idempotency_in_progress": {
                    "summary": "409 idempotency_in_progress",
                    "value": {
                      "type": "about:blank",
                      "status": 409,
                      "code": "idempotency_in_progress",
                      "title": "A request with this idempotency key is still in progress"
                    }
                  },
                  "api_key_invalid": {
                    "summary": "401 api_key_invalid",
                    "value": {
                      "type": "about:blank",
                      "status": 401,
                      "code": "api_key_invalid",
                      "title": "The API key is missing, unknown or revoked"
                    }
                  },
                  "api_key_ip_denied": {
                    "summary": "403 api_key_ip_denied",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_ip_denied",
                      "title": "The API key may not be used from this address"
                    }
                  },
                  "account_suspended": {
                    "summary": "403 account_suspended",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "account_suspended",
                      "title": "The account is suspended"
                    }
                  },
                  "api_key_scope": {
                    "summary": "403 api_key_scope",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_scope",
                      "title": "The API key lacks the permission for this request"
                    }
                  },
                  "too_many_requests": {
                    "summary": "429 too_many_requests",
                    "value": {
                      "type": "about:blank",
                      "status": 429,
                      "code": "too_many_requests",
                      "title": "Too many requests. Try again later"
                    }
                  }
                }
              }
            }
          }
        },
        "x-api-key-scope": "send",
        "x-rate-limit": "50 requests a second per key"
      }
    },
    "/templates": {
      "get": {
        "operationId": "templates.index",
        "description": "The templates of the account you can send — WhatsApp ones first, then SMS, by name; `channel` lists one channel. A message is sent with the template `name` of its `channel` in one of its `languages`, with a value for every variable that has no fallback in that language. Use it to check names, languages and variables before sending, or to build a picker in your system.",
        "summary": "List the templates",
        "tags": [
          "Templates"
        ],
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "whatsapp",
                "sms"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PublicTemplateResource"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "examples": {
                  "templates": {
                    "summary": "Approved templates",
                    "value": {
                      "data": [
                        {
                          "name": "welcome_bonus",
                          "version": 3,
                          "channel": "whatsapp",
                          "category": "marketing",
                          "languages": [
                            "pt",
                            "en"
                          ],
                          "texts": {
                            "pt": "Olá {{name}}! Seu bônus {{promo_code}} já está ativo.",
                            "en": "Hi {{name}}! Your bonus {{promo_code}} is active."
                          },
                          "variables": [
                            {
                              "key": "name",
                              "example": {
                                "pt": "Ana",
                                "en": "Ann"
                              },
                              "fallback": {
                                "pt": "cliente",
                                "en": "there"
                              }
                            },
                            {
                              "key": "promo_code",
                              "example": {
                                "pt": "BONUS10",
                                "en": "BONUS10"
                              },
                              "fallback": {}
                            }
                          ]
                        },
                        {
                          "name": "deposit_reminder",
                          "version": 1,
                          "channel": "sms",
                          "category": "standard",
                          "languages": [
                            "en"
                          ],
                          "texts": {
                            "en": "Hi {{name}}, your deposit of {{amount}} is waiting. Reply STOP to opt out."
                          },
                          "variables": [
                            {
                              "key": "name",
                              "example": {
                                "en": "Ann"
                              },
                              "fallback": {
                                "en": "there"
                              }
                            },
                            {
                              "key": "amount",
                              "example": {
                                "en": "$50.00"
                              },
                              "fallback": {
                                "en": "your bonus"
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Problem Details (RFC 9457)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "api_key_invalid": {
                    "summary": "401 api_key_invalid",
                    "value": {
                      "type": "about:blank",
                      "status": 401,
                      "code": "api_key_invalid",
                      "title": "The API key is missing, unknown or revoked"
                    }
                  },
                  "api_key_ip_denied": {
                    "summary": "403 api_key_ip_denied",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_ip_denied",
                      "title": "The API key may not be used from this address"
                    }
                  },
                  "account_suspended": {
                    "summary": "403 account_suspended",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "account_suspended",
                      "title": "The account is suspended"
                    }
                  },
                  "api_key_scope": {
                    "summary": "403 api_key_scope",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_scope",
                      "title": "The API key lacks the permission for this request"
                    }
                  },
                  "too_many_requests": {
                    "summary": "429 too_many_requests",
                    "value": {
                      "type": "about:blank",
                      "status": 429,
                      "code": "too_many_requests",
                      "title": "Too many requests. Try again later"
                    }
                  }
                }
              }
            }
          }
        },
        "x-api-key-scope": "send",
        "x-rate-limit": "20 requests a second per key"
      }
    },
    "/messages/{message}": {
      "get": {
        "operationId": "messages.show",
        "description": "The message `msg_…` of the account with the history of its statuses (`events`, oldest first). A message of\nanother account is not found, nor a message of the other mode: a test key sees only the test messages (`test`\ntrue), a live key only the live ones. Keys with the `status` permission.",
        "summary": "Get a message",
        "tags": [
          "Messages"
        ],
        "parameters": [
          {
            "name": "message",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "msg_CgdWeHQN4sPaZnXfh7kP5"
          }
        ],
        "responses": {
          "200": {
            "description": "`PublicMessageResource`",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PublicMessageResource"
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "examples": {
                  "read": {
                    "summary": "A read WhatsApp message",
                    "value": {
                      "data": {
                        "id": "msg_CgdWeHQN4sPaZnXfh7kP5",
                        "status": "read",
                        "to": "+5521998120937",
                        "from": null,
                        "country": "BR",
                        "channel": "whatsapp",
                        "template": {
                          "name": "welcome_bonus",
                          "version": 3
                        },
                        "language": "pt",
                        "reference": "crm-42",
                        "text": "Olá Ana! Seu bônus BONUS10 já está ativo.",
                        "text_masked": false,
                        "segments": 1,
                        "encoding": null,
                        "price": {
                          "amount": "0.062500",
                          "currency": "USD"
                        },
                        "error": null,
                        "test": false,
                        "campaign": null,
                        "created_at": "2026-11-02T12:00:00+00:00",
                        "updated_at": "2026-11-02T12:00:09+00:00",
                        "events": [
                          {
                            "status": "accepted",
                            "at": "2026-11-02T12:00:00+00:00",
                            "error": null
                          },
                          {
                            "status": "queued",
                            "at": "2026-11-02T12:00:00+00:00",
                            "error": null
                          },
                          {
                            "status": "submitted",
                            "at": "2026-11-02T12:00:01+00:00",
                            "error": null
                          },
                          {
                            "status": "sent",
                            "at": "2026-11-02T12:00:02+00:00",
                            "error": null
                          },
                          {
                            "status": "delivered",
                            "at": "2026-11-02T12:00:04+00:00",
                            "error": null
                          },
                          {
                            "status": "read",
                            "at": "2026-11-02T12:00:09+00:00",
                            "error": null
                          }
                        ]
                      }
                    }
                  },
                  "rejected": {
                    "summary": "A message without WhatsApp",
                    "value": {
                      "data": {
                        "id": "msg_CgdWeHQNqtkmHvG3auyN5",
                        "status": "rejected",
                        "to": "+5521998120938",
                        "from": null,
                        "country": "BR",
                        "channel": "whatsapp",
                        "template": {
                          "name": "welcome_bonus",
                          "version": 3
                        },
                        "language": "pt",
                        "reference": "crm-43",
                        "text": "Olá Bruno! Seu bônus BONUS10 já está ativo.",
                        "text_masked": false,
                        "segments": 1,
                        "encoding": null,
                        "price": {
                          "amount": "0.062500",
                          "currency": "USD"
                        },
                        "error": {
                          "code": "no_whatsapp",
                          "text": "The number does not use WhatsApp"
                        },
                        "test": false,
                        "campaign": null,
                        "created_at": "2026-11-02T12:00:00+00:00",
                        "updated_at": "2026-11-02T12:00:02+00:00",
                        "events": [
                          {
                            "status": "accepted",
                            "at": "2026-11-02T12:00:00+00:00",
                            "error": null
                          },
                          {
                            "status": "queued",
                            "at": "2026-11-02T12:00:00+00:00",
                            "error": null
                          },
                          {
                            "status": "submitted",
                            "at": "2026-11-02T12:00:01+00:00",
                            "error": null
                          },
                          {
                            "status": "rejected",
                            "at": "2026-11-02T12:00:02+00:00",
                            "error": {
                              "code": "no_whatsapp",
                              "text": "The number does not use WhatsApp"
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Problem Details (RFC 9457)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "not_found": {
                    "summary": "404 not_found",
                    "value": {
                      "type": "about:blank",
                      "status": 404,
                      "code": "not_found",
                      "title": "Not found"
                    }
                  },
                  "api_key_invalid": {
                    "summary": "401 api_key_invalid",
                    "value": {
                      "type": "about:blank",
                      "status": 401,
                      "code": "api_key_invalid",
                      "title": "The API key is missing, unknown or revoked"
                    }
                  },
                  "api_key_ip_denied": {
                    "summary": "403 api_key_ip_denied",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_ip_denied",
                      "title": "The API key may not be used from this address"
                    }
                  },
                  "account_suspended": {
                    "summary": "403 account_suspended",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "account_suspended",
                      "title": "The account is suspended"
                    }
                  },
                  "api_key_scope": {
                    "summary": "403 api_key_scope",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_scope",
                      "title": "The API key lacks the permission for this request"
                    }
                  },
                  "too_many_requests": {
                    "summary": "429 too_many_requests",
                    "value": {
                      "type": "about:blank",
                      "status": 429,
                      "code": "too_many_requests",
                      "title": "Too many requests. Try again later"
                    }
                  }
                }
              }
            }
          }
        },
        "x-api-key-scope": "status",
        "x-rate-limit": "20 requests a second per key"
      }
    },
    "/contacts": {
      "post": {
        "operationId": "contacts.upsert",
        "description": "The contact of the number `to` (with the country code): created when the account has none (201), else changed\n(200). `name` replaces the name (null clears it); `fields` — values of custom fields by key (GET /v1/fields),\nonly the keys sent change, null removes one. Campaigns fill the variables {{key}} from these values. Refusals:\n`invalid_number`, `validation_failed` (`fields.{key}` `in` — no such field, `field_value` — not a value of its\ntype). Keys with the `contacts` permission.",
        "summary": "Create or update a contact",
        "tags": [
          "Contacts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertContactRequest"
              },
              "examples": {
                "contact": {
                  "summary": "Name and fields",
                  "value": {
                    "to": "+5521998120937",
                    "name": "Ana Souza",
                    "fields": {
                      "promo_code": "VIP25",
                      "amount": "150",
                      "vip_since": "2026-09-14"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "`PublicContactResource`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicContactResource"
                },
                "examples": {
                  "changed": {
                    "summary": "Existing contact changed",
                    "value": {
                      "id": "cnt_CgdWeHQNoWb5T3WhuKxnx",
                      "to": "+5521998120937",
                      "name": "Ana Souza",
                      "fields": {
                        "promo_code": "VIP25",
                        "amount": "150",
                        "vip_since": "2026-09-14"
                      },
                      "created_at": "2026-10-30T08:15:00+00:00",
                      "updated_at": "2026-11-02T12:00:00+00:00"
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "`PublicContactResource`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicContactResource"
                },
                "examples": {
                  "created": {
                    "summary": "New contact created",
                    "value": {
                      "id": "cnt_CgdWeHQNoWb5T3WhuKxnx",
                      "to": "+5521998120937",
                      "name": "Ana Souza",
                      "fields": {
                        "promo_code": "VIP25",
                        "amount": "150",
                        "vip_since": "2026-09-14"
                      },
                      "created_at": "2026-11-02T12:00:00+00:00",
                      "updated_at": "2026-11-02T12:00:00+00:00"
                    }
                  }
                }
              }
            }
          },
          "default": {
            "description": "Problem Details (RFC 9457)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalid_number": {
                    "summary": "422 invalid_number",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "invalid_number",
                      "title": "The recipient's number is not valid"
                    }
                  },
                  "validation_failed": {
                    "summary": "422 validation_failed",
                    "value": {
                      "type": "about:blank",
                      "status": 422,
                      "code": "validation_failed",
                      "title": "Check the form fields",
                      "errors": [
                        {
                          "field": "fields.amount",
                          "code": "field_value",
                          "message": "The value does not fit the type of the field: a number, an amount or a date like 30.10.2026"
                        },
                        {
                          "field": "fields.city",
                          "code": "in",
                          "message": "This value is not allowed"
                        }
                      ]
                    }
                  },
                  "api_key_invalid": {
                    "summary": "401 api_key_invalid",
                    "value": {
                      "type": "about:blank",
                      "status": 401,
                      "code": "api_key_invalid",
                      "title": "The API key is missing, unknown or revoked"
                    }
                  },
                  "api_key_ip_denied": {
                    "summary": "403 api_key_ip_denied",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_ip_denied",
                      "title": "The API key may not be used from this address"
                    }
                  },
                  "account_suspended": {
                    "summary": "403 account_suspended",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "account_suspended",
                      "title": "The account is suspended"
                    }
                  },
                  "api_key_scope": {
                    "summary": "403 api_key_scope",
                    "value": {
                      "type": "about:blank",
                      "status": 403,
                      "code": "api_key_scope",
                      "title": "The API key lacks the permission for this request"
                    }
                  },
                  "too_many_requests": {
                    "summary": "429 too_many_requests",
                    "value": {
                      "type": "about:blank",
                      "status": 429,
                      "code": "too_many_requests",
                      "title": "Too many requests. Try again later"
                    }
                  }
                }
              }
            }
          }
        },
        "x-api-key-scope": "contacts",
        "x-rate-limit": "50 requests a second per key"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "description": "An API key of the account (console: Settings → API and webhooks).",
        "scheme": "bearer",
        "bearerFormat": "ak_live_… | ak_test_…"
      }
    },
    "schemas": {
      "Channel": {
        "type": "string",
        "description": "The channel of a message.",
        "enum": [
          "whatsapp",
          "sms"
        ],
        "title": "Channel"
      },
      "MessageStatus": {
        "type": "string",
        "description": "The status of a message. See https://docs.ace-send.com/guide/statuses.",
        "enum": [
          "accepted",
          "queued",
          "submitted",
          "sent",
          "delivered",
          "read",
          "rejected",
          "failed",
          "expired",
          "cancelled"
        ],
        "title": "MessageStatus"
      },
      "Problem": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "examples": [
              "about:blank"
            ],
            "description": "Always `about:blank`."
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status."
          },
          "code": {
            "type": "string",
            "description": "What went wrong: stable and machine-readable. New codes may be added. See https://docs.ace-send.com/guide/errors."
          },
          "title": {
            "type": "string",
            "description": "A short text for people, in the language of `Accept-Language`. It may change."
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "field": {
                  "type": "string"
                },
                "code": {
                  "type": "string",
                  "description": "The failed rule of the field, e.g. `required`, `max`, `in`, `prohibited`, `field_value`."
                },
                "message": {
                  "type": "string"
                },
                "meta": {
                  "type": "object",
                  "description": "Numbers of some codes, when there are any.",
                  "additionalProperties": {
                    "type": "integer"
                  }
                }
              },
              "required": [
                "field",
                "code",
                "message"
              ]
            },
            "description": "The wrong fields, for `validation_failed` and some other codes."
          }
        },
        "required": [
          "type",
          "status",
          "code",
          "title"
        ],
        "title": "Problem"
      },
      "PublicContactResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The contact, `cnt_…`."
          },
          "to": {
            "type": "string",
            "description": "E.164, as messages are sent to it."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "The name of the contact."
          },
          "fields": {
            "type": "object",
            "description": "Values of custom fields by key, as kept: text, a number or an amount as «1234.5», a date as «2026-10-30».",
            "additionalProperties": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "description": "When the contact was created."
          },
          "updated_at": {
            "type": "string",
            "description": "When the contact last changed."
          }
        },
        "required": [
          "id",
          "to",
          "name",
          "fields",
          "created_at",
          "updated_at"
        ],
        "title": "PublicContactResource"
      },
      "PublicMessageResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The message, `msg_…`."
          },
          "status": {
            "type": "string",
            "enum": [
              "accepted",
              "queued",
              "submitted",
              "sent",
              "delivered",
              "read",
              "rejected",
              "failed",
              "expired",
              "cancelled"
            ]
          },
          "to": {
            "type": "string",
            "description": "The number in E.164."
          },
          "from": {
            "type": [
              "string",
              "null"
            ],
            "description": "The sender name of an SMS; null for WhatsApp (its number is not shown) and for a test SMS."
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 of the number."
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp",
              "sms"
            ]
          },
          "template": {
            "type": [
              "object",
              "null"
            ],
            "description": "The template and the number of the version the message was sent with; null for an own SMS text.",
            "properties": {
              "name": {
                "type": "string"
              },
              "version": {
                "type": "integer"
              }
            },
            "required": [
              "name",
              "version"
            ]
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "The language of the template; null for an own SMS text."
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your own id of the message, as you sent it."
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "description": "The text as sent; null once it is past its retention period (90 days, `text_masked`)."
          },
          "text_masked": {
            "type": "boolean",
            "description": "Whether `text` was erased after the retention period (90 days)."
          },
          "segments": {
            "type": "integer",
            "description": "The parts the SMS is sent and priced in (its price is the price of a segment times them); 1 for WhatsApp."
          },
          "encoding": {
            "type": [
              "string",
              "null"
            ],
            "description": "The encoding of the SMS: gsm7 (160 characters, 153 a segment of a longer text) or ucs2 (70, 67); null\nfor WhatsApp.",
            "enum": [
              "gsm7",
              "ucs2",
              null
            ]
          },
          "price": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "amount": {
                "type": "string"
              },
              "currency": {
                "type": "string"
              }
            },
            "required": [
              "amount",
              "currency"
            ],
            "description": "The price fixed at acceptance, in the currency of the account; for an SMS, the price of a segment times `segments`. Null for a test message."
          },
          "error": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "text": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "text"
            ],
            "description": "Why the message did not reach the recipient: a stable `code` and a `text` in the language of `Accept-Language`. Null while it is on its way or when delivered."
          },
          "test": {
            "type": "boolean",
            "description": "Sent with a test key: through the sandbox, free."
          },
          "campaign": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ],
            "description": "The console campaign that sent the message; null for a message of the API."
          },
          "created_at": {
            "type": "string",
            "description": "When the message was accepted."
          },
          "updated_at": {
            "type": "string",
            "description": "When the message last changed."
          },
          "events": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string"
                },
                "at": {
                  "type": "string"
                },
                "error": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "text": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "code",
                    "text"
                  ]
                }
              },
              "required": [
                "status",
                "at",
                "error"
              ]
            },
            "description": "The history of statuses, oldest first. Only in `GET /messages/{id}`; null elsewhere."
          }
        },
        "required": [
          "id",
          "status",
          "to",
          "from",
          "country",
          "channel",
          "template",
          "language",
          "reference",
          "text",
          "text_masked",
          "segments",
          "encoding",
          "price",
          "error",
          "test",
          "campaign",
          "created_at",
          "updated_at",
          "events"
        ],
        "title": "PublicMessageResource"
      },
      "PublicTemplateResource": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name to send with (`template` of POST /messages), unique in the channel."
          },
          "version": {
            "type": "integer",
            "description": "The number of the current version: messages answer with it."
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp",
              "sms"
            ]
          },
          "category": {
            "type": "string",
            "description": "The category of the current version, which the price of a message depends on."
          },
          "languages": {
            "type": "array",
            "description": "The languages of the template, the primary one first.",
            "items": {
              "type": "string"
            }
          },
          "texts": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The text of the current version in each language; variables are written as `{{key}}`."
          },
          "variables": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "example": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  }
                },
                "fallback": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "key",
                "example",
                "fallback"
              ]
            },
            "description": "The variables of the texts: `example` and `fallback` by language. A variable with a fallback in the language of the message may be left out of `variables`."
          }
        },
        "required": [
          "name",
          "version",
          "channel",
          "category",
          "languages",
          "texts",
          "variables"
        ],
        "title": "PublicTemplateResource"
      },
      "SendMessageRequest": {
        "type": "object",
        "description": "A message with a template (`template`, `language`, `variables`) or, for an SMS, with an own `text` — exactly one of the two: both answer `text` `prohibited`, neither answers `template` `required`.",
        "properties": {
          "to": {
            "type": "string",
            "description": "The number in E.164, for example +5521998120937.",
            "maxLength": 32
          },
          "template": {
            "type": "string",
            "description": "The name of an approved template of the channel (GET /templates); or `text`, never both.",
            "maxLength": 64
          },
          "language": {
            "type": "string",
            "description": "A language of the template; not with `text`.",
            "maxLength": 16
          },
          "variables": {
            "type": "object",
            "description": "Values of the variables by key; a missing one takes the fallback of the template in the language. Not\nwith `text`.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your own id of the message (up to 64 characters), returned with it and searchable.",
            "maxLength": 64
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp",
              "sms"
            ]
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "description": "An own SMS text instead of a template (`channel` sms) when the account may send one (otherwise 403\nfree_text_not_allowed); split into segments as any SMS. Not with `template`.",
            "maxLength": 10000
          }
        },
        "required": [
          "to"
        ],
        "title": "SendMessageRequest"
      },
      "UpsertContactRequest": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "description": "The number with the country code (E.164, «+5511912345678»), as for a message.",
            "maxLength": 32
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Up to 120 characters; null or blank clears it; left out keeps it.",
            "maxLength": 120
          },
          "fields": {
            "type": "object",
            "additionalProperties": {
              "type": [
                "string",
                "null"
              ]
            },
            "description": "Values of custom fields by key (`GET /fields`): only the keys sent change; null removes a value."
          }
        },
        "required": [
          "to"
        ],
        "title": "UpsertContactRequest"
      },
      "WebhookMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The message, `msg_…`."
          },
          "status": {
            "type": "string",
            "enum": [
              "accepted",
              "queued",
              "submitted",
              "sent",
              "delivered",
              "read",
              "rejected",
              "failed",
              "expired",
              "cancelled"
            ]
          },
          "to": {
            "type": "string",
            "description": "The number in E.164."
          },
          "from": {
            "type": [
              "string",
              "null"
            ],
            "description": "The sender name of an SMS; null for WhatsApp (its number is not shown) and for a test SMS."
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 of the number."
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp",
              "sms"
            ]
          },
          "template": {
            "type": [
              "object",
              "null"
            ],
            "description": "The template and the number of the version the message was sent with; null for an own SMS text.",
            "properties": {
              "name": {
                "type": "string"
              },
              "version": {
                "type": "integer"
              }
            },
            "required": [
              "name",
              "version"
            ]
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "The language of the template; null for an own SMS text."
          },
          "reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your own id of the message, as you sent it."
          },
          "text": {
            "type": [
              "string",
              "null"
            ],
            "description": "The text as sent; null once it is past its retention period (90 days, `text_masked`)."
          },
          "text_masked": {
            "type": "boolean",
            "description": "Whether `text` was erased after the retention period (90 days)."
          },
          "segments": {
            "type": "integer",
            "description": "The parts the SMS is sent and priced in (its price is the price of a segment times them); 1 for WhatsApp."
          },
          "encoding": {
            "type": [
              "string",
              "null"
            ],
            "description": "The encoding of the SMS: gsm7 (160 characters, 153 a segment of a longer text) or ucs2 (70, 67); null\nfor WhatsApp.",
            "enum": [
              "gsm7",
              "ucs2",
              null
            ]
          },
          "price": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "amount": {
                "type": "string"
              },
              "currency": {
                "type": "string"
              }
            },
            "required": [
              "amount",
              "currency"
            ],
            "description": "The price fixed at acceptance, in the currency of the account; for an SMS, the price of a segment times `segments`. Null for a test message."
          },
          "error": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "text": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "text"
            ],
            "description": "Why the message did not reach the recipient: a stable `code` and a `text` in the language of `Accept-Language`. Null while it is on its way or when delivered."
          },
          "test": {
            "type": "boolean",
            "description": "Sent with a test key: through the sandbox, free."
          },
          "campaign": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "name"
            ],
            "description": "The console campaign that sent the message; null for a message of the API."
          },
          "created_at": {
            "type": "string",
            "description": "When the message was accepted."
          },
          "updated_at": {
            "type": "string",
            "description": "When the message last changed."
          }
        },
        "required": [
          "id",
          "status",
          "to",
          "from",
          "country",
          "channel",
          "template",
          "language",
          "reference",
          "text",
          "text_masked",
          "segments",
          "encoding",
          "price",
          "error",
          "test",
          "campaign",
          "created_at",
          "updated_at"
        ],
        "title": "WebhookMessage",
        "description": "The message as GET /messages/{id} returns it, without `events`."
      }
    }
  },
  "tags": [
    {
      "name": "Messages",
      "description": "Send WhatsApp and SMS messages and follow their statuses. A message is sent with an approved template; an SMS may carry an own text when the account allows it."
    },
    {
      "name": "Templates",
      "description": "The approved templates of the account: what can be sent and with which variables."
    },
    {
      "name": "Contacts",
      "description": "Keep the contacts of the account and their custom fields up to date. Campaigns of the console fill template variables from these fields."
    },
    {
      "name": "Webhooks",
      "description": "Events ACE SEND posts to your webhook address."
    }
  ],
  "webhooks": {
    "message.sent": {
      "post": {
        "operationId": "webhooks.message.sent",
        "summary": "Message sent",
        "description": "The provider sent the message to the network. The data is the message as `GET /messages/{id}` returns it, without `events`; `status` is the status of this change (the message may have moved on by the time the webhook arrives).",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "message.sent"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "$ref": "#/components/schemas/WebhookMessage"
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "message-sent": {
                  "summary": "Message sent",
                  "value": {
                    "type": "message.sent",
                    "timestamp": "2026-11-02T12:00:04+00:00",
                    "data": {
                      "id": "msg_CgdWeHQN4sPaZnXfh7kP5",
                      "status": "sent",
                      "to": "+5521998120937",
                      "from": null,
                      "country": "BR",
                      "channel": "whatsapp",
                      "template": {
                        "name": "welcome_bonus",
                        "version": 3
                      },
                      "language": "pt",
                      "reference": "crm-42",
                      "text": "Olá Ana! Seu bônus BONUS10 já está ativo.",
                      "text_masked": false,
                      "segments": 1,
                      "encoding": null,
                      "price": {
                        "amount": "0.062500",
                        "currency": "USD"
                      },
                      "error": null,
                      "test": false,
                      "campaign": null,
                      "created_at": "2026-11-02T12:00:00+00:00",
                      "updated_at": "2026-11-02T12:00:00+00:00"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    },
    "message.delivered": {
      "post": {
        "operationId": "webhooks.message.delivered",
        "summary": "Message delivered",
        "description": "The message reached the phone of the recipient. The data is the message without `events`.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "message.delivered"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "$ref": "#/components/schemas/WebhookMessage"
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "message-delivered": {
                  "summary": "Message delivered",
                  "value": {
                    "type": "message.delivered",
                    "timestamp": "2026-11-02T12:00:04+00:00",
                    "data": {
                      "id": "msg_CgdWeHQN4sPaZnXfh7kP5",
                      "status": "delivered",
                      "to": "+5521998120937",
                      "from": null,
                      "country": "BR",
                      "channel": "whatsapp",
                      "template": {
                        "name": "welcome_bonus",
                        "version": 3
                      },
                      "language": "pt",
                      "reference": "crm-42",
                      "text": "Olá Ana! Seu bônus BONUS10 já está ativo.",
                      "text_masked": false,
                      "segments": 1,
                      "encoding": null,
                      "price": {
                        "amount": "0.062500",
                        "currency": "USD"
                      },
                      "error": null,
                      "test": false,
                      "campaign": null,
                      "created_at": "2026-11-02T12:00:00+00:00",
                      "updated_at": "2026-11-02T12:00:00+00:00"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    },
    "message.read": {
      "post": {
        "operationId": "webhooks.message.read",
        "summary": "Message read",
        "description": "The recipient opened the WhatsApp message. Only WhatsApp reports reads: SMS never get this event.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "message.read"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "$ref": "#/components/schemas/WebhookMessage"
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "message-read": {
                  "summary": "Message read",
                  "value": {
                    "type": "message.read",
                    "timestamp": "2026-11-02T12:00:04+00:00",
                    "data": {
                      "id": "msg_CgdWeHQN4sPaZnXfh7kP5",
                      "status": "read",
                      "to": "+5521998120937",
                      "from": null,
                      "country": "BR",
                      "channel": "whatsapp",
                      "template": {
                        "name": "welcome_bonus",
                        "version": 3
                      },
                      "language": "pt",
                      "reference": "crm-42",
                      "text": "Olá Ana! Seu bônus BONUS10 já está ativo.",
                      "text_masked": false,
                      "segments": 1,
                      "encoding": null,
                      "price": {
                        "amount": "0.062500",
                        "currency": "USD"
                      },
                      "error": null,
                      "test": false,
                      "campaign": null,
                      "created_at": "2026-11-02T12:00:00+00:00",
                      "updated_at": "2026-11-02T12:00:09+00:00"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    },
    "message.failed": {
      "post": {
        "operationId": "webhooks.message.failed",
        "summary": "Message failed",
        "description": "The message will not reach the recipient. `status` is one of `rejected`, `failed`, `expired` or `cancelled`, and `error` says why (see [failure codes](/guide/statuses#failure-codes)).",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "message.failed"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "$ref": "#/components/schemas/WebhookMessage"
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "message-failed": {
                  "summary": "Message failed",
                  "value": {
                    "type": "message.failed",
                    "timestamp": "2026-11-02T12:00:04+00:00",
                    "data": {
                      "id": "msg_CgdWeHQNqtkmHvG3auyN5",
                      "status": "rejected",
                      "to": "+5521998120938",
                      "from": null,
                      "country": "BR",
                      "channel": "whatsapp",
                      "template": {
                        "name": "welcome_bonus",
                        "version": 3
                      },
                      "language": "pt",
                      "reference": "crm-43",
                      "text": "Olá Bruno! Seu bônus BONUS10 já está ativo.",
                      "text_masked": false,
                      "segments": 1,
                      "encoding": null,
                      "price": {
                        "amount": "0.062500",
                        "currency": "USD"
                      },
                      "error": {
                        "code": "no_whatsapp",
                        "text": "The number does not use WhatsApp"
                      },
                      "test": false,
                      "campaign": null,
                      "created_at": "2026-11-02T12:00:00+00:00",
                      "updated_at": "2026-11-02T12:00:02+00:00"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    },
    "template.status": {
      "post": {
        "operationId": "webhooks.template.status",
        "summary": "Template reviewed",
        "description": "A template version was approved or rejected. An approved version can be sent at once with `POST /messages`; `category` is the category it was approved in (null for a rejected one).",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "template.status"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "template": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string",
                            "description": "The name to send the template with."
                          },
                          "version": {
                            "type": "integer",
                            "description": "The number of the reviewed version."
                          }
                        },
                        "required": [
                          "name",
                          "version"
                        ]
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "approved",
                          "rejected"
                        ]
                      },
                      "category": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "The category of an approved version."
                      }
                    },
                    "required": [
                      "template",
                      "status",
                      "category"
                    ]
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "template-status": {
                  "summary": "Template reviewed",
                  "value": {
                    "type": "template.status",
                    "timestamp": "2026-11-02T12:00:04+00:00",
                    "data": {
                      "template": {
                        "name": "welcome_bonus",
                        "version": 3
                      },
                      "status": "approved",
                      "category": "marketing"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    },
    "balance.low": {
      "post": {
        "operationId": "webhooks.balance.low",
        "summary": "Balance is low",
        "description": "The available balance (the balance minus the reserves of messages and campaigns in progress) fell below the threshold of the account. Top it up in the console to keep sending.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "balance.low"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "available": {
                        "type": "object",
                        "properties": {
                          "amount": {
                            "type": "string",
                            "description": "A decimal with 6 digits after the point."
                          },
                          "currency": {
                            "type": "string",
                            "description": "ISO 4217 code of the account currency."
                          }
                        },
                        "required": [
                          "amount",
                          "currency"
                        ],
                        "description": "The available balance now."
                      },
                      "threshold": {
                        "type": "object",
                        "properties": {
                          "amount": {
                            "type": "string",
                            "description": "A decimal with 6 digits after the point."
                          },
                          "currency": {
                            "type": "string",
                            "description": "ISO 4217 code of the account currency."
                          }
                        },
                        "required": [
                          "amount",
                          "currency"
                        ],
                        "description": "The low balance threshold of the account."
                      }
                    },
                    "required": [
                      "available",
                      "threshold"
                    ]
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "balance-low": {
                  "summary": "Balance is low",
                  "value": {
                    "type": "balance.low",
                    "timestamp": "2026-11-02T12:00:04+00:00",
                    "data": {
                      "available": {
                        "amount": "4.200000",
                        "currency": "USD"
                      },
                      "threshold": {
                        "amount": "5.000000",
                        "currency": "USD"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    },
    "campaign.finished": {
      "post": {
        "operationId": "webhooks.campaign.finished",
        "summary": "Campaign finished",
        "description": "A campaign of the console completed or was stopped. The numbers are those of the moment it finished: the delivery of its messages goes on and comes as `message.*` events.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "campaign.finished"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "description": "The campaign, `cmp_…`."
                      },
                      "name": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "completed",
                          "stopped"
                        ]
                      },
                      "recipients": {
                        "type": "integer",
                        "description": "Recipients of the campaign, the control group included."
                      },
                      "sent": {
                        "type": "integer",
                        "description": "Messages accepted for sending."
                      },
                      "skipped": {
                        "type": "integer",
                        "description": "Recipients that got no message: a stop list, an invalid number, a missing variable."
                      },
                      "control": {
                        "type": "integer",
                        "description": "The control group: recipients left without a message on purpose."
                      },
                      "started_at": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "format": "date-time"
                      },
                      "finished_at": {
                        "type": "string",
                        "format": "date-time"
                      }
                    },
                    "required": [
                      "id",
                      "name",
                      "status",
                      "recipients",
                      "sent",
                      "skipped",
                      "control",
                      "started_at",
                      "finished_at"
                    ]
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "campaign-finished": {
                  "summary": "Campaign finished",
                  "value": {
                    "type": "campaign.finished",
                    "timestamp": "2026-11-02T14:30:00+00:00",
                    "data": {
                      "id": "cmp_CgdWeHQNKTXRFhMrxkn9z",
                      "name": "Reactivation — November",
                      "status": "completed",
                      "recipients": 12840,
                      "sent": 12115,
                      "skipped": 83,
                      "control": 642,
                      "started_at": "2026-11-02T12:00:00+00:00",
                      "finished_at": "2026-11-02T14:30:00+00:00"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    },
    "test.ping": {
      "post": {
        "operationId": "webhooks.test.ping",
        "summary": "Test event",
        "description": "«Send a test event» in the console sends it to the webhook address, whatever its events and even when it is turned off. Use it to check the address and the signature check.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "webhook-id",
            "in": "header",
            "required": true,
            "description": "The delivery, `whd_…`. The same on every attempt of one delivery: use it to drop a repeated delivery.",
            "schema": {
              "type": "string"
            },
            "example": "whd_CgdWeHQNPm2BJ3HKzjYWt"
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "required": true,
            "description": "Unix time of the attempt, in seconds. Refuse deliveries older than 5 minutes.",
            "schema": {
              "type": "string"
            },
            "example": "1793620804"
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "required": true,
            "description": "`v1,` and the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}`, keyed with the secret (the part after `whsec_`, base64-decoded).",
            "schema": {
              "type": "string"
            },
            "example": "v1,o61V81Bi612VDBDvxqFnc13T6m90nu59Ymx5ju/Tud4="
          },
          {
            "name": "content-type",
            "in": "header",
            "required": true,
            "description": "`application/json`",
            "schema": {
              "type": "string"
            },
            "example": "application/json"
          },
          {
            "name": "user-agent",
            "in": "header",
            "required": true,
            "description": "`ACE-SEND-Webhooks/1`",
            "schema": {
              "type": "string"
            },
            "example": "ACE-SEND-Webhooks/1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "const": "test.ping"
                  },
                  "timestamp": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When the event happened (UTC)."
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "endpoint": {
                        "type": "string",
                        "description": "The webhook address, `whe_…`."
                      }
                    },
                    "required": [
                      "endpoint"
                    ]
                  }
                },
                "required": [
                  "type",
                  "timestamp",
                  "data"
                ]
              },
              "examples": {
                "test-ping": {
                  "summary": "Test event",
                  "value": {
                    "type": "test.ping",
                    "timestamp": "2026-11-02T12:00:04+00:00",
                    "data": {
                      "endpoint": "whe_CgdWeHQNAxHTekU8MJRZ9"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Received. Any other answer, a redirect or no answer in 5 seconds is retried."
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Guides",
    "url": "https://docs.ace-send.com"
  }
}
