{
  "openapi": "3.1.0",
  "info": {
    "title": "IntelliPortal Partner API",
    "version": "1.6.0",
    "description": "Connect client WhatsApp and Instagram accounts, manage their message templates, send messages on their behalf, and meter usage through a versioned partner API.",
    "contact": {
      "email": "support@intelliconcierge.com"
    }
  },
  "servers": [
    {
      "url": "https://api.intelliconcierge.dev/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Messages",
      "description": "Send through a connected client, and acknowledge what customers send you with read receipts and typing indicators."
    },
    {
      "name": "Clients",
      "description": "Onboard and inspect channel connections."
    },
    {
      "name": "Templates",
      "description": "Create WhatsApp message templates on a client's behalf and follow them through Meta's review."
    },
    {
      "name": "Usage",
      "description": "Read monthly message consumption."
    },
    {
      "name": "Platform",
      "description": "Probe public edge health and version."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Scoped partner API key prefixed with ik_test_ or ik_live_.\n\nKeys carry scopes. Each operation lists the scopes it requires in its security requirement; a key without them gets 403 forbidden.\n\n- `messages:send`: Send messages and templates, upload send media, mark messages read and show typing indicators.\n- `clients:read`: List and read connected clients and download media they received.\n- `clients:write`: Start hosted WhatsApp and Instagram onboarding and update or register clients.\n- `templates:read`: List and read a client's WhatsApp message templates.\n- `templates:write`: Create, update and delete WhatsApp message templates and upload template media."
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "examples": [
                  "bad_request",
                  "unauthorized",
                  "rate_limited"
                ]
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "additionalProperties": true,
                "description": "Optional structured validation or provider context."
              }
            }
          }
        }
      },
      "SendMessageRequest": {
        "type": "object",
        "required": [
          "client_ref",
          "to",
          "type"
        ],
        "description": "Meta-compatible free-form message. The type value selects the same-named payload field.",
        "properties": {
          "client_ref": {
            "type": "string",
            "description": "Stable client identifier from your own system."
          },
          "to": {
            "type": "string",
            "description": "WhatsApp recipient number or Instagram-scoped user ID."
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "image",
              "video",
              "audio",
              "document",
              "sticker",
              "location",
              "contacts",
              "interactive",
              "reaction"
            ]
          },
          "text": {
            "type": "object",
            "properties": {
              "body": {
                "type": "string"
              },
              "preview_url": {
                "type": "boolean"
              }
            }
          },
          "image": {
            "$ref": "#/components/schemas/CaptionedMedia"
          },
          "video": {
            "$ref": "#/components/schemas/CaptionedMedia"
          },
          "audio": {
            "$ref": "#/components/schemas/Media"
          },
          "document": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CaptionedMedia"
              },
              {
                "type": "object",
                "properties": {
                  "filename": {
                    "type": "string"
                  }
                }
              }
            ]
          },
          "sticker": {
            "$ref": "#/components/schemas/Media"
          },
          "location": {
            "type": "object",
            "required": [
              "latitude",
              "longitude"
            ],
            "properties": {
              "latitude": {
                "type": "number"
              },
              "longitude": {
                "type": "number"
              },
              "name": {
                "type": "string"
              },
              "address": {
                "type": "string"
              }
            }
          },
          "contacts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "interactive": {
            "type": "object",
            "required": [
              "type"
            ],
            "additionalProperties": true,
            "properties": {
              "type": {
                "type": "string"
              }
            }
          },
          "reaction": {
            "type": "object",
            "required": [
              "message_id",
              "emoji"
            ],
            "properties": {
              "message_id": {
                "type": "string"
              },
              "emoji": {
                "type": "string",
                "description": "An empty value removes an existing reaction."
              }
            }
          },
          "dry_run": {
            "type": "boolean",
            "description": "Validate without delivery. Always true for ik_test_ keys."
          }
        }
      },
      "Media": {
        "type": "object",
        "description": "Provide either a public HTTPS link or an uploaded media id.",
        "properties": {
          "link": {
            "type": "string",
            "format": "uri"
          },
          "id": {
            "type": "string"
          }
        }
      },
      "CaptionedMedia": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Media"
          },
          {
            "type": "object",
            "properties": {
              "caption": {
                "type": "string"
              }
            }
          }
        ]
      },
      "SendTemplateRequest": {
        "type": "object",
        "required": [
          "client_ref",
          "to"
        ],
        "description": "Name the template with template_ref (recommended — the template is resolved, approval-checked, and its components are built server-side) or pass a raw Meta template object. Exactly one of template_ref / template.",
        "properties": {
          "client_ref": {
            "type": "string"
          },
          "to": {
            "type": "string"
          },
          "template_ref": {
            "type": "string",
            "description": "Template id from the Templates API, or the template name. Disambiguate a name that exists in several languages with `language`."
          },
          "language": {
            "type": "string",
            "description": "Language code (e.g. en_US) used to disambiguate template_ref by name."
          },
          "parameters": {
            "description": "Body variable values: an array fills {{1}}, {{2}}… in order; an object matches named variables or numbered keys.",
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                }
              }
            ]
          },
          "header": {
            "type": "object",
            "description": "Header variable when the template has one: {\"text\": ...} for text headers; {\"link\": ...} or {\"id\": ...} (plus optional \"filename\") for image/video/document; {\"location\": {...}} for location headers.",
            "additionalProperties": true
          },
          "buttons": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Values for dynamic URL buttons, in button order."
          },
          "cards": {
            "type": "array",
            "description": "Carousel templates only: one object per card, in card order. Every card needs its header media at send time.",
            "items": {
              "type": "object",
              "properties": {
                "header": {
                  "type": "object",
                  "description": "The card's header media: {\"link\": ...} or {\"id\": ...}.",
                  "additionalProperties": true
                },
                "parameters": {
                  "description": "The card's body variable values.",
                  "oneOf": [
                    {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    }
                  ]
                },
                "buttons": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Values for the card's quick replies (webhook payload) and dynamic URL buttons (suffix), in button order."
                }
              }
            }
          },
          "template": {
            "type": "object",
            "required": [
              "name"
            ],
            "description": "Raw Meta template object, forwarded unchanged. Alternative to template_ref.",
            "properties": {
              "name": {
                "type": "string"
              },
              "language": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "default": "en_US"
                  }
                }
              },
              "components": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "dry_run": {
            "type": "boolean"
          }
        }
      },
      "MessageResponse": {
        "type": "object",
        "required": [
          "success",
          "message_id"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message_id": {
            "type": "string"
          },
          "dry_run": {
            "type": "boolean",
            "description": "Present and true when no delivery was attempted."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Present when the message was sent but the channel could not carry part of it — a caption on an Instagram attachment, for example. The send succeeded and needs no retry, but the listed content never reached the recipient."
          },
          "template": {
            "type": "object",
            "additionalProperties": true,
            "description": "On a template_ref dry-run: the assembled Meta template object a live send would carry."
          },
          "hint": {
            "type": "string",
            "description": "Present on a simulated test-key send — explains that delivery only happens to registered test recipients."
          }
        }
      },
      "MarkReadRequest": {
        "type": "object",
        "required": [
          "client_ref",
          "to"
        ],
        "description": "Send a read receipt in a customer's thread. WhatsApp attaches it to one inbound message (message_id required); Instagram marks the whole conversation seen.",
        "properties": {
          "client_ref": {
            "type": "string",
            "description": "Stable client identifier from your own system."
          },
          "to": {
            "type": "string",
            "description": "The customer: the WhatsApp number the message came from (messages[].from in message.received) or the Instagram-scoped user ID (messages[].sender.id)."
          },
          "message_id": {
            "type": "string",
            "description": "WhatsApp: required — the wamid of the message you received (messages[].id in message.received). Only inbound messages can be marked read. Instagram: ignored, seen is per conversation."
          },
          "dry_run": {
            "type": "boolean",
            "description": "Validate without calling Meta. With an ik_test_ key, calls are simulated unless `to` is a registered test recipient."
          }
        }
      },
      "TypingRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MarkReadRequest"
          },
          {
            "type": "object",
            "properties": {
              "state": {
                "type": "string",
                "enum": [
                  "on",
                  "off"
                ],
                "default": "on",
                "description": "`on` shows the indicator and also marks the conversation read. `off` clears it on Instagram; WhatsApp has no such call, so it is accepted as a no-op with a warning — the indicator clears when you send a message or after 25 seconds."
              }
            }
          }
        ]
      },
      "ActionResponse": {
        "type": "object",
        "required": [
          "success"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "state": {
            "type": "string",
            "enum": [
              "on",
              "off"
            ],
            "description": "Typing only: the state that was applied."
          },
          "dry_run": {
            "type": "boolean",
            "description": "Present and true when Meta was not called."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Present when the channel could not do part of what was asked — typing off on WhatsApp, for example. Nothing needs retrying."
          },
          "hint": {
            "type": "string",
            "description": "Present on a simulated test-key call — explains that only registered test recipients are reached for real."
          }
        }
      },
      "SessionRequest": {
        "type": "object",
        "required": [
          "client_ref"
        ],
        "properties": {
          "client_ref": {
            "type": "string",
            "description": "Stable, unique identifier from your own system."
          }
        }
      },
      "SessionResponse": {
        "type": "object",
        "required": [
          "session_id",
          "url",
          "expires_in"
        ],
        "properties": {
          "session_id": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "expires_in": {
            "type": "integer",
            "const": 600
          }
        }
      },
      "ClientSignupRequest": {
        "type": "object",
        "required": [
          "client_ref",
          "auth_code"
        ],
        "description": "Advanced Meta signup completion. Most integrations should use the hosted session flow.",
        "properties": {
          "client_ref": {
            "type": "string"
          },
          "auth_code": {
            "type": "string"
          }
        }
      },
      "Client": {
        "type": "object",
        "required": [
          "client_ref",
          "channel"
        ],
        "additionalProperties": true,
        "properties": {
          "client_ref": {
            "type": "string"
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp",
              "instagram"
            ]
          },
          "business_name": {
            "type": "string"
          },
          "phone_number": {
            "type": "string"
          },
          "phone_number_id": {
            "type": "string"
          },
          "waba_id": {
            "type": "string"
          }
        }
      },
      "ClientUpdateRequest": {
        "type": "object",
        "minProperties": 1,
        "description": "Rename a client (client_ref) and/or relabel it (business_name). Pass only what changes.",
        "properties": {
          "client_ref": {
            "type": "string",
            "maxLength": 255,
            "description": "New reference. Unique per partner and used as a URL path segment, so it cannot contain \"/\". Takes effect immediately: the old reference stops resolving and later webhooks carry the new one — update your own mapping first."
          },
          "business_name": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name shown in the portal and returned on the client. Filled by Meta at onboarding (phone number or Instagram handle) until you set it."
          }
        }
      },
      "UsagePeriod": {
        "type": "object",
        "required": [
          "period",
          "inbound_messages",
          "outbound_messages",
          "outbound_template_messages",
          "total_messages"
        ],
        "properties": {
          "period": {
            "type": "string",
            "examples": [
              "2026-07"
            ]
          },
          "inbound_messages": {
            "type": "integer"
          },
          "outbound_messages": {
            "type": "integer"
          },
          "outbound_template_messages": {
            "type": "integer"
          },
          "total_messages": {
            "type": "integer"
          }
        }
      },
      "UsageResponse": {
        "type": "object",
        "required": [
          "current",
          "history"
        ],
        "properties": {
          "current": {
            "$ref": "#/components/schemas/UsagePeriod"
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsagePeriod"
            }
          }
        }
      },
      "TemplateHeader": {
        "type": "object",
        "description": "Optional header. Media formats need either media_handle (from POST /v1/templates/media) or media_url, which Intelli downloads and uploads to Meta for you.",
        "properties": {
          "format": {
            "type": "string",
            "enum": [
              "TEXT",
              "IMAGE",
              "VIDEO",
              "DOCUMENT",
              "LOCATION"
            ]
          },
          "text": {
            "type": "string",
            "description": "TEXT headers only. May contain a single {{1}}."
          },
          "examples": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "media_handle": {
            "type": "string"
          },
          "media_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "TemplateButton": {
        "type": "object",
        "required": [
          "type",
          "text"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "QUICK_REPLY",
              "URL",
              "PHONE_NUMBER",
              "COPY_CODE",
              "OTP"
            ]
          },
          "text": {
            "type": "string",
            "maxLength": 25
          },
          "url": {
            "type": "string",
            "description": "URL buttons. A trailing {{1}} may be appended at send time."
          },
          "example": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "phone_number": {
            "type": "string",
            "description": "PHONE_NUMBER buttons."
          }
        }
      },
      "CreateTemplateRequest": {
        "type": "object",
        "required": [
          "client_ref",
          "name",
          "body"
        ],
        "description": "Either supply header/body/footer/buttons and let Intelli assemble Meta's payload, or pass a raw `components` array if you already build it yourself. `components` takes precedence.",
        "properties": {
          "client_ref": {
            "type": "string",
            "description": "The client whose WhatsApp Business Account owns the template."
          },
          "name": {
            "type": "string",
            "description": "Normalized to lower_snake_case. Must be unique per language for the client.",
            "examples": [
              "order_update"
            ]
          },
          "language": {
            "type": "string",
            "default": "en_US"
          },
          "category": {
            "type": "string",
            "enum": [
              "MARKETING",
              "UTILITY",
              "AUTHENTICATION"
            ],
            "default": "MARKETING"
          },
          "header": {
            "$ref": "#/components/schemas/TemplateHeader"
          },
          "body": {
            "type": "object",
            "required": [
              "text"
            ],
            "properties": {
              "text": {
                "type": "string",
                "maxLength": 1024
              },
              "examples": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "One sample per {{n}} placeholder. Meta rejects templates whose placeholders have no example, so missing entries are auto-filled."
              }
            }
          },
          "footer": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string",
                "maxLength": 60
              }
            }
          },
          "buttons": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/TemplateButton"
            }
          },
          "components": {
            "type": "array",
            "description": "Raw Meta component array. Overrides the fields above.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "Template": {
        "type": "object",
        "required": [
          "id",
          "client_ref",
          "name",
          "language",
          "status"
        ],
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Meta's template id. Use it as {template_ref}."
          },
          "client_ref": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "language": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "APPROVED",
              "REJECTED",
              "PAUSED",
              "DISABLED",
              "IN_APPEAL",
              "FLAGGED"
            ],
            "description": "Only APPROVED templates can be sent."
          },
          "rejected_reason": {
            "type": [
              "string",
              "null"
            ],
            "description": "Meta's reason. Non-null only when status is REJECTED."
          },
          "template_type": {
            "type": "string"
          },
          "components": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "variables": {
            "type": "object",
            "description": "Placeholders each component expects, so you know what to supply on send.",
            "properties": {
              "header": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "body": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "buttons": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "TemplateList": {
        "type": "object",
        "required": [
          "results",
          "count"
        ],
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Template"
            }
          },
          "count": {
            "type": "integer"
          },
          "warning": {
            "type": "string",
            "description": "Present when Meta could not be reached to refresh and the last known state is being served."
          }
        }
      },
      "TemplateMediaResponse": {
        "type": "object",
        "required": [
          "handle",
          "format"
        ],
        "properties": {
          "handle": {
            "type": "string",
            "description": "Pass as header.media_handle when creating a template."
          },
          "format": {
            "type": "string",
            "enum": [
              "IMAGE",
              "VIDEO",
              "DOCUMENT"
            ]
          },
          "filename": {
            "type": "string"
          },
          "size": {
            "type": "integer"
          }
        }
      }
    }
  },
  "paths": {
    "/media": {
      "post": {
        "operationId": "uploadSendMedia",
        "summary": "Upload send media",
        "description": "Upload media to a client's WhatsApp number and get back the media id sends can reference — header.id on a template send, image.id and friends on a free-form message. Meta keeps it 30 days, so one upload serves many sends; prefer an id over link in production, since link is re-fetched by Meta at every delivery and fails it silently when unreachable. WhatsApp-only: Instagram takes media as a public URL on the send itself.",
        "tags": [
          "Messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "client_ref",
                  "file"
                ],
                "properties": {
                  "client_ref": {
                    "type": "string"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "image/jpeg or png (≤5 MB), video/mp4 or 3gpp (≤16 MB), audio aac/mp4/mpeg/amr/ogg (≤16 MB), documents pdf/Office/txt (≤100 MB), sticker webp (≤500 KB)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Uploaded — reference media_id from sends.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "media_id"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "media_id": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string",
                      "description": "What WhatsApp classified the upload as: image, video, audio, document or sticker."
                    },
                    "expires_in_days": {
                      "type": "integer",
                      "const": 30
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unsupported media type, file too large, or the client is not a WhatsApp client.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing messages:send scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Meta rejected the upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "messages:send"
            ]
          }
        ]
      }
    },
    "/media/{media_id}": {
      "get": {
        "operationId": "downloadMedia",
        "summary": "Download inbound media",
        "description": "Stream media a customer sent in. WhatsApp names inbound media by id only and resolving it needs the client's Meta credentials, which partners never hold — call this instead. Instagram does not need it: its webhooks already carry a fetchable URL at attachments[].payload.url, short-lived, so download on receipt. Meta keeps inbound media for 30 days.",
        "tags": [
          "Messages"
        ],
        "parameters": [
          {
            "name": "media_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The id from the webhook, e.g. messages[].image.id."
          },
          {
            "name": "client_ref",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Which of your clients received the media. Selects the credentials used to fetch it."
          }
        ],
        "responses": {
          "200": {
            "description": "The file, streamed with its real Content-Type. X-Media-Sha256 carries the checksum to verify against the webhook.",
            "headers": {
              "X-Media-Sha256": {
                "description": "SHA-256 of the file as reported by Meta.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "client_ref missing (client_ref_required), or the client's channel delivers media inline (channel_media_inline).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing clients:read scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client_ref, or Meta does not recognise the media id for this client (media_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "The client has no channel credentials on file.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Meta was unreachable or refused the download.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "clients:read"
            ]
          }
        ]
      }
    },
    "/messages/send": {
      "post": {
        "operationId": "sendMessage",
        "summary": "Send a free-form message",
        "description": "Send a Meta-compatible payload through the channel connected to client_ref. WhatsApp carries every type below. Instagram carries text, image, video, audio and document — media must be a public HTTPS URL in <type>.link, since Instagram fetches the file itself and cannot use an uploaded media id (code media_link_required); caption and filename are returned in `warnings` because an Instagram attachment has nowhere to put them. Templates, sticker, location, contacts, interactive and reaction are WhatsApp-only (code channel_type_unsupported).",
        "tags": [
          "Messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message accepted or dry-run validated.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing messages:send scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client_ref.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Channel provider rejected the message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "messages:send"
            ]
          }
        ]
      }
    },
    "/messages/send-template": {
      "post": {
        "operationId": "sendTemplateMessage",
        "summary": "Send a WhatsApp template",
        "tags": [
          "Messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template send accepted or dry-run validated.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing messages:send scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client or template.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Channel provider rejected the message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "description": "Send an approved WhatsApp template, which can open a conversation outside the 24-hour service window. Reference a template from the Templates API by template_ref and pass plain parameter values, or send a raw Meta template object instead. Templates that Meta has not approved return template_not_approved.",
        "security": [
          {
            "bearerAuth": [
              "messages:send"
            ]
          }
        ]
      }
    },
    "/messages/read": {
      "post": {
        "operationId": "markMessageRead",
        "summary": "Send a read receipt",
        "description": "Mark a customer's message as read through the client connected to client_ref — the blue ticks on WhatsApp, \"Seen\" on Instagram. WhatsApp attaches the receipt to one inbound message, so message_id (the wamid from your message.received webhook) is required there (code message_id_required); a message you sent cannot be marked read and comes back as 422 meta_rejected. Instagram marks the whole conversation with `to` as seen and ignores message_id. Creates no message and never counts toward usage.",
        "tags": [
          "Messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MarkReadRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Receipt sent or dry-run validated.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, or message_id missing on WhatsApp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing messages:send scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client_ref.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Channel provider rejected the request — typically a message_id that is not an inbound message of this client.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "messages:send"
            ]
          }
        ]
      }
    },
    "/messages/typing": {
      "post": {
        "operationId": "setTypingIndicator",
        "summary": "Show or clear the typing indicator",
        "description": "Show the typing indicator in a customer's thread while you prepare a reply. Turning it on also marks the conversation read on both channels: WhatsApp only shows the bubble on a message being marked read, so message_id is required there, and the bubble clears by itself when you send a message or after 25 seconds. Instagram marks the thread seen, then shows typing. `state: off` sends typing_off on Instagram and is accepted as a no-op with a warning on WhatsApp, which has no such call. Only show typing when a reply is actually coming. Creates no message and never counts toward usage.",
        "tags": [
          "Messages"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TypingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Indicator state applied or dry-run validated.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request, or message_id missing on WhatsApp.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing messages:send scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client_ref.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Channel provider rejected the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "502": {
            "description": "Upstream unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "messages:send"
            ]
          }
        ]
      }
    },
    "/embedded-signup/sessions": {
      "post": {
        "operationId": "createWhatsAppSignupSession",
        "summary": "Create a hosted WhatsApp signup session",
        "description": "Returns a single-use Intelli-hosted URL valid for 10 minutes.",
        "tags": [
          "Clients"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing clients:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Client reference or number is already connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "clients:write"
            ]
          }
        ]
      }
    },
    "/instagram-connect/sessions": {
      "post": {
        "operationId": "createInstagramConnectSession",
        "summary": "Create a hosted Instagram connect session",
        "description": "Returns a single-use Intelli-hosted URL valid for 10 minutes.",
        "tags": [
          "Clients"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session created.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing clients:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Client reference or account is already connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "clients:write"
            ]
          }
        ]
      }
    },
    "/clients": {
      "get": {
        "operationId": "listClients",
        "summary": "List connected clients",
        "tags": [
          "Clients"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1
            },
            "description": "Maximum number of records to return."
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Number of records to skip before the first returned record."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated client records.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Client"
                      }
                    },
                    {
                      "type": "object",
                      "additionalProperties": true
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing clients:read scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "description": "List the clients connected to your partner account, newest first, with each client's channel and client_ref. Page through results with limit and offset.",
        "security": [
          {
            "bearerAuth": [
              "clients:read"
            ]
          }
        ]
      }
    },
    "/clients/{client_ref}": {
      "get": {
        "operationId": "getClient",
        "summary": "Get a client by reference",
        "tags": [
          "Clients"
        ],
        "parameters": [
          {
            "name": "client_ref",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your stable identifier for the connected client and channel."
          }
        ],
        "responses": {
          "200": {
            "description": "Connected client.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Client"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing clients:read scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client_ref.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "description": "Get one connected client by your client_ref. Call this server-to-server after hosted onboarding completes to confirm the connection before enabling sends.",
        "security": [
          {
            "bearerAuth": [
              "clients:read"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "updateClient",
        "summary": "Rename or relabel a client",
        "description": "Change a client's reference and/or display name after onboarding. A rename takes effect immediately — the old client_ref stops resolving and every later webhook carries the new one, so update your own mapping first. Nothing else moves: sends, templates, usage and delivery logs stay attached to the client. A reference already used by another of your clients returns 409 client_ref_exists.",
        "tags": [
          "Clients"
        ],
        "parameters": [
          {
            "name": "client_ref",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The client's current reference."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated client.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Client"
                }
              }
            }
          },
          "400": {
            "description": "Blank value, a \"/\" in client_ref, or nothing to change.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing clients:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Unknown client_ref.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "The new client_ref is already used by another of your clients (client_ref_exists).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "clients:write"
            ]
          }
        ]
      }
    },
    "/clients/signup": {
      "post": {
        "operationId": "completeWhatsAppSignup",
        "summary": "Complete a Meta signup code exchange",
        "description": "Advanced endpoint used to complete Meta Embedded Signup. Most integrations should use /embedded-signup/sessions.",
        "tags": [
          "Clients"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientSignupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Client connected.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Client"
                }
              }
            }
          },
          "400": {
            "description": "Invalid code or request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing clients:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Client or number is already connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "clients:write"
            ]
          }
        ]
      }
    },
    "/templates": {
      "get": {
        "operationId": "listTemplates",
        "summary": "List a client's message templates",
        "description": "Templates are registered per client WhatsApp Business Account, so client_ref is required. Results are served from Intelli's mirror of the WABA, refreshed from Meta when it goes stale; pass refresh=true to force a pull.",
        "tags": [
          "Templates"
        ],
        "parameters": [
          {
            "name": "client_ref",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your stable identifier for the connected client and channel."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "APPROVED",
                "REJECTED",
                "PAUSED",
                "DISABLED"
              ]
            },
            "description": "Only return templates with this Meta review status."
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "MARKETING",
                "UTILITY",
                "AUTHENTICATION"
              ]
            },
            "description": "Only return templates in this Meta category."
          },
          {
            "name": "language",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Template language code (for example en_US), used to pick between templates that share a name."
          },
          {
            "name": "search",
            "in": "query",
            "description": "Case-insensitive match on the template name.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "refresh",
            "in": "query",
            "description": "Force a pull from Meta before responding.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The client's templates.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateList"
                }
              }
            }
          },
          "400": {
            "description": "client_ref is missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing templates:read scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Client not found or inactive.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "templates:read"
            ]
          }
        ]
      },
      "post": {
        "operationId": "createTemplate",
        "summary": "Submit a template for review",
        "description": "Creates the template on the client's WhatsApp Business Account. It comes back with status PENDING — Meta reviews asynchronously and only APPROVED templates can be sent. Listen for the `template.status` webhook, or poll GET /templates/{template_ref}.",
        "tags": [
          "Templates"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Template submitted for review.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "Meta rejected the template, or the payload is invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing templates:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Client not found or inactive.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "A template with this name and language already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "templates:write"
            ]
          }
        ]
      }
    },
    "/templates/media": {
      "post": {
        "operationId": "uploadTemplateMedia",
        "summary": "Upload header media",
        "description": "Uploads a sample image, video or document and returns a handle to pass as header.media_handle. Only needed when you hold the bytes — if the file already sits on a public URL, pass header.media_url on the create instead.",
        "tags": [
          "Templates"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "client_ref",
                  "file"
                ],
                "properties": {
                  "client_ref": {
                    "type": "string"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "IMAGE",
                      "VIDEO",
                      "DOCUMENT"
                    ],
                    "description": "Inferred from the file's content type when omitted."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Media uploaded.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateMediaResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing file, unsupported type, or over the size limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing templates:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "templates:write"
            ]
          }
        ]
      }
    },
    "/templates/{template_ref}": {
      "parameters": [
        {
          "name": "template_ref",
          "in": "path",
          "required": true,
          "description": "Meta's template id, or the template name — add ?language= when the name exists in several languages.",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "client_ref",
          "in": "query",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Your stable identifier for the connected client and channel."
        },
        {
          "name": "language",
          "in": "query",
          "schema": {
            "type": "string"
          },
          "description": "Template language code (for example en_US), used to pick between templates that share a name."
        }
      ],
      "get": {
        "operationId": "getTemplate",
        "summary": "Get a template and its review status",
        "description": "Poll this to follow a template through review if you'd rather not consume the `template.status` webhook.",
        "tags": [
          "Templates"
        ],
        "parameters": [
          {
            "name": "refresh",
            "in": "query",
            "description": "Force a pull from Meta before responding.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The template.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing templates:read scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Template or client not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "The name matches several languages — pass ?language=.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "templates:read"
            ]
          }
        ]
      },
      "patch": {
        "operationId": "updateTemplate",
        "summary": "Edit a template",
        "description": "Updates the template's components on Meta, which sends it back through review. Name and language are immutable — create a new template to change either. Meta limits how often an approved template may be edited.",
        "tags": [
          "Templates"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template updated and resubmitted for review.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Template"
                }
              }
            }
          },
          "400": {
            "description": "Meta rejected the edit, or name/language was changed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing templates:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Template or client not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "The template is in a state Meta will not accept edits for.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "templates:write"
            ]
          }
        ]
      },
      "delete": {
        "operationId": "deleteTemplate",
        "summary": "Delete a template",
        "description": "Deletes the template from the client's WhatsApp Business Account. Sends referencing it will fail afterwards. Meta blocks re-using the same name for 30 days.",
        "tags": [
          "Templates"
        ],
        "responses": {
          "204": {
            "description": "Template deleted."
          },
          "400": {
            "description": "Meta refused the delete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "402": {
            "description": "Trial or subscription has ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Missing templates:write scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Template or client not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Billing access could not be verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": [
              "templates:write"
            ]
          }
        ]
      }
    },
    "/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Get monthly message usage",
        "description": "Returns the current UTC month and recent closed months. Test-key and dry-run traffic is excluded.",
        "tags": [
          "Usage"
        ],
        "responses": {
          "200": {
            "description": "Usage rollups.",
            "headers": {
              "X-Request-Id": {
                "description": "Opaque request correlation ID.",
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Edge request ceiling for the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current edge window.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/status": {
      "get": {
        "operationId": "getStatus",
        "summary": "Probe public API edge health and version",
        "tags": [
          "Platform"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The API edge is reachable.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "version"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "const": "ok"
                    },
                    "version": {
                      "type": "string",
                      "const": "v1"
                    }
                  }
                }
              }
            }
          }
        },
        "description": "Check that the public API edge is reachable and which API version it serves. This endpoint is public and needs no API key."
      }
    }
  }
}