{
  "openapi": "3.0.3",
  "info": {
    "title": "Cast API",
    "version": "1.4.0",
    "description": "Multi-channel messaging for MENA and Africa: SMS, WhatsApp, Voice, Push, journeys, contacts, links and campaigns.\n\n## Authentication\nBearer token. Send `Authorization: Bearer sk_live_...`.\n\n## Sandbox\nAn `sk_test_` key authenticates against your real account and reads your real data, but every side-effecting endpoint is **simulated** - nothing is sent and nothing is charged. Events, contacts, contact properties and verification checks sent with a test key are validated and answered as usual but nothing is saved, so a test key never starts or feeds a journey and never uses a verification attempt. Two writes are real even with a test key: creating a short link (`POST /v1/links`) and registering or unregistering a push device (`POST` and `DELETE /v1/push/devices`). Every response to a valid key, refusals included, carries an `X-Cast-Mode: live|test` header, and simulated responses include `\"livemode\": false`.\n\nBuild and run your whole integration on a test key, then change one string.\n\n## Retries\nEvery POST and DELETE accepts an `Idempotency-Key` header (200 characters or fewer). Send a unique value and a retry replays the original response rather than acting twice. A key is tied to the whole request - the method, the query string and the body - so reusing a key for a different request is refused with 422 `idempotency_key_reused`, never replayed. Sandbox (`sk_test_`) and live keys keep separate keys: a key used in the sandbox is new to a live key. Without the header, behaviour is unchanged.\n\n## Errors\nErrors return a JSON body with a stable machine-readable `code`.\n\n## Rate limits\nEach key has one hourly window. Every authenticated response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset` (unix seconds). Over the limit Cast answers 429 with the code `rate_limit_exceeded` and a `Retry-After` header. Treat the three headers as optional: an internal key with no limit does not get them. A failed authentication uses none of the window.\n\n## Versioning\nThe major version is in the URL. Additions ship with no notice, so ignore fields and enum values you do not know. A breaking change gets at least 180 days of notice, and a new major version runs beside the old one for at least 12 months. A deprecated item carries `deprecated`, `x-sunset` and `x-replacement` here, and a deprecated endpoint answers with `Deprecation`, `Sunset` and `Link` headers. The changelog is at `/developers/changelog` and `/v1/changelog`.",
    "contact": {
      "name": "Cast support",
      "email": "cast@wayvzgroup.com"
    },
    "x-webhook-events-url": "https://cast.wayvzgroup.com/v1/webhook-events",
    "x-changelog-url": "https://cast.wayvzgroup.com/v1/changelog"
  },
  "servers": [
    {
      "url": "https://cast.wayvzgroup.com",
      "description": "Cast API"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account"
    },
    {
      "name": "Messages"
    },
    {
      "name": "WhatsApp"
    },
    {
      "name": "Voice"
    },
    {
      "name": "Contacts"
    },
    {
      "name": "Events"
    },
    {
      "name": "Journeys"
    },
    {
      "name": "Links"
    },
    {
      "name": "Campaigns"
    },
    {
      "name": "Push"
    },
    {
      "name": "Audit"
    },
    {
      "name": "Reference"
    }
  ],
  "components": {
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 200
        },
        "description": "Send a unique key to make a write safe to retry. A repeat of the same request with the same key replays the original response instead of acting twice. The key covers the method, the query string and the body: reusing it for a different request (another person, another message) is refused with 422 idempotency_key_reused rather than replayed. Sandbox and live keys have separate key spaces."
      },
      "MethodOverride": {
        "name": "X-HTTP-Method-Override",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "DELETE"
          ]
        },
        "description": "Some hosts refuse the DELETE verb before it reaches the API. Send the request as POST with this header set to DELETE and it is treated as a DELETE in every respect: the sandbox, the request log and Idempotency-Key all see a DELETE. Only POST may be overridden, and only to DELETE."
      }
    },
    "headers": {
      "XRateLimitLimit": {
        "description": "The requests this key may make in the hourly window. Absent for an internal key with no limit.",
        "schema": {
          "type": "integer"
        }
      },
      "XRateLimitRemaining": {
        "description": "The requests left in the window. Absent for an internal key with no limit.",
        "schema": {
          "type": "integer"
        }
      },
      "XRateLimitReset": {
        "description": "When the window ends, in unix seconds. Absent for an internal key with no limit.",
        "schema": {
          "type": "integer"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before trying again.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Use `sk_live_...` to send for real, or `sk_test_...` for the sandbox."
      }
    },
    "schemas": {
      "AuditLogEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Row id. Rising, but not contiguous within one account."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "UTC, ISO 8601 with milliseconds and Z."
          },
          "category": {
            "type": "string",
            "nullable": true
          },
          "action": {
            "type": "string",
            "nullable": true
          },
          "actor": {
            "type": "object",
            "properties": {
              "username": {
                "type": "string",
                "nullable": true,
                "description": "Sign-in name (an email), or api:<key id> for an API call."
              },
              "name": {
                "type": "string",
                "nullable": true
              },
              "role": {
                "type": "string",
                "nullable": true
              },
              "seat_id": {
                "type": "integer",
                "nullable": true,
                "description": "Team member id; null for the account owner."
              }
            }
          },
          "entity": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "nullable": true
              },
              "id": {
                "type": "string",
                "nullable": true
              },
              "label": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "detail": {
            "description": "The recorded detail: a JSON object (or array) when it was stored as JSON, otherwise the stored text, or null. A detail longer than 32,000 characters is returned cut, as text, with `detail_truncated: true`.",
            "oneOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "array",
                "items": {}
              },
              {
                "type": "string",
                "nullable": true
              }
            ]
          },
          "detail_truncated": {
            "type": "boolean",
            "description": "Present, and true, only when `detail` was cut at 32,000 characters."
          },
          "ip": {
            "type": "string",
            "nullable": true
          },
          "user_agent": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AuditLogList": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "list"
            ]
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuditLogEntry"
            }
          },
          "count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "order": {
            "type": "string",
            "enum": [
              "desc",
              "asc"
            ]
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": "string",
            "description": "Pass as starting_after. On asc, present whenever there is a position (the last row, or the cursor you sent when the page is empty); on desc only while has_more."
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable code.",
                "example": "invalid_api_key"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "SendMessage": {
        "type": "object",
        "required": [
          "to",
          "text"
        ],
        "properties": {
          "to": {
            "description": "One recipient, or an array of them.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "text": {
            "type": "string"
          },
          "from": {
            "type": "string",
            "description": "Approved sender id."
          },
          "schedule_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SendWhatsApp": {
        "type": "object",
        "required": [
          "to"
        ],
        "properties": {
          "to": {
            "type": "string"
          },
          "template": {
            "type": "string",
            "description": "Approved template name."
          },
          "language": {
            "type": "string",
            "example": "en"
          },
          "params": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "text": {
            "type": "string",
            "description": "Free-form text; only inside the 24-hour service window."
          }
        }
      },
      "VoiceCall": {
        "type": "object",
        "required": [
          "to"
        ],
        "properties": {
          "to": {
            "type": "string"
          },
          "text": {
            "type": "string",
            "description": "Text to speak."
          },
          "audio_url": {
            "type": "string"
          },
          "ivr_id": {
            "type": "integer"
          }
        }
      },
      "Contact": {
        "type": "object",
        "required": [
          "phone"
        ],
        "properties": {
          "phone": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "group_id": {
            "type": "integer"
          },
          "properties": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "ContactEvent": {
        "type": "object",
        "required": [
          "phone",
          "type"
        ],
        "properties": {
          "phone": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "maxLength": 50,
            "example": "purchase.completed"
          },
          "payload": {
            "type": "object"
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BatchEvents": {
        "type": "object",
        "required": [
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/ContactEvent"
            }
          }
        }
      },
      "PushDevice": {
        "type": "object",
        "required": [
          "token",
          "platform"
        ],
        "properties": {
          "token": {
            "type": "string"
          },
          "platform": {
            "type": "string",
            "enum": [
              "android",
              "ios",
              "web"
            ]
          },
          "contact_phone": {
            "type": "string"
          }
        }
      },
      "SendEmail": {
        "type": "object",
        "required": [
          "to",
          "html"
        ],
        "properties": {
          "to": {
            "type": "string",
            "format": "email",
            "description": "Recipient email address."
          },
          "subject": {
            "type": "string",
            "description": "Subject line. Merge tags ({{first_name}} etc.) are supported."
          },
          "html": {
            "type": "string",
            "description": "HTML body. Open/click tracking and an unsubscribe footer are added automatically."
          },
          "fromAddress": {
            "type": "string",
            "description": "Optional verified from-address. Defaults to the account sender."
          },
          "fromName": {
            "type": "string"
          },
          "preheader": {
            "type": "string"
          },
          "firstName": {
            "type": "string",
            "description": "Optional merge value for personalization."
          },
          "lastName": {
            "type": "string"
          }
        }
      },
      "SendPush": {
        "type": "object",
        "required": [
          "token",
          "title"
        ],
        "properties": {
          "token": {
            "type": "string",
            "description": "Device token registered via POST /v1/push/devices."
          },
          "platform": {
            "type": "string",
            "enum": [
              "android",
              "ios",
              "web"
            ],
            "description": "Optional; auto-resolved from the registered device when omitted."
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string",
            "description": "https image URL (optional)."
          },
          "deepLink": {
            "type": "string",
            "description": "App deep link opened on tap (optional)."
          }
        }
      },
      "SendRcs": {
        "type": "object",
        "required": [
          "to",
          "body"
        ],
        "properties": {
          "to": {
            "type": "string",
            "description": "Recipient phone in E.164 (digits)."
          },
          "body": {
            "type": "string"
          },
          "mediaUrl": {
            "type": "string",
            "description": "https media URL (optional)."
          },
          "suggestedReplies": {
            "description": "Up to 11 suggested-reply chips. CSV string or array of strings.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          }
        }
      },
      "MessageAccepted": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Message id (e.g. email_123). Prefix _test_ in sandbox."
          },
          "object": {
            "type": "string",
            "example": "message"
          },
          "channel": {
            "type": "string",
            "enum": [
              "email",
              "push",
              "rcs"
            ]
          },
          "status": {
            "type": "string",
            "example": "queued"
          },
          "to": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateLink": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "campaign_id": {
            "type": "string"
          }
        }
      },
      "CreateCampaign": {
        "type": "object",
        "required": [
          "channel"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "sms",
              "whatsapp",
              "voice"
            ]
          },
          "group_id": {
            "type": "integer"
          },
          "text": {
            "type": "string"
          },
          "from": {
            "type": "string"
          }
        }
      },
      "FlowTrigger": {
        "type": "object",
        "required": [
          "flow_id",
          "phone"
        ],
        "properties": {
          "flow_id": {
            "type": "integer"
          },
          "phone": {
            "type": "string"
          }
        }
      },
      "AccountResponse": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "example": "account"
          },
          "client_id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "active": {
            "type": "boolean"
          },
          "balance": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "currency_symbol": {
            "type": "string"
          },
          "rate_limits": {
            "type": "object",
            "properties": {
              "requests_per_hour": {
                "type": "integer",
                "nullable": true,
                "description": "The ceiling that applies to this key. Null for an internal key with no limit."
              },
              "window_seconds": {
                "type": "integer",
                "example": 3600
              },
              "requests_per_second": {
                "type": "integer",
                "deprecated": true,
                "description": "The key's raw setting, 0 when unset. Not the enforced limit.",
                "x-sunset": "2027-05-01",
                "x-replacement": "rate_limits.requests_per_hour"
              },
              "messages_per_day": {
                "type": "string",
                "example": "unlimited"
              }
            }
          },
          "api_version": {
            "type": "string",
            "example": "v1"
          }
        }
      },
      "MessageFailure": {
        "type": "object",
        "nullable": true,
        "description": "Why a message failed. Null when there is nothing to report.",
        "properties": {
          "reason": {
            "type": "string",
            "description": "A normalised reason from a closed list, for example handset_unreachable.",
            "example": "handset_unreachable"
          },
          "reason_text": {
            "type": "string",
            "description": "The reason as a sentence you can show to a person."
          },
          "code": {
            "type": "string",
            "nullable": true,
            "description": "The carrier's own error code, when it sent one."
          },
          "attempts": {
            "type": "integer",
            "description": "How many routes were tried.",
            "example": 1
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "msg_12345"
          },
          "object": {
            "type": "string",
            "example": "message"
          },
          "to": {
            "type": "string"
          },
          "from": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "parts": {
            "type": "integer",
            "nullable": true
          },
          "language": {
            "type": "string",
            "example": "gsm7"
          },
          "status": {
            "type": "string",
            "example": "delivered"
          },
          "rate": {
            "type": "string"
          },
          "gateway": {
            "type": "string"
          },
          "submitted_at": {
            "type": "string",
            "nullable": true
          },
          "campaign_id": {
            "type": "string"
          },
          "failure": {
            "$ref": "#/components/schemas/MessageFailure"
          }
        }
      },
      "MessageList": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "example": "list"
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Message"
            }
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "count": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          },
          "next_cursor": {
            "type": "string"
          },
          "next_offset": {
            "type": "integer"
          }
        }
      }
    }
  },
  "paths": {
    "/v1/ping": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "ping",
        "summary": "Health check",
        "description": "Confirms the key is valid and the API is reachable.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        }
      }
    },
    "/v1/balance": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getBalance",
        "summary": "Wallet balance",
        "description": "Current sending balance and currency.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "503": {
            "description": "The balance could not be read right now (code `balance_unavailable`). Retry after the number of seconds in Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/verify/start": {
      "post": {
        "tags": [
          "Verify"
        ],
        "operationId": "startVerification",
        "summary": "Start phone verification (OTP)",
        "description": "Sends a one-time verification code by SMS. Body: phone, sender, optional purpose, code_length, expiry_seconds, max_attempts, template.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone",
                  "sender"
                ],
                "properties": {
                  "phone": {
                    "type": "string"
                  },
                  "sender": {
                    "type": "string"
                  },
                  "purpose": {
                    "type": "string"
                  },
                  "code_length": {
                    "type": "integer"
                  },
                  "expiry_seconds": {
                    "type": "integer"
                  },
                  "max_attempts": {
                    "type": "integer"
                  },
                  "template": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification started",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        }
      }
    },
    "/v1/verify/check": {
      "post": {
        "tags": [
          "Verify"
        ],
        "operationId": "checkVerification",
        "summary": "Check a verification code",
        "description": "Verifies a code the user entered. Body: phone, code. Returns whether the code was approved.\n\n**Sandbox:** with an `sk_test_` key the code is never checked and no attempt is used. The answer is `not_found`, or the state of the open verification for that phone (`pending` with its attempts left, `expired`, `max_attempts`), never `approved`, with `\"livemode\": false` and `\"simulated\": true`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone",
                  "code"
                ],
                "properties": {
                  "phone": {
                    "type": "string"
                  },
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Check result (approved / pending / expired / max_attempts)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        }
      }
    },
    "/v1/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccount",
        "summary": "Account details",
        "description": "Company, status and enabled channels.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountResponse"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "503": {
            "description": "The balance could not be read right now (code `balance_unavailable`). Retry after the number of seconds in Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/messages": {
      "post": {
        "tags": [
          "Messages"
        ],
        "operationId": "sendMessage",
        "summary": "Send an SMS",
        "description": "Sends to one or many recipients.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessage"
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "listMessages",
        "summary": "List messages",
        "description": "Filter by status, date and channel.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageList"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not available while this account's team views are on (code `team_scoping`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "queued, sent, delivered, failed ..."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Max 100."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          }
        ]
      }
    },
    "/v1/messages/{id}": {
      "get": {
        "tags": [
          "Messages"
        ],
        "operationId": "getMessage",
        "summary": "Retrieve a message",
        "description": "Status and delivery detail for one message.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not available while this account's team views are on (code `team_scoping`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id returned when the message was created."
          }
        ]
      }
    },
    "/v1/whatsapp/messages": {
      "post": {
        "tags": [
          "WhatsApp"
        ],
        "operationId": "sendWhatsApp",
        "summary": "Send a WhatsApp message",
        "description": "Template message, or free-form inside the 24-hour service window.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendWhatsApp"
              }
            }
          }
        }
      }
    },
    "/v1/voice/call": {
      "post": {
        "tags": [
          "Voice"
        ],
        "operationId": "placeCall",
        "summary": "Place a voice call",
        "description": "Text-to-speech, a hosted audio file, or an IVR flow.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "202": {
            "description": "Outcome unknown. The call could not be confirmed as queued. It may still be placed, so it was not tried again, and its charge is kept until it settles. `status` is `unknown` and `message` says in plain words whether this was recorded; if it says to contact support, quote the `callSid`. Look the call up with `GET /v1/voice/call/{callSid}`. A replay with the same `Idempotency-Key` returns this answer and places nothing.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "string" },
                    "callSid": { "type": "string" },
                    "status": { "type": "string", "enum": [ "unknown" ] },
                    "to": { "type": "string" },
                    "estimatedCost": { "type": "number" },
                    "message": { "type": "string" },
                    "createdAt": { "type": "string", "format": "date-time" }
                  }
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "500": {
            "description": "voice_enqueue_failed: the call could not be queued, and it was not placed. `message` says what happened to the charge: returned (you were not charged), recorded and to be returned or reviewed, or neither, in which case it asks you to contact support and quotes the callSid. A 500 is not stored against the `Idempotency-Key`, so a retry, even with the same key, runs the request again: a new charge and a new call. Retry only after reading `error.message`: retry when it says the charge was returned or recorded; when it asks you to contact support, do that first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "voice_enqueue_failed",
                    "message": "Could not enqueue the voice call. The call was not placed, and its charge could not be returned or recorded. Contact support and quote callSid abc12345def67890."
                  }
                }
              }
            }
          },
          "503": {
            "description": "charge_unavailable: the call was not placed because the charge could not be taken right now. Not a balance problem. Retry after the number of seconds in Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoiceCall"
              }
            }
          }
        }
      }
    },
    "/v1/voice/call/{callSid}": {
      "get": {
        "tags": [
          "Voice"
        ],
        "operationId": "getCall",
        "summary": "Retrieve a call",
        "description": "Status, duration and outcome.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "callSid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Call id (sid) returned when the call was placed."
          }
        ]
      }
    },
    "/v1/email/messages": {
      "post": {
        "tags": [
          "Email"
        ],
        "operationId": "sendEmail",
        "summary": "Send an email",
        "description": "Queues one tracked email through the same pipeline the console and journeys use. Consent + the suppression list are enforced; an opted-out or suppressed recipient is rejected with 422.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendEmail"
              },
              "example": {
                "to": "aisha@example.com",
                "subject": "Your order shipped",
                "html": "<h1>On its way</h1><p>Hi {{first_name}}, your order is out for delivery.</p>",
                "firstName": "Aisha"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted for delivery",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageAccepted"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Recipient opted out / suppressed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        }
      }
    },
    "/v1/push/messages": {
      "post": {
        "tags": [
          "Push"
        ],
        "operationId": "sendPush",
        "summary": "Send a push notification",
        "description": "Queues one push to a registered device token through the same pipeline the console and journeys use. Push consent is enforced; an opted-out token is rejected with 422.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendPush"
              },
              "example": {
                "token": "fcm-device-token-abc123",
                "title": "Flash sale",
                "body": "24 hours only - 30% off everything.",
                "deepLink": "myapp://sale"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted for delivery",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageAccepted"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Recipient opted out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        }
      }
    },
    "/v1/rcs/messages": {
      "post": {
        "tags": [
          "RCS"
        ],
        "operationId": "sendRcs",
        "summary": "Send an RCS message",
        "description": "Queues one RCS message through the same pipeline the console and journeys use. RCS consent is enforced; an opted-out recipient is rejected with 422.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendRcs"
              },
              "example": {
                "to": "96170123456",
                "body": "Your table is booked for 8pm. Reply to change.",
                "suggestedReplies": [
                  "Confirm",
                  "Reschedule"
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted for delivery",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageAccepted"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Recipient opted out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        }
      }
    },
    "/v1/contacts": {
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "upsertContact",
        "summary": "Create or update a contact",
        "description": "Idempotent on phone within your account. Creating a NEW contact is refused with 402 `mac_limit_reached` when your plan's active contact limit is reached; updating an existing contact never is.\n\n**Sandbox:** with an `sk_test_` key the contact is validated exactly as live (including the 402) and the answer says whether it would be created or updated and how many groups and properties would be written, with `\"livemode\": false` and `\"simulated\": true`. Nothing is saved.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Plan's active contact limit reached (code `mac_limit_reached`); upgrade the plan to add contacts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Contact"
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "listContacts",
        "summary": "List contacts",
        "description": "Paged, optionally filtered by group.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "group_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Max 100."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": ""
          }
        ]
      }
    },
    "/v1/contacts/{phone}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "getContact",
        "summary": "Retrieve a contact",
        "description": "Contact with its properties.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Contact phone in international format, digits only."
          }
        ]
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "operationId": "eraseContact",
        "summary": "Erase a person permanently",
        "description": "Right to erasure (GDPR Art. 17, POPIA s24). Removes their contact record, messages, events, properties, notes, consent records, push devices and browser push subscriptions, and strips the content and the recipient from billing records while keeping the rows themselves. Not reached yet: call recordings, carrier billing subscriptions, voice call detail rows, WhatsApp template parameters and outbound webhook payloads. An address or number another contact also uses is left in place for that contact. This cannot be undone.\n\n`erase=true` is required: there is no soft delete on this resource, so a bare DELETE would be ambiguous and the wrong reading is unrecoverable.\n\nSafe to retry: send an `Idempotency-Key` and a retry of the same request replays the original 200 (the key covers the person in the path, so the same key for somebody else is refused with 422). Without a key, a second call answers 404 not_found, which a client retrying a timed-out request can treat as done. On a host that refuses DELETE, send POST with `X-HTTP-Method-Override: DELETE`.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is erased.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is held for that person",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still being processed (code `request_in_progress`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Idempotency-Key already used for a different request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Contact phone in international format, digits only."
          },
          {
            "name": "erase",
            "in": "query",
            "required": true,
            "schema": {
              "type": "boolean"
            },
            "description": "Must be true. Confirms the erasure is permanent."
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional. The person's email address, so the request also reaches what is held under that address (email events, suppression, consent kept by email)."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/MethodOverride"
          }
        ]
      }
    },
    "/v1/contacts/{phone}/export": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "exportContactData",
        "summary": "Export a person's data",
        "description": "Subject access and portability (GDPR Art. 15 and Art. 20, POPIA s23). Returns a JSON bundle with one section per source: the contact record, properties, events, consent and its history, messages in and out with their bodies, email engagement, clicks, conversions, inbox notes and tags, AI agent transcripts, satisfaction (CSAT) answers, the content of campaign emails, web chat replies, WhatsApp calls, quiz results, verification requests and linked identifiers, push devices and their push events, and browser push subscriptions (without their encryption keys). Not included: call recordings, carrier billing subscriptions, voice call detail rows and WhatsApp template parameters. Notes and transcripts are free text written by your agents and can name other people, so review the bundle before you release it to the person.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Contact phone in international format, digits only."
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional. The person's email address, so the request also reaches what is held under that address (email events, suppression, consent kept by email)."
          }
        ]
      }
    },
    "/v1/contacts/{phone}/properties": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "operationId": "getContactProperties",
        "summary": "List contact properties",
        "description": "Custom key/value properties.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Contact phone in international format, digits only."
          }
        ]
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "operationId": "setContactProperties",
        "summary": "Set contact properties",
        "description": "Merges into existing properties.\n\n**Sandbox:** with an `sk_test_` key the properties are validated exactly as live and the answer counts the keys that would be saved, with `\"livemode\": false` and `\"simulated\": true`. Nothing is saved.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Contact phone in international format, digits only."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/v1/contacts/{phone}/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "listContactEvents",
        "summary": "List events for a contact",
        "description": "Newest first.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Not available while this account's team views are on (code `team_scoping`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Contact phone in international format, digits only."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Max 100."
          }
        ]
      },
      "post": {
        "tags": [
          "Events"
        ],
        "operationId": "recordContactEvent",
        "summary": "Record an event for a contact",
        "description": "Appends a single behavioural event to the contact's timeline (for one-off events; use `POST /v1/events` for batches). The event is stored on the timeline, where goal and wait_for_event steps of running journeys and segment conditions read it. It does not start event-triggered journeys: only `POST /v1/events` does.\n\n**Sandbox:** with an `sk_test_` key the event is validated exactly as live and answered with the same fields, `event_id` 0, `\"livemode\": false` and `\"simulated\": true`. Nothing is stored and no journey is started.",
        "responses": {
          "201": {
            "description": "Recorded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Contact phone in international format, digits only."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "maxLength": 50,
                    "description": "Event type, lowercase domain.action, e.g. \"purchase.completed\"."
                  },
                  "payload": {
                    "type": "object",
                    "description": "Optional event data, 8 KB at most."
                  },
                  "occurred_at": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Optional ISO 8601 time the event happened. Defaults to now."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/events": {
      "post": {
        "tags": [
          "Events"
        ],
        "operationId": "batchEvents",
        "summary": "Ingest events",
        "description": "Up to 100 events per call, accepted or rejected per item. An accepted event also enrols the contact in any active journey triggered by that event type.\n\n**Sandbox:** with an `sk_test_` key each event is validated and gets the same per-item verdict as live, and the response adds `\"livemode\": false` and `\"simulated\": true`. No event is stored and no journey is started.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchEvents"
              }
            }
          }
        }
      }
    },
    "/v1/push/devices": {
      "post": {
        "tags": [
          "Push"
        ],
        "operationId": "registerPushDevice",
        "summary": "Register a push device",
        "description": "Upsert by token; safe to call on every app start.\n\n**Sandbox:** with an `sk_test_` key this is a real write: the same as with a live key.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PushDevice"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Push"
        ],
        "operationId": "unregisterPushDevice",
        "summary": "Unregister a push device",
        "description": "Retires a device so it receives no more pushes. Send `token` or `device_id` in the body. On a host that refuses DELETE, send POST with `X-HTTP-Method-Override: DELETE`.\n\n**Sandbox:** with an `sk_test_` key this is a real write: the same as with a live key.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "token": {
                    "type": "string",
                    "maxLength": 512
                  },
                  "device_id": {
                    "type": "string"
                  }
                },
                "description": "One of token or device_id is required."
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/MethodOverride"
          }
        ]
      }
    },
    "/v1/flows": {
      "get": {
        "tags": [
          "Journeys"
        ],
        "operationId": "listFlows",
        "summary": "List journeys",
        "description": "Filter by status.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "active, paused, draft, all"
          }
        ]
      }
    },
    "/v1/flows/{id}/trigger": {
      "post": {
        "tags": [
          "Journeys"
        ],
        "operationId": "triggerFlowById",
        "summary": "Enrol a contact into a journey",
        "description": "Same as /v1/flows/trigger with the journey id in the path.\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Journey id."
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone"
                ],
                "properties": {
                  "phone": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/flows/enrollments/{id}": {
      "get": {
        "tags": [
          "Journeys"
        ],
        "operationId": "getEnrollment",
        "summary": "Retrieve an enrolment",
        "description": "Current step and status.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enrolment id."
          }
        ]
      }
    },
    "/v1/links": {
      "post": {
        "tags": [
          "Links"
        ],
        "operationId": "createLink",
        "summary": "Create a short link",
        "description": "Returns the branded short URL.\n\n**Sandbox:** with an `sk_test_` key this is a real write: the same as with a live key.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLink"
              }
            }
          }
        }
      }
    },
    "/v1/campaigns": {
      "post": {
        "tags": [
          "Campaigns"
        ],
        "operationId": "createCampaign",
        "summary": "Create and send a campaign",
        "description": "Queues a message to each recipient\n\n**Sandbox:** with an `sk_test_` key this endpoint validates the request and returns a shape-identical response with `\"livemode\": false`. Nothing is sent and nothing is charged.",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid request. On the whatsapp channel the error code `template_not_found` means the template and language are not approved on this account: nothing was sent or charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCampaign"
              }
            }
          }
        }
      }
    },
    "/v1/audit-log": {
      "get": {
        "tags": [
          "Audit"
        ],
        "operationId": "listAuditLog",
        "summary": "List the audit log",
        "description": "Your account's audit trail: sign-ins, team and role changes, API key creation, billing actions, settings changes and record access. Needs a live key created with **Can read the audit log** ticked in Developers (only someone allowed to export the audit log can tick it). Every other key, and every sandbox key, gets `403 insufficient_scope`.\n\n**Paging.** Keyset on the row id. Pass the `next_cursor` of one response as `starting_after` of the next. With `order=desc` (the default) rows come newest first and `next_cursor` is present only while `has_more` is true. With `order=asc` rows come oldest first and `next_cursor` is always present once there is a position: the last row of the page, or, on an empty page, the cursor you sent. A system that polls the log keeps the last cursor and asks again later; the next poll returns the rows written since. On `asc`, rows still being saved are held back for five seconds. A page can hold fewer than `limit` rows when its rows are large; `has_more` says whether to ask again.\n\n**Personal data.** Rows carry the acting user's email and name, their IP address and browser, and free text in `entity.label` and `detail` that can include a customer's name or phone number. Rows older than the account's audit retention, where it is switched on, are no longer returned.\n\nReads are not themselves written to the audit log. Requests count toward the key's hourly rate limit like any other call.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "description": "1 to 500. Values outside that range are clamped, not refused."
          },
          {
            "name": "starting_after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The `next_cursor` of a previous response. With `order=asc` a cursor that cannot be read is `400 invalid_cursor` (a poller is never sent back to the start); with `order=desc` it is ignored and the list starts from the newest row."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "desc",
                "asc"
              ],
              "default": "desc"
            },
            "description": "`desc` newest first, `asc` oldest first. Anything else is `400 invalid_order`."
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "ISO 8601, inclusive. A value with no offset is read as UTC. Invalid: `400 invalid_since`."
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "ISO 8601, exclusive. Invalid: `400 invalid_until`. `since` not earlier than `until`: `400 invalid_range`."
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "description": "Exact match, for example `Security`, `Team`, `Billing`, `Settings`, `Developers`."
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "description": "Exact match, for example `auth.login`, `team.invite`, `apikey.create`."
          },
          {
            "name": "actor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "description": "Contains match on the acting user's sign-in name or display name."
          },
          {
            "name": "entity_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "description": "Exact match on the kind of record acted on, for example `api_key`, `contact`, `team_member`."
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditLogList"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              }
            }
          },
          "400": {
            "description": "Invalid parameter: invalid_order, invalid_cursor, invalid_since, invalid_until, invalid_range, invalid_category, invalid_action, invalid_actor, invalid_entity_type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope (the key has no audit access, or is a sandbox key), ip_not_allowed (the account's API address allowlist), plan_required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "Only GET is accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/XRateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/XRateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/XRateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            }
          },
          "503": {
            "description": "not_available: the export is not available on this server yet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhook-events": {
      "get": {
        "tags": [
          "Reference"
        ],
        "operationId": "listWebhookEvents",
        "summary": "Webhook event catalogue",
        "description": "Every webhook event, its fields, a sample, deprecations and the delivery policy. Public: no key needed, no account data.",
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "ETag": {
                "description": "Send it back as If-None-Match to get a 304 when nothing changed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          }
        }
      }
    },
    "/v1/changelog": {
      "get": {
        "tags": [
          "Reference"
        ],
        "operationId": "getChangelog",
        "summary": "API changelog",
        "description": "The API changelog and the deprecation registry. Public: no key needed, no account data.",
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "headers": {
              "ETag": {
                "description": "Send it back as If-None-Match to get a 304 when nothing changed.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          }
        }
      }
    }
  }
}
