{
  "info": {
    "name": "ChatRail API",
    "description": "Send, schedule and receive WhatsApp messages through a linked-device session.\n\n**Two things the API is careful about, which shape every endpoint below.**\n\n*Accepted is not delivered.* A 202 means the message is durably stored and queued. Only the `status` field ever claims WhatsApp delivered anything, and `queued`, `submitted`, `sent`, `delivered` and `read` are deliberately distinct.\n\n*A retry must not send twice.* Send `Idempotency-Key` on every send. A replay returns the original response; a concurrent duplicate is told to retry rather than allowed to race.\n\nGenerated from the OpenAPI document; do not edit.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.chatrail.dev"
    },
    {
      "key": "api_key",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Messages",
      "description": "Sending, delivery state and export.",
      "item": [
        {
          "name": "Send a message",
          "description": "Accepts a message for delivery and returns 202. **202 means accepted, never delivered** — the message is durably stored and queued, and only the `status` field ever claims delivery. Send `media` or `location` for an attachment, `send_at` to defer it. Supply `Idempotency-Key` so a retry cannot send twice.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/messages/text",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "messages",
                "text"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"connection\": \"main\",\n  \"to\": \"+15551234567\",\n  \"body\": \"Order CR-2048 has shipped.\",\n  \"context\": {\n    \"order_id\": \"CR-2048\",\n    \"status\": \"dispatched\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "List messages",
          "description": "Newest first, cursor paginated. Offsets are not offered: they skip and duplicate.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/messages?",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "messages"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "connection",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "direction",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Get a message",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/messages/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "messages",
                ":id"
              ]
            }
          }
        },
        {
          "name": "Cancel a message",
          "description": "Only while it has not reached the provider. Once submitted the message exists on somebody's phone and cancelling would be a lie.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/messages/:id/cancel",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "messages",
                ":id",
                "cancel"
              ]
            }
          }
        },
        {
          "name": "Move a scheduled message",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/messages/:id/reschedule",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "messages",
                ":id",
                "reschedule"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"send_at\": \"2026-10-01T09:00:00Z\",\n  \"timezone\": \"Europe/London\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Export delivery metadata as CSV",
          "description": "Streamed row by row. **Message bodies are not included** — this is delivery metadata, not content.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/messages/export?",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "messages",
                "export"
              ],
              "query": [
                {
                  "key": "connection",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "direction",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "days",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Check whether a number is on WhatsApp",
          "description": "Answers `checked: false` when the engine cannot say. Treat that as \"send anyway\": refusing a message because a check failed turns a missing provider feature into a delivery failure.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/numbers/check?",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "numbers",
                "check"
              ],
              "query": [
                {
                  "key": "phone",
                  "value": "",
                  "disabled": true
                },
                {
                  "key": "connection",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Connections",
      "description": "WhatsApp numbers and their pairing lifecycle.",
      "item": [
        {
          "name": "Create a connection",
          "description": "Returns `callback_token` **exactly once**. It cannot be retrieved again; store it when you receive it.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"slug\": \"operations\",\n  \"name\": \"Operations line\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "List connections",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections"
              ]
            }
          }
        },
        {
          "name": "Get a connection",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections/:connection",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections",
                ":connection"
              ]
            }
          }
        },
        {
          "name": "Delete a connection",
          "description": "Soft deletes it and queues removal of its data.",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections/:connection",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections",
                ":connection"
              ]
            }
          }
        },
        {
          "name": "Begin pairing",
          "description": "Issues a short-lived, single-use QR grant. The QR itself is fetched with the grant id — it is a pairing credential, so anyone who scans it links *their* device to the number.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections/:connection/pair",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections",
                ":connection",
                "pair"
              ]
            }
          }
        },
        {
          "name": "Redeem a QR grant",
          "description": "Single use. A redeemed or expired grant is gone; ask for another.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections/:connection/qr/:grantId",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections",
                ":connection",
                "qr",
                ":grantId"
              ]
            }
          }
        },
        {
          "name": "Suspend a connection",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections/:connection/suspend",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections",
                ":connection",
                "suspend"
              ]
            }
          }
        },
        {
          "name": "Resume a suspended connection",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/connections/:connection/resume",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "connections",
                ":connection",
                "resume"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Schedules",
      "description": "Recurring sends.",
      "item": [
        {
          "name": "Create a recurring schedule",
          "description": "Daily, weekly or monthly, resolved in the given IANA timezone. A schedule that fell behind fires once and drops the backlog rather than delivering days of stale messages.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/schedules",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "schedules"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Friday digest\",\n  \"timezone\": \"Europe/London\",\n  \"recurrence\": {\n    \"type\": \"weekly\",\n    \"hour\": 9,\n    \"minute\": 0,\n    \"days_of_week\": [\n      5\n    ]\n  },\n  \"message\": {\n    \"connection\": \"main\",\n    \"to\": \"+15551234567\",\n    \"body\": \"Your weekly digest is ready.\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "List schedules",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/schedules?",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "schedules"
              ],
              "query": [
                {
                  "key": "status",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Get a schedule",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/schedules/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "schedules",
                ":id"
              ]
            }
          }
        },
        {
          "name": "Pause a schedule",
          "description": "Keeps the schedule and stops it firing.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/schedules/:id/pause",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "schedules",
                ":id",
                "pause"
              ]
            }
          }
        },
        {
          "name": "Resume a schedule",
          "description": "The next run is computed from now. A schedule paused for a month does not fire the month it missed.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/schedules/:id/resume",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "schedules",
                ":id",
                "resume"
              ]
            }
          }
        },
        {
          "name": "Cancel a schedule",
          "description": "Permanent. A cancelled schedule cannot be restarted.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/schedules/:id/cancel",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "schedules",
                ":id",
                "cancel"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Webhooks",
      "description": "Where inbound events and delivery updates are sent.",
      "item": [
        {
          "name": "Register a webhook endpoint",
          "description": "Returns the signing secret **exactly once**. Every delivery is signed with HMAC-SHA256 over `${timestamp}.${rawBody}`; verify it and reject stale timestamps. The URL is validated at registration and the connection pinned at delivery, so an endpoint pointing at a private address is refused.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/webhook-endpoints",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhook-endpoints"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://example.com/hooks/chatrail\",\n  \"events\": [\n    \"message.received\",\n    \"message.delivered\",\n    \"message.failed\"\n  ],\n  \"description\": \"Order updates\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "List webhook endpoints",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/webhook-endpoints",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhook-endpoints"
              ]
            }
          }
        },
        {
          "name": "Delete a webhook endpoint",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/webhook-endpoints/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "webhook-endpoints",
                ":id"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "AI",
      "description": "Optional, per connection, off by default.",
      "item": [
        {
          "name": "Store a model provider credential",
          "description": "Encrypted at rest and never returned. AI is off by default and enabled per connection.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/ai/credentials",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "ai",
                "credentials"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"provider\": \"anthropic\",\n  \"label\": \"Production key\",\n  \"api_key\": \"sk-ant-replace-with-your-own-key\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "List credentials",
          "description": "Fingerprints and metadata only; the key itself is never returned.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/ai/credentials",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "ai",
                "credentials"
              ]
            }
          }
        },
        {
          "name": "Delete a credential",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/ai/credentials/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "ai",
                "credentials",
                ":id"
              ]
            }
          }
        },
        {
          "name": "Set the AI policy for a connection",
          "description": "Draft or auto mode, with token, rate and monthly cost ceilings. Absent policy means AI is off for that connection.",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/ai/policies/:connection",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "ai",
                "policies",
                ":connection"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"credential_id\": \"019bf4a1-0000-7000-8000-000000000000\",\n  \"enabled\": true,\n  \"mode\": \"draft\",\n  \"model\": \"claude-sonnet-4-5\",\n  \"system_instruction\": \"Answer only from the attached context. If the answer is not there, say so.\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Get the AI policy for a connection",
          "description": "Absent policy means AI is off for that connection, which is the default.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/ai/policies/:connection",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "ai",
                "policies",
                ":connection"
              ]
            }
          }
        },
        {
          "name": "List AI runs",
          "description": "Prompt hashes, usage, cost and outcome. Never prompt or completion text.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/ai/runs",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "ai",
                "runs"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Team",
      "description": "Membership and invitations. Dashboard sessions only.",
      "item": [
        {
          "name": "List members and pending invitations",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/members",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "members"
              ]
            }
          }
        },
        {
          "name": "Invite somebody",
          "description": "Emails a single-use link bound to that address. The token is never returned in the response. Nobody may invite to a role above their own.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/members/invitations",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "members",
                "invitations"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"colleague@company.com\",\n  \"role\": \"viewer\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Revoke an invitation",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/members/invitations/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "members",
                "invitations",
                ":id"
              ]
            }
          }
        },
        {
          "name": "Accept an invitation",
          "description": "Requires a signed-in session whose address matches the invited one. Possessing the token is not enough — a forwarded invitation email must not be a way into a workspace.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/members/accept",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "members",
                "accept"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"token\": \"the token from the invitation link\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Change a member's role",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/members/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "members",
                ":id"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"role\": \"developer\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Remove a member",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/members/:id",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "members",
                ":id"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Workspace",
      "description": "Identity, credentials, plan and usage.",
      "item": [
        {
          "name": "Confirm a credential",
          "description": "Shows exactly what the presented credential can do. The first call to make.",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/whoami",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "whoami"
              ]
            }
          }
        },
        {
          "name": "Get the current workspace",
          "description": "Includes the plan and what has been used against it.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/workspace",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "workspace"
              ]
            }
          }
        },
        {
          "name": "Usage counts",
          "description": "Counts only. A count of messages is not a message; no content is reachable here.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/usage?",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "usage"
              ],
              "query": [
                {
                  "key": "days",
                  "value": "",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Issue an API key",
          "description": "Returns the key **exactly once**. It is stored only as a hash and cannot be recovered. A key may never hold more than the person issuing it.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/api-keys",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "api-keys"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"name\": \"Order service\",\n  \"scopes\": [\n    \"messages:write\",\n    \"messages:read\"\n  ],\n  \"environment\": \"live\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "List API keys",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/api-keys",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "api-keys"
              ]
            }
          }
        },
        {
          "name": "Revoke an API key",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/api-keys/:id/revoke",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "api-keys",
                ":id",
                "revoke"
              ]
            }
          }
        },
        {
          "name": "Rotate an API key",
          "description": "Issues a replacement and revokes the old one.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/api-keys/:id/rotate",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "api-keys",
                ":id",
                "rotate"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Auth",
      "description": "Dashboard sign-in. Not used by API clients.",
      "item": [
        {
          "name": "Request a sign-in code",
          "description": "Always answers 202, whether or not the address has an account. It is not an existence check and must not be presented as one.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/auth/request-code",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "auth",
                "request-code"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"you@company.com\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Exchange a code for a session",
          "description": "Every failure returns the same error — no code, wrong code, expired, too many attempts. Distinguishing them would reintroduce an oracle.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/auth/verify",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "auth",
                "verify"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"you@company.com\",\n  \"code\": \"123456\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Read the current session",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/auth/session",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "auth",
                "session"
              ]
            }
          }
        },
        {
          "name": "End the session",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/auth/logout",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "auth",
                "logout"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "MCP",
      "description": "Workspace tools for a coding assistant.",
      "item": [
        {
          "name": "MCP endpoint",
          "description": "Model Context Protocol over a stateless streamable HTTP transport. Read-only by default; mutating tools preview and apply only when called again with `confirm: true`. No tool returns message content.",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/mcp",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "mcp"
              ]
            }
          }
        },
        {
          "name": "List MCP tools",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Authorization",
                "value": "Bearer {{api_key}}",
                "type": "text"
              }
            ],
            "url": {
              "raw": "{{base_url}}/v1/mcp/tools",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "mcp",
                "tools"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Operational",
      "description": "Health and metrics.",
      "item": [
        {
          "name": "Liveness",
          "description": "Never checks dependencies. Point a restart policy here, not a traffic probe.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/healthz",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "healthz"
              ]
            }
          }
        },
        {
          "name": "Readiness",
          "description": "Checks dependencies. Point the load balancer here.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/readyz",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "readyz"
              ]
            }
          }
        },
        {
          "name": "Prometheus metrics",
          "description": "Not registered unless `METRICS_TOKEN` is configured. No label carries a workspace, connection, number or session name.",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/metrics",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "metrics"
              ]
            }
          }
        },
        {
          "name": "This document",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/openapi.json",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "openapi.json"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Internal",
      "description": "Called by the transport, not by you.",
      "item": [
        {
          "name": "Provider callback",
          "description": "Called by the WhatsApp transport, not by you. Authenticated by the per-connection token returned once when the connection was created. Redeliveries are deduplicated.",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/v1/provider/:providerName/:token",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "v1",
                "provider",
                ":providerName",
                ":token"
              ]
            }
          }
        }
      ]
    }
  ]
}
