{
  "openapi": "3.1.0",
  "info": {
    "title": "Beam API",
    "version": "1.0.0",
    "description": "Beam exposes tenant-safe blue messaging, SMS/MMS, and managed conversational email through one workspace API and inbox. Authenticate every request with your workspace API key in the x-api-key header (Settings -> API key). Human-readable docs: https://beam.aisync.link/docs/ - full corpus for LLMs: https://beam.aisync.link/docs/llms-full.txt"
  },
  "servers": [
    {
      "url": "https://beam.aisync.link"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Workspace API key from Settings -> API key"
      }
    },
    "schemas": {
      "Message": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Beam message id"
          },
          "direction": {
            "type": "string",
            "enum": [
              "outbound",
              "inbound"
            ]
          },
          "channel": {
            "type": "string",
            "enum": [
              "imessage",
              "sms",
              "mms"
            ],
            "nullable": true
          },
          "body": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "sent",
              "delivered",
              "failed",
              "cancelled",
              "received",
              "no_channel"
            ],
            "description": "queued = waiting for the send window and pacing. sent = accepted by the carrier network. delivered = verified delivered. failed = verified dead (shown as Not delivered). cancelled = cancelled before delivery. received = inbound."
          },
          "from_number": {
            "type": "string",
            "nullable": true
          },
          "sender": {
            "type": "string",
            "enum": [
              "human",
              "bot",
              "system"
            ],
            "description": "Who authored an outbound message: a teammate, the AI assistant, or the system."
          },
          "attachments": {
            "type": "array",
            "items": {}
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "ts": {
            "type": "string",
            "format": "date-time",
            "description": "Carrier-time timestamp when available, else created_at. Present on list and conversation responses."
          },
          "contact_phone": {
            "type": "string",
            "description": "The lead's number. Present on list responses."
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "EmailSendRequest": {
        "type": "object",
        "required": ["domain_id", "to", "subject", "text", "request_key"],
        "properties": {
          "domain_id": { "type": "string", "description": "Beam domain id returned for this workspace" },
          "mailbox_id": { "type": "string", "nullable": true, "description": "Optional Beam mailbox id owned by the same workspace and domain" },
          "to": { "type": "string", "format": "email" },
          "subject": { "type": "string", "maxLength": 998 },
          "text": { "type": "string" },
          "request_key": { "type": "string", "description": "Stable business idempotency key. Reuse it only for the same intended send." },
          "attachments": { "type": "array", "items": { "type": "object" } }
        }
      }
    }
  },
  "security": [
    {
      "ApiKey": []
    }
  ],
  "paths": {
    "/v1/messages": {
      "post": {
        "operationId": "sendMessage",
        "summary": "Send a message",
        "description": "Queues an outbound message. Beam picks the channel (blue bubble when the recipient's phone supports it, text otherwise), applies warm-up pacing and the send window, pins the sender number for the conversation, and enforces opt-outs. Returns immediately with a queued id; poll GET /v1/messages/{id} or subscribe to event webhooks for delivery truth.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "to",
                  "message"
                ],
                "properties": {
                  "to": {
                    "type": "string",
                    "description": "Recipient phone number, E.164 or 10-digit US"
                  },
                  "message": {
                    "type": "string"
                  },
                  "first_name": {
                    "type": "string",
                    "description": "Stored on the contact if new"
                  },
                  "attachments": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uri"
                    },
                    "description": "Up to 10 https URLs"
                  },
                  "effect": {
                    "type": "string",
                    "enum": [
                      "slam",
                      "loud",
                      "gentle",
                      "invisible_ink",
                      "echo",
                      "spotlight",
                      "balloons",
                      "confetti",
                      "love",
                      "lasers",
                      "fireworks",
                      "celebration",
                      "shooting_star"
                    ],
                    "description": "Full-screen effect, blue bubble only"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Contact opted out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/messages/{id}": {
      "get": {
        "operationId": "getMessage",
        "summary": "Get a message and its delivery status",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "delete": {
        "operationId": "cancelMessage",
        "summary": "Cancel a queued or in-flight message",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled"
          },
          "409": {
            "description": "Too late to cancel"
          }
        }
      }
    },
    "/v1/messages/list": {
      "get": {
        "operationId": "listMessages",
        "summary": "List recent messages",
        "parameters": [
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by contact phone"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Messages, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "messages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Message"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{phone}": {
      "get": {
        "operationId": "getConversation",
        "summary": "Full conversation history with one contact",
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 500,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Messages oldest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "phone": {
                      "type": "string"
                    },
                    "messages": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Message"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No conversation with this contact"
          }
        }
      }
    },
    "/v1/contacts/{phone}": {
      "get": {
        "operationId": "getContact",
        "summary": "Contact details, channel, and opt-out state",
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The contact",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "phone": {
                      "type": "string"
                    },
                    "first_name": {
                      "type": "string",
                      "nullable": true
                    },
                    "imessage_available": {
                      "type": "boolean",
                      "nullable": true
                    },
                    "opted_out": {
                      "type": "boolean"
                    },
                    "pinned_number": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/availability/{phone}": {
      "get": {
        "operationId": "checkAvailability",
        "summary": "Does this number support blue bubbles?",
        "parameters": [
          {
            "name": "phone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Availability",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "phone": {
                      "type": "string"
                    },
                    "imessage": {
                      "type": "boolean",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/typing": {
      "post": {
        "operationId": "typingIndicator",
        "summary": "Show or hide the typing indicator (blue bubble only)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "to"
                ],
                "properties": {
                  "to": {
                    "type": "string"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "start",
                      "stop"
                    ],
                    "default": "start"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done"
          },
          "400": {
            "description": "Not a blue-bubble contact"
          },
          "404": {
            "description": "No conversation yet"
          }
        }
      }
    },
    "/v1/read": {
      "post": {
        "operationId": "sendReadReceipt",
        "summary": "Send a read receipt (blue bubble only)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "to"
                ],
                "properties": {
                  "to": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sent"
          },
          "400": {
            "description": "Not a blue-bubble contact"
          }
        }
      }
    },
    "/v1/reactions": {
      "post": {
        "operationId": "react",
        "summary": "Tapback-react to a contact's message (blue bubble only)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "to",
                  "tapback",
                  "message"
                ],
                "properties": {
                  "to": {
                    "type": "string"
                  },
                  "tapback": {
                    "type": "string",
                    "enum": [
                      "love",
                      "like",
                      "dislike",
                      "laugh",
                      "emphasize",
                      "question"
                    ]
                  },
                  "message": {
                    "type": "string",
                    "description": "The exact text of the message being reacted to"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "add",
                      "remove"
                    ],
                    "default": "add"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reaction delivered"
          },
          "400": {
            "description": "Invalid tapback or not blue bubble"
          }
        }
      }
    },
    "/v1/numbers": {
      "get": {
        "operationId": "listNumbers",
        "summary": "The workspace's dedicated numbers",
        "responses": {
          "200": {
            "description": "Numbers with channels and pacing caps",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "numbers": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "e164": {
                            "type": "string"
                          },
                          "channels": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "active": {
                            "type": "boolean"
                          },
                          "daily_cap": {
                            "type": "integer"
                          },
                          "hourly_cap": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/email/plan": {
      "get": {
        "operationId": "getEmailPlan",
        "summary": "Read the workspace email plan, usage, and public catalog",
        "responses": { "200": { "description": "Tenant-scoped entitlement and plan catalog" } }
      }
    },
    "/v1/email/domains": {
      "get": {
        "operationId": "listEmailDomains",
        "summary": "List domains owned by this workspace",
        "responses": { "200": { "description": "Safe domain verification and DNS state without provider ids" } }
      },
      "post": {
        "operationId": "createEmailDomain",
        "summary": "Provision a domain for this workspace",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["domain"], "properties": { "domain": { "type": "string" }, "from_name": { "type": "string" }, "from_local_part": { "type": "string" }, "inbound_enabled": { "type": "boolean" }, "confirm_root": { "type": "boolean" } } } } } },
        "responses": { "201": { "description": "Domain created with a sanitized DNS checklist" }, "409": { "description": "Invalid ownership, capacity, or deliberate root confirmation required" } }
      }
    },
    "/v1/email/domains/{id}/verify": {
      "post": {
        "operationId": "verifyEmailDomain",
        "summary": "Request domain verification and perform a server-side read-back",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Current verified domain state" } }
      }
    },
    "/v1/email/mailboxes": {
      "get": {
        "operationId": "listEmailMailboxes",
        "summary": "List sending identities owned by this workspace",
        "responses": { "200": { "description": "Tenant-owned mailboxes and safe domain state" } }
      },
      "post": {
        "operationId": "createEmailMailbox",
        "summary": "Create a mailbox on an owned domain",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["domain_id", "local_part"], "properties": { "domain_id": { "type": "string" }, "local_part": { "type": "string" }, "display_name": { "type": "string" }, "inbound_enabled": { "type": "boolean" }, "outbound_enabled": { "type": "boolean" } } } } } },
        "responses": { "201": { "description": "Mailbox created" } }
      }
    },
    "/v1/email/messages": {
      "post": {
        "operationId": "sendEmail",
        "summary": "Queue one tenant-authorized conversational email",
        "description": "The From identity is derived from an owned verified domain and mailbox. A 202 response is queued, not delivered. Duplicate request_key values return the original message and do not consume another allowance unit.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailSendRequest" } } } },
        "responses": { "202": { "description": "Queued once" }, "409": { "description": "Domain, entitlement, suppression, or idempotency policy denied the send" } }
      }
    },
    "/v1/email/threads": {
      "get": {
        "operationId": "listEmailThreads",
        "summary": "List email threads for this workspace",
        "responses": { "200": { "description": "Tenant-scoped email threads" } }
      }
    },
    "/v1/email/threads/{id}": {
      "get": {
        "operationId": "getEmailThread",
        "summary": "Read one email thread and its timeline",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Thread, messages, notes, drafts, and provider events" }, "404": { "description": "Thread is not owned by this workspace" } }
      }
    },
    "/v1/email/threads/{id}/messages": {
      "post": {
        "operationId": "replyEmailThread",
        "summary": "Queue one reply on an owned email thread",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailSendRequest" } } } },
        "responses": { "202": { "description": "Reply queued once with thread references preserved" } }
      }
    },
    "/v1/email/threads/{id}/takeover": {
      "post": {
        "operationId": "setEmailHumanTakeover",
        "summary": "Pause or deliberately resume the assistant for one email thread",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "paused": { "type": "boolean", "default": true } } } } } },
        "responses": { "200": { "description": "Current takeover state" } }
      }
    },
    "/t/{workspace}/optin": {
      "post": {
        "operationId": "newLeadWebhook",
        "summary": "New-lead webhook (CRM first touch)",
        "description": "Point your CRM workflow at this URL (it includes ?secret=, copy the whole thing from Settings). Each new lead gets the personalized first-touch message automatically, once, respecting pacing and the send window.",
        "security": [],
        "parameters": [
          {
            "name": "workspace",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "secret",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone"
                ],
                "properties": {
                  "phone": {
                    "type": "string"
                  },
                  "first_name": {
                    "type": "string"
                  },
                  "contact_id": {
                    "type": "string",
                    "description": "Your CRM contact id for tag-backs"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Queued (or already contacted)"
          }
        }
      }
    }
  },
  "webhooks": {
    "beamEvents": {
      "post": {
        "summary": "Signed event webhooks Beam sends to your endpoint",
        "description": "Configure your HTTPS endpoint in Settings -> Event webhooks. Every delivery is signed: header Beam-Signature: t=<unix>,v1=<hex HMAC-SHA256 of '<t>.<raw body>' with your signing secret>. Events include message.received, message.sent, message.failed, email.received, email.sent, email.delivered, email.bounced, email.complained, email.suppressed, contact.opted_out, assistant.booked (with a confirmed appointment_id), and assistant.handoff.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event": {
                    "type": "string"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledge with any 2xx"
          }
        }
      }
    }
  }
}
