{
  "openapi": "3.1.0",
  "info": {
    "title": "Inboxr API",
    "version": "1",
    "description": "Disposable inboxes for developers, CI, and AI agents — email, SMS, and (soon) voice. Every endpoint takes a Bearer key from https://app.getinboxr.app/api-keys. SMS endpoints additionally require positive credit balance — buy credits at https://app.getinboxr.app/sms/inboxes (Stripe). 1 credit per SMS in or out. For an interactive playground: https://app.getinboxr.app/docs/api.",
    "contact": {
      "url": "https://getinboxr.app"
    },
    "license": {
      "name": "Commercial",
      "url": "https://getinboxr.app/terms"
    }
  },
  "servers": [
    {
      "url": "https://api.getinboxr.app",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Inboxes",
      "description": "Provision, list, delete, and long-poll email inboxes."
    },
    {
      "name": "Messages",
      "description": "Read inbound mail; send outbound mail."
    },
    {
      "name": "SMS",
      "description": "Phone-number-backed inboxes: send + receive SMS, stake sender claims, long-poll for replies, extract OTPs."
    },
    {
      "name": "Voice",
      "description": "Place outbound calls, drive IVR flows, fetch recordings + voicemail transcripts. (Coming.)"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "inb_live_<24 base62>",
        "description": "Generate a key at https://app.getinboxr.app/api-keys. Scopes: read | write | admin (admin ⊃ write ⊃ read)."
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/inboxes": {
      "get": {
        "operationId": "list_inboxes",
        "summary": "List your inboxes",
        "description": "Returns every inbox in the calling tenant. Cheap — paginate by ignoring this and using individual GETs if you grow past a few hundred.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, address, label, createdAt, expiresAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "post": {
        "operationId": "create_inbox",
        "summary": "Create a new inbox",
        "description": "Provisions a real disposable address on the engine. Label is optional; if omitted, a random GUID becomes the local-part.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "label": {
                    "description": "Local-part prefix. Lowercase letters, digits, dot/underscore/dash. Max 64.",
                    "type": "string"
                  },
                  "domain": {
                    "description": "Restrict to a domain you have access to. Defaults to getinboxr.app.",
                    "type": "string"
                  },
                  "webhookUrl": {
                    "description": "Optional per-inbox webhook for new mail.",
                    "type": "string"
                  }
                },
                "example": {
                  "label": "signup-test",
                  "domain": "getinboxr.app"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, address, label, guid, createdAt, expiresAt }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/inboxes/{id}": {
      "get": {
        "operationId": "get_inbox",
        "summary": "Get one inbox",
        "description": "Fetch a single inbox by ID. 404 if it does not belong to the calling tenant.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox UUID returned at creation.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, address, label, createdAt, expiresAt }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "delete": {
        "operationId": "delete_inbox",
        "summary": "Delete an inbox",
        "description": "Removes the mailbox on the engine and clears cached message metadata. Irreversible.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox UUID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/inboxes/{id}/smtp-credentials": {
      "post": {
        "operationId": "smtp_credentials",
        "summary": "Issue SMTP submission credentials",
        "description": "Generates a fresh SMTP username + password for this inbox so you can send via mail.<domain>:587 (STARTTLS) instead of POST /v1/messages. Calling again rotates the credential. Plaintext is shown once — save it. Only works on REAL mailboxes (exact address on a domain you control); disposable inboxes have no IMAP/SMTP login and return 409 not_a_mailbox.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "admin"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox UUID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ host, port, secure, username, password, url, notes }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/inboxes/{id}/wait": {
      "get": {
        "operationId": "wait_for_mail",
        "summary": "Long-poll for the next message",
        "description": "Blocks up to 30 seconds waiting for a new message in the inbox. Ideal for CI flows that need a verification email and would otherwise busy-poll.",
        "tags": [
          "Inboxes"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox UUID.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timeout",
            "in": "query",
            "required": false,
            "description": "Seconds to wait, max 30. Default 30.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "description": "Only return messages received after this ISO timestamp.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ message: { uid, from, subject, ... } | null }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/messages": {
      "get": {
        "operationId": "list_messages",
        "summary": "List recent messages",
        "description": "Tenant-wide inbound mail listing, newest first. Use the inbox filter to narrow down.",
        "tags": [
          "Messages"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "inbox",
            "in": "query",
            "required": false,
            "description": "Inbox UUID to filter by.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1..200, default 50.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ uid, inboxId, from, subject, receivedAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "post": {
        "operationId": "send_message",
        "summary": "Send an outbound message",
        "description": "Outbound via SES relay. From: must be on a domain enabled on the engine. Recorded in your outbound history regardless of success.",
        "tags": [
          "Messages"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "from",
                  "to",
                  "subject"
                ],
                "properties": {
                  "from": {
                    "description": "Sender address. Domain must be SES-verified for your tenant.",
                    "type": "string"
                  },
                  "to": {
                    "description": "One address or an array.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "subject": {
                    "description": "Plain text subject.",
                    "type": "string"
                  },
                  "text": {
                    "description": "Plain-text body. Either text or html is required.",
                    "type": "string"
                  },
                  "html": {
                    "description": "HTML body.",
                    "type": "string"
                  },
                  "cc": {
                    "description": "CC list.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "bcc": {
                    "description": "BCC list.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "from": "noreply@getinboxr.app",
                  "to": "someone@example.com",
                  "subject": "Hi from Inboxr",
                  "text": "Test message body."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ ok, outboundId, messageId }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/messages/{uid}": {
      "get": {
        "operationId": "get_message",
        "summary": "Get one message (full body)",
        "description": "Returns full text + sanitized HTML + attachments metadata. Use the attachment download URL for binaries.",
        "tags": [
          "Messages"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "uid",
            "in": "path",
            "required": true,
            "description": "Engine UID returned by list_messages.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "The inbox domain (e.g. getinboxr.app). Required because UIDs are scoped per-mailbox.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ uid, from, subject, textBody, htmlBody, attachments: [...] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/messages/{uid}/attachments/{idx}": {
      "get": {
        "operationId": "get_attachment",
        "summary": "Download an attachment",
        "description": "Streams one attachment’s raw bytes (up to 20 MB; larger returns 413). Get the idx + metadata from GET /v1/messages/{uid}. Add download=1 to force a file download rather than inline preview.",
        "tags": [
          "Messages"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "uid",
            "in": "path",
            "required": true,
            "description": "Engine UID of the message.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "idx",
            "in": "path",
            "required": true,
            "description": "Attachment index within the message (from the attachments array).",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "The inbox domain (e.g. getinboxr.app).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "download",
            "in": "query",
            "required": false,
            "description": "Set to 1 to force Content-Disposition: attachment.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "(binary attachment stream)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/sms/inboxes": {
      "get": {
        "operationId": "sms_list_inboxes",
        "summary": "List SMS inboxes",
        "description": "Every inbox owns a real Australian mobile number that can send + receive SMS. Created via POST /v1/sms/inboxes. 1 credit per outbound and per inbound.",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, phoneNumber, label, deviceId, createdAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "post": {
        "operationId": "sms_create_inbox",
        "summary": "Create an SMS inbox",
        "description": "Provisions a new SMS inbox bound to the least-loaded online phone in the SmsSaaS pool. Requires positive credit balance — buy credits at app.getinboxr.app/sms/inboxes.",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "label": {
                    "description": "Optional human label, e.g. \"signup-bot\".",
                    "type": "string"
                  }
                },
                "example": {
                  "label": "signup-bot"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, phoneNumber, label, deviceId }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/sms/inboxes/{id}": {
      "delete": {
        "operationId": "sms_delete_inbox",
        "summary": "Delete an SMS inbox",
        "description": "Releases the inbox. Future inbound SMS to that phone number from never-claimed senders becomes \"unclaimed\" in the admin view. Existing message history is preserved on the tenant for 90 days.",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/sms/send": {
      "post": {
        "operationId": "sms_send",
        "summary": "Send an SMS",
        "description": "Sends from the inbox's assigned number. Long bodies are auto-split into multipart messages — credits charge per part. Recipient sees the SIM's MSISDN as the sender (no alphanumeric sender ID with the current architecture; that requires a separate SIP/aggregator add-on).",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "inboxId",
                  "toNumber",
                  "body"
                ],
                "properties": {
                  "inboxId": {
                    "description": "Source inbox ID.",
                    "type": "string"
                  },
                  "toNumber": {
                    "description": "Recipient in E.164, e.g. \"+61413253383\".",
                    "type": "string"
                  },
                  "body": {
                    "description": "Message text. Auto-split if > 160 chars.",
                    "type": "string"
                  }
                },
                "example": {
                  "inboxId": "sms_…",
                  "toNumber": "+61413253383",
                  "body": "Hello from Inboxr"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, status: \"pending\"|\"sending\"|\"sent\", direction: \"outbound\", ... }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/sms/inboxes/{id}/claim": {
      "post": {
        "operationId": "sms_claim_sender",
        "summary": "Claim a sender",
        "description": "Stake a 30-minute claim that the next inbound from senderNumber routes to this inbox even without a prior outbound pairing. Useful for OTP verification when you trigger the SMS from a non-Inboxr channel (e.g. a signup form on another service).",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "senderNumber"
                ],
                "properties": {
                  "senderNumber": {
                    "description": "Expected sender, in E.164.",
                    "type": "string"
                  }
                },
                "example": {
                  "senderNumber": "+61400000000"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ ok: true, expiresIn: 1800 }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/sms/inboxes/{id}/messages": {
      "get": {
        "operationId": "sms_list_messages",
        "summary": "List messages in an SMS inbox",
        "description": "Returns inbound + outbound thread, newest first. Each message has direction, fromNumber, toNumber, body, status, receivedAt.",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox ID.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Default 50, max 200.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, direction, fromNumber, toNumber, body, status, receivedAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/sms/inboxes/{id}/messages/wait": {
      "get": {
        "operationId": "sms_wait_for_message",
        "summary": "Long-poll for the next inbound SMS",
        "description": "Blocks up to 30s for a new inbound message. Filter by `from` to wait for a specific sender. Pair with /claim to make sure the sender routes here.",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Inbox ID.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO timestamp; only return messages after this. Defaults to now.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Optional E.164 sender filter.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timeout",
            "in": "query",
            "required": false,
            "description": "Max wait ms (default 30000, max 60000).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ message: { id, direction, fromNumber, body, receivedAt } | null }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/domains": {
      "get": {
        "operationId": "list_domains",
        "summary": "List your domains",
        "description": "Domains this tenant can send from / receive on — the shared getinboxr.app plus any custom domains you have verified.",
        "tags": [
          "Domains"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ domain, verified, role }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/forwards": {
      "get": {
        "operationId": "list_forwards",
        "summary": "List forwarding rules",
        "description": "Every active \"deliver mail for X to Y\" rule. The engine redirects matching inbound mail to the destination.",
        "tags": [
          "Forwards"
        ],
        "security": [
          {
            "bearerAuth": [
              "forward:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, source, destination, createdAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "post": {
        "operationId": "create_forward",
        "summary": "Create a forwarding rule",
        "description": "Forward all mail for `source` (an address on a domain you control) to `destination`. Both must be valid addresses.",
        "tags": [
          "Forwards"
        ],
        "security": [
          {
            "bearerAuth": [
              "forward:write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "source",
                  "destination"
                ],
                "properties": {
                  "source": {
                    "description": "Address to forward FROM, on one of your domains.",
                    "type": "string"
                  },
                  "destination": {
                    "description": "Address to forward TO.",
                    "type": "string"
                  }
                },
                "example": {
                  "source": "hello@yourdomain.com",
                  "destination": "you@gmail.com"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, source, destination, createdAt }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/forwards/{id}": {
      "delete": {
        "operationId": "delete_forward",
        "summary": "Delete a forwarding rule",
        "description": "Stops forwarding. Mail for the source address then follows normal delivery.",
        "tags": [
          "Forwards"
        ],
        "security": [
          {
            "bearerAuth": [
              "forward:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Forward rule ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/webhooks": {
      "get": {
        "operationId": "list_webhooks",
        "summary": "List webhooks",
        "description": "Your registered webhook endpoints plus the full list of subscribable event types.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, url, events, active }], allEvents: [...] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "post": {
        "operationId": "create_webhook",
        "summary": "Register a webhook",
        "description": "POSTs a signed JSON payload to `url` when subscribed events fire. Omit `events` to receive all. Returns a signing secret once — verify the X-Inboxr-Signature header with it.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "description": "HTTPS endpoint to receive events.",
                    "type": "string"
                  },
                  "events": {
                    "description": "Subset of: message.received, email.received, inbox.expired, sms.received, sms.delivered, voice.completed, voicemail.created.",
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "projectId": {
                    "description": "Optional project UUID to scope the webhook.",
                    "type": "string"
                  }
                },
                "example": {
                  "url": "https://example.com/hooks/inboxr",
                  "events": [
                    "message.received"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, url, events, secret }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/webhooks/{id}": {
      "delete": {
        "operationId": "delete_webhook",
        "summary": "Delete a webhook",
        "description": "Stops all deliveries to this endpoint. Irreversible.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "webhook_deliveries",
        "summary": "Recent delivery attempts",
        "description": "Delivery log for a webhook — event, HTTP status returned by your endpoint, and timing. Use it to debug missed events.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, event, status, responseCode, attemptedAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/webhooks/{id}/test": {
      "post": {
        "operationId": "test_webhook",
        "summary": "Send a test event",
        "description": "Fires a synthetic event at your endpoint so you can confirm signing + handling without waiting for real mail.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearerAuth": [
              "write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Webhook ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok, responseCode }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/sms/credits": {
      "get": {
        "operationId": "sms_credits",
        "summary": "SMS credit balance",
        "description": "Remaining SMS credits for the tenant. Each outbound segment consumes credits.",
        "tags": [
          "SMS"
        ],
        "security": [
          {
            "bearerAuth": [
              "sms:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ balance, currency }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/pbx/extensions": {
      "get": {
        "operationId": "list_extensions",
        "summary": "List PBX extensions",
        "description": "Dial-able extensions used by `dial_extension` IVR nodes — each maps a short number to a mobile or voicemail.",
        "tags": [
          "PBX"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, extensionNumber, name, destinationType, destinationValue, active }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "post": {
        "operationId": "create_extension",
        "summary": "Create an extension",
        "description": "Map a short extension number to a destination (a mobile number, or voicemail).",
        "tags": [
          "PBX"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "extensionNumber",
                  "name",
                  "destinationValue"
                ],
                "properties": {
                  "extensionNumber": {
                    "description": "2–6 digits, e.g. \"101\".",
                    "type": "string"
                  },
                  "name": {
                    "description": "Human label, e.g. \"Reception\".",
                    "type": "string"
                  },
                  "destinationType": {
                    "description": "\"mobile\" or \"voicemail\".",
                    "type": "string"
                  },
                  "destinationValue": {
                    "description": "E.164 number for mobile, or a voicemail box id.",
                    "type": "string"
                  },
                  "active": {
                    "description": "Defaults to true.",
                    "type": "boolean"
                  }
                },
                "example": {
                  "extensionNumber": "101",
                  "name": "Reception",
                  "destinationType": "mobile",
                  "destinationValue": "+61400000000"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, extensionNumber, name, destinationType, destinationValue, active }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/pbx/extensions/{id}": {
      "get": {
        "operationId": "get_extension",
        "summary": "Get one extension",
        "description": "Fetch a single extension by ID.",
        "tags": [
          "PBX"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Extension ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, extensionNumber, name, destinationType, destinationValue, active }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "patch": {
        "operationId": "update_extension",
        "summary": "Update an extension",
        "description": "Change any subset of name, destination, or active state.",
        "tags": [
          "PBX"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Extension ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "name": {
                    "description": "New label.",
                    "type": "string"
                  },
                  "destinationType": {
                    "description": "\"mobile\" or \"voicemail\".",
                    "type": "string"
                  },
                  "destinationValue": {
                    "description": "New destination.",
                    "type": "string"
                  },
                  "active": {
                    "description": "Enable/disable.",
                    "type": "boolean"
                  }
                },
                "example": {
                  "active": false
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, ... }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "delete": {
        "operationId": "delete_extension",
        "summary": "Delete an extension",
        "description": "Remove an extension. IVR nodes referencing it will fail to dial.",
        "tags": [
          "PBX"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Extension ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/inboxes": {
      "get": {
        "operationId": "voice_list_inboxes",
        "summary": "List voice inboxes",
        "description": "Phone numbers provisioned for voice, with the flow currently assigned to each.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, number, flowId, label }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/calls": {
      "get": {
        "operationId": "voice_list_calls",
        "summary": "List recent calls",
        "description": "Call history with direction, duration, and outcome.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max rows (default 50).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, from, to, direction, durationSec, status, startedAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/calls/active": {
      "get": {
        "operationId": "voice_active_calls",
        "summary": "List in-progress calls",
        "description": "Calls happening right now — useful for a live wallboard.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, from, to, since, currentNode }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/calls/{id}": {
      "get": {
        "operationId": "voice_get_call",
        "summary": "Get one call",
        "description": "Full detail for a single call including the node-by-node path taken.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Call ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, from, to, direction, durationSec, status, recordingUrl, trace }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/flows": {
      "get": {
        "operationId": "voice_list_flows",
        "summary": "List IVR flows",
        "description": "Your call flows (IVR trees). Assign one to a voice inbox to control what callers hear.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, name, updatedAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "post": {
        "operationId": "voice_create_flow",
        "summary": "Create an IVR flow",
        "description": "Two ways to create: pass `flow_json` for an explicit node graph, OR pass `description` and the system generates a flow from your prose.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "description": "Flow name.",
                    "type": "string"
                  },
                  "description": {
                    "description": "Plain-English spec → AI-generated flow (omit flow_json).",
                    "type": "string"
                  },
                  "flow_json": {
                    "description": "Explicit node graph (omit description).",
                    "type": "string"
                  }
                },
                "example": {
                  "name": "Main IVR",
                  "description": "Greet the caller, then press 1 for sales or 2 for support."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, name, flow_json }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/flows/{id}": {
      "get": {
        "operationId": "voice_get_flow",
        "summary": "Get one flow",
        "description": "Fetch a flow including its full node graph.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Flow ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, name, flow_json, updatedAt }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "patch": {
        "operationId": "voice_update_flow",
        "summary": "Update a flow",
        "description": "Rename or replace the node graph.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Flow ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "name": {
                    "description": "New name.",
                    "type": "string"
                  },
                  "flow_json": {
                    "description": "New node graph.",
                    "type": "string"
                  }
                },
                "example": {
                  "name": "Main IVR v2"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ id, name, flow_json }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      },
      "delete": {
        "operationId": "voice_delete_flow",
        "summary": "Delete a flow",
        "description": "Remove a flow. Inboxes using it fall back to the default behaviour.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Flow ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok: true }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/flows/{id}/dry-run": {
      "post": {
        "operationId": "voice_dry_run_flow",
        "summary": "Dry-run a flow",
        "description": "Simulate a caller pressing a sequence of DTMF digits and see which nodes execute — no real call placed. Body is a JSON array of digit strings, e.g. [\"1\",\"2\"].",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Flow ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ path: [{ nodeId, type, say }], ended }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/flows/{id}/traces": {
      "get": {
        "operationId": "voice_flow_traces",
        "summary": "Flow execution traces",
        "description": "Recent real-call traces through this flow — what callers actually did. Great for tuning prompts.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Flow ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ callId, path, startedAt }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/inboxes/{id}/flow": {
      "put": {
        "operationId": "voice_set_inbox_flow",
        "summary": "Assign a flow to an inbox",
        "description": "Point a voice inbox at a flow. Pass flow_id: null to clear it.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Voice inbox ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "flow_id": {
                    "description": "Flow ID to assign, or null to clear.",
                    "type": "string"
                  }
                },
                "example": {
                  "flow_id": "00000000-0000-0000-0000-000000000000"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ ok: true, inboxId, flowId }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/inboxes/{id}/test-call": {
      "post": {
        "operationId": "voice_test_call",
        "summary": "Place a test call",
        "description": "Triggers a test call against the inbox's assigned flow so you can hear it end-to-end.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Voice inbox ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ ok, callId }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/templates": {
      "get": {
        "operationId": "voice_list_templates",
        "summary": "List flow templates",
        "description": "Prebuilt flow templates you can clone as a starting point.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, name, description }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/templates/{id}/clone": {
      "post": {
        "operationId": "voice_clone_template",
        "summary": "Clone a template",
        "description": "Copy a template into your own editable flow.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Template ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ id, name, flow_json }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/tts/voices": {
      "get": {
        "operationId": "voice_tts_voices",
        "summary": "List TTS voices",
        "description": "Available text-to-speech voices for flow prompts.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "{ items: [{ id, name, language, preview }] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/tts/generate": {
      "post": {
        "operationId": "voice_tts_generate",
        "summary": "Generate speech audio",
        "description": "Render text to an audio clip with a chosen voice. Max 4000 characters.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "description": "Text to speak (≤ 4000 chars).",
                    "type": "string"
                  },
                  "voice_id": {
                    "description": "Voice to use; defaults to the account default.",
                    "type": "string"
                  }
                },
                "example": {
                  "text": "Thanks for calling. Press 1 for sales.",
                  "voice_id": ""
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ audioUrl, durationMs }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    },
    "/v1/voice/tts/script": {
      "post": {
        "operationId": "voice_tts_script",
        "summary": "Draft a prompt script",
        "description": "Generate prompt copy from a brief — hand it to /voice/tts/generate or into a flow.",
        "tags": [
          "Voice"
        ],
        "security": [
          {
            "bearerAuth": [
              "voice:call"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "description"
                ],
                "properties": {
                  "description": {
                    "description": "What the prompt should say / achieve.",
                    "type": "string"
                  },
                  "max_words": {
                    "description": "Cap the length.",
                    "type": "integer"
                  },
                  "company": {
                    "description": "Company name to weave in.",
                    "type": "string"
                  },
                  "tone": {
                    "description": "e.g. \"warm\", \"professional\".",
                    "type": "string"
                  }
                },
                "example": {
                  "description": "Friendly greeting for a dental clinic IVR",
                  "tone": "warm"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ script }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer key."
          },
          "403": {
            "description": "Bearer key lacks the required scope."
          },
          "429": {
            "description": "Plan cap reached."
          }
        }
      }
    }
  },
  "externalDocs": {
    "url": "https://getinboxr.app/llms-full.txt",
    "description": "Full markdown docs (LLM-friendly)"
  }
}