# Bridge REST Integrations API & Webhooks > Official Bridge developer documentation for the REST API, webhooks and Custom Connections: contacts, conversations and messaging. Available in English, Spanish and Brazilian Portuguese. Read these public sources directly by HTTP; no MCP configuration or Bridge credentials are required for documentation access. Choose English, Español or Português do Brasil. API hosts and contracts are shared across translations. ## Agent Instructions - Bridge exposes three integration surfaces: the REST Integrations API for pushing data into Bridge, webhooks for receiving events from Bridge, and the public Custom Connections endpoint that a tenant's landing page posts to. - The Integrations API host is https://api-connect-us.bridge.new and every request to it must be authenticated with the x-api-key header. Bridge does not use bearer tokens or OAuth. - The Custom Connections endpoint is different and the Integrations API rules do not apply to it: it has its own host, it takes no x-api-key and no authentication header of any kind, and it is called from a visitor's browser. It is identified by a workspace id and a capture key together with a reCAPTCHA token. Never tell a reader to authenticate it with an API key, and never tell them to keep its capture key out of frontend code - it is designed to live in the page. - REST error catalog keys use BRIDGE__, for example BRIDGE_CONVERSATION_0001. Some reviewed legacy handlers return a recognized code plus a symbolic suffix separated by |; preserve the complete received value and use the compatible catalog lookup on /error-codes. Custom Connections uses separate BRIDGE.CAMPAIGN_LEADS. identifiers on its own error reference. Never invent an error code or confuse the two integration surfaces. - This documentation covers the Integrations API, webhooks and Custom Connections only. It does not describe the Bridge web application or its internal APIs. - Before generating an API request, read the relevant OpenAPI specification or the individual endpoint Markdown page. llms-full.txt collects guides and endpoint descriptions; it does not embed every request and response schema. The REST and Custom Connections contracts are separate. - Preserve the published host, method, path, operationId, authentication, headers, parameter and field names, types, formats, required and nullable fields, enums, defaults, limits, and response codes. Do not invent identifiers, fields, retry rules, or delivery guarantees. When published sources conflict, identify the conflicting passages and ask Bridge support to confirm the current behavior before relying on it. - Custom Connections is the current name of the landing-page feature previously documented as Lead Capture. The existing /lead-capture documentation URLs, captureKey field, campaign-leads endpoint, and BRIDGE.CAMPAIGN_LEADS error identifiers are unchanged. This is a naming change, not a change to authentication or the API contract. - For a complete workflow, start with the task guides: /guides/first-conversation, /guides/send-attachments, /guides/send-template, /guides/agent-outbound, /guides/pagination, /guides/identifiers and /guides/responses. Read the endpoint contract as well as the recipe. Outbound requires an existing Contact, but does not require creating a separate Conversation first. - forceSend=true permits reuse of an existing active conversation; it does not create a fresh one by ignoring it and it is not idempotency. Recovery of a released recoverable conversation can occur even with false. The LeadScout and Agents outbound routes have different line-selection and controller checks; use /guides/agent-outbound. - For webhook HMAC, follow /webhooks/verifying-signatures exactly: the Python JSON serialization with sorted keys is signed; X-Bridge-Timestamp is not included in that signature. Do not claim a signed timestamp, raw-body signing, exactly-once delivery or a global event order. Use /webhooks/receive-events for durable acceptance and duplicates. - A 201 message response, 202 handoff or 202 Custom Connections response is not a provider delivery receipt. Do not invent a polling endpoint from messageId, trackingId or requestId. REST validation parsing must tolerate the compatibility difference explained in /error-codes. - The documentation is available in English (existing root URLs), Spanish (/es/) and Brazilian Portuguese (/pt-br/). Prefer the reader's language when a localized page exists, but preserve the API's exact field names, enums, routes, authentication and examples. Translations describe the same API; they do not introduce regional API hosts or behaviors. - For coding-assistant setup, use /connect-your-agent, /es/connect-your-agent or /pt-br/connect-your-agent. The Bridge documentation MCP server reads published documentation and has a separate optional feedback tool. Connecting it does not connect the coding assistant to a customer workspace or authorize live business requests. - For direct HTTP access without MCP, start at https://docs.bridge.new/llms.txt. It lists every published page in English, Spanish and Brazilian Portuguese. Choose /llms-en.json, /llms-es.json or /llms-pt-br.json for a language-specific index, and /llms-full-en.json, /llms-full-es.json or /llms-full-pt-br.json for collected content. /llms-full.txt contains the combined collection. Fetch the original OpenAPI specification for exact schemas. - For HTTP page reads, follow the .md URLs from the index or request Accept: text/markdown at the canonical page URL. The MCP virtual filesystem uses .mdx page paths instead; .mdx is not the public HTTP export extension. With Search MCP, set language to en, es or pt-BR explicitly; its default is en. - For integration capabilities and source-selection rules, read https://docs.bridge.new/skill.md. Documentation access does not authorize business API actions; use the actual user request, workspace, credentials and target identifiers for any live integration. This combined corpus contains all three languages. It includes guides and operation descriptions, but does not embed every request and response schema. Read the exact OpenAPI contract linked for each surface before generating requests. ## Agent guidance - [Bridge integration guidance for AI agents](https://docs.bridge.new/skill.md) ## OpenAPI specifications - [Bridge API](https://docs.bridge.new/api-reference/openapi.yaml) - [Bridge Campaign Leads API](https://docs.bridge.new/api-reference/campaign-leads.openapi.yaml) - [Bridge API](https://docs.bridge.new/es/api-reference/openapi.yaml) - [Bridge Campaign Leads API](https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml) - [Bridge API](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) - [Bridge Campaign Leads API](https://docs.bridge.new/pt-br/api-reference/campaign-leads.openapi.yaml) # Integrate with Bridge Source: https://docs.bridge.new/index Connect your CRM, automation, or landing page with the REST API, webhooks, and Custom Connections. Build with your preferred coding tool ## Connect your AI coding assistant Give your coding tool the current Bridge docs. Choose it below for setup, an example prompt and a connection check. [Codex →](https://docs.bridge.new/connect-your-agent.md#codex) [Claude Code →](https://docs.bridge.new/connect-your-agent.md#claude-code) [Cursor →](https://docs.bridge.new/connect-your-agent.md#cursor) [GitHub Copilot →](https://docs.bridge.new/connect-your-agent.md#github-copilot) Docs access needs no Bridge API Key. Workspace access is separate. ## Choose your integration ### [REST API](https://docs.bridge.new/credentials.md) Create contacts, conversations and messages from your server. **Access:** server-side `x-api-key`. ### [Webhooks](https://docs.bridge.new/webhooks.md) Receive Bridge events at your HTTPS endpoint. **Access:** verify webhook credentials and freshness. ### [Custom Connections](https://docs.bridge.new/lead-capture/index.md) Capture landing-page leads and queue an opening WhatsApp message. **Access:** `captureKey` and reCAPTCHA; no REST API Key. ## Make your first REST API request ### Get your API credentials Follow [Authentication](https://docs.bridge.new/credentials.md) to generate an API key in the Bridge Admin Console. Ask your Bridge administrator for access if needed. Keep the key on your server. ### Check the connection Use your `x-api-key` header to call the authenticated [health check](https://docs.bridge.new/api-reference/health/health-check.md) at `https://api-connect-us.bridge.new/bridge/api/health`. Continue in the **REST API** tab. Each endpoint lists its fields, responses, and examples. **Note** Custom Connections uses a separate endpoint and public `captureKey`. Follow its [integration guide](https://docs.bridge.new/lead-capture/integration.md). A `202` confirms acceptance, not WhatsApp delivery. ## Build from the published contract - [Create a Contact and send a message](https://docs.bridge.new/guides/first-conversation.md) — follow the complete Contact → conversation → message workflow. - [Send a PDF or attachment](https://docs.bridge.new/guides/send-attachments.md) — checksum, upload URL, file upload and message. - [Send a WhatsApp template](https://docs.bridge.new/guides/send-template.md) — discover variables and supply caller-required values. - [Start Agent outbound and hand off](https://docs.bridge.new/guides/agent-outbound.md) — choose an Agent, understand `forceSend`, reuse and recovery. - [Look up identifiers](https://docs.bridge.new/guides/identifiers.md) and [page through results](https://docs.bridge.new/guides/pagination.md) — use the right IDs and cursors. - [Rate limits](https://docs.bridge.new/rate-limits.md) — share the request budget and handle `429` responses. - [Error codes](https://docs.bridge.new/error-codes.md) — interpret REST API errors. Custom Connections has a separate [error reference](https://docs.bridge.new/lead-capture/errors.md). - [WhatsApp template parameters](https://docs.bridge.new/templates-and-parameters.md) — open conversations with WhatsApp templates and supply their variables. - [Changelog](https://docs.bridge.new/changelog.md) — review changes that affect integrations. Read without MCP using the [trilingual documentation index](https://docs.bridge.new/llms.txt), [English index](https://docs.bridge.new/llms-en.json), [English collection](https://docs.bridge.new/llms-full-en.json), or [integration guidance for AI agents](https://docs.bridge.new/skill.md). Use the exact [REST Integrations OpenAPI](https://docs.bridge.new/api-reference/openapi.yaml) or [Custom Connections OpenAPI](https://docs.bridge.new/api-reference/campaign-leads.openapi.yaml) for schemas. For help using the Bridge application, visit the [Help Center](https://help.bridge.new). --- # Connect your AI coding assistant Source: https://docs.bridge.new/connect-your-agent Connect Codex, Claude Code, Cursor or GitHub Copilot to current Bridge documentation, then build from the exact API contract. Give your coding assistant access to the current Bridge documentation before asking it to build your integration. Choose your tool below, add the public MCP endpoint, and run the connection check. | Setting | Value | | --- | --- | | Server URL | `https://docs.bridge.new/mcp` | | Connection | Remote HTTP / Streamable HTTP | | Suggested local name | `bridgeDocs` | | Bridge credentials | None for this documentation server | **Note** This connects your assistant to **Bridge documentation**. It does not connect it to your workspace or give it permission to create Contacts or send messages. Your integration uses the separate [REST API credentials](https://docs.bridge.new/credentials.md), or the public [Custom Connections](https://docs.bridge.new/lead-capture/index.md) setup. The documentation server also exposes an optional feedback tool that sends documentation comments to Bridge. ## Choose your coding assistant ### [Codex](https://docs.bridge.new/connect-your-agent.md#codex) CLI and local IDE configuration. ### [Claude Code](https://docs.bridge.new/connect-your-agent.md#claude-code) One command, then check the connection. ### [Cursor](https://docs.bridge.new/connect-your-agent.md#cursor) Add the server to your project's MCP file. ### [GitHub Copilot](https://docs.bridge.new/connect-your-agent.md#github-copilot) Guided setup in VS Code or portable project configuration. ## Codex **Before you start:** have Codex CLI or the Codex IDE extension installed. For the CLI, add the server in your terminal: ```bash codex mcp add bridgeDocs --url https://docs.bridge.new/mcp codex mcp list ``` The list should include `bridgeDocs` with the Bridge documentation URL. Listing it confirms configuration; use [the connection check below](https://docs.bridge.new/connect-your-agent.md#check-the-connection) to confirm that it can actually read documentation. If you prefer editing configuration, add this entry to `~/.codex/config.toml`. Keep your other settings and server entries: ```toml [mcp_servers.bridgeDocs] url = "https://docs.bridge.new/mcp" ``` Restart the client or extension after changing its configuration. In the Codex terminal interface, `/mcp` shows active servers. Local Codex clients can share configuration on the same host; remote environments can have separate configuration and policy. **Example prompt:** > Use bridgeDocs to read the Bridge REST contract and the first-conversation guide. Prepare a Node.js integration that creates a Contact, starts a Conversation and creates a Message. List the required identifiers and configuration first. Keep every API field and type unchanged, cite your sources, and do not make live API requests. [Official Codex MCP guidance](https://learn.chatgpt.com/docs/extend/mcp?surface=cli). ## Claude Code **Before you start:** have Claude Code installed. Add the server to your personal configuration so it is available across projects: ```bash claude mcp add --transport http bridgeDocs --scope user https://docs.bridge.new/mcp claude mcp list ``` For a shared project configuration instead, use `--scope project` rather than `--scope user`. Review the resulting project configuration before committing it. Start Claude Code and use `/mcp` to inspect `bridgeDocs`. Then run [the connection check below](https://docs.bridge.new/connect-your-agent.md#check-the-connection). The Bridge documentation endpoint does not need a Bridge API Key or an OAuth login. **Example prompt:** > Use bridgeDocs to read the current Bridge webhook verification and receiver guides. Implement a Python receiver with the documented HMAC representation and durable acceptance before acknowledgement. Add offline tests using the published signature vector. Explain the timestamp limitation and duplicate handling, and cite the pages you used. [Official Claude Code MCP guidance](https://code.claude.com/docs/en/mcp). ## Cursor **Before you start:** open your integration project in Cursor. Create or update `.cursor/mcp.json` in that project. Merge the entry with any existing servers: ```json { "mcpServers": { "bridgeDocs": { "url": "https://docs.bridge.new/mcp" } } } ``` For a personal configuration across projects, use `~/.cursor/mcp.json` instead. In Cursor's **Customize** sidebar, check that the server is enabled. Open an Agent conversation and run [the connection check below](https://docs.bridge.new/connect-your-agent.md#check-the-connection); relevant MCP tools appear under **Available Tools**. Review tool requests when Cursor asks. **Example prompt:** > Use bridgeDocs to find the complete PDF attachment workflow. Implement a server-side upload that hashes the exact file bytes as Base64 SHA-256, requests a presigned upload, sends the required PUT and creates a Message with the returned mediaId. Preserve the documented fields and explain each stage's failure handling. Do not send a Bridge API Key to the upload URL. [Official Cursor MCP guidance](https://cursor.com/docs/mcp). ## GitHub Copilot **Before you start:** enable GitHub Copilot in VS Code and open your project folder. Select **Copilot** as the session target. 1. Open the Command Palette with `Command` + `Shift` + `P` on macOS, or `Ctrl` + `Shift` + `P` on Windows/Linux. 2. Run **MCP: Add Server** and choose **HTTP (HTTP or Server-Sent Events)**. 3. Enter `https://docs.bridge.new/mcp` and name the server `bridgeDocs`. 4. Choose **Global → Copilot Global** for your personal configuration, when available. Review the destination shown by your VS Code version and any server trust request. 5. Open a Copilot conversation, enable the Bridge documentation tools for that session, and run [the connection check below](https://docs.bridge.new/connect-your-agent.md#check-the-connection). For a shared project using the current portable Copilot configuration, create or merge this entry into `.mcp.json` at the workspace root: ```json { "mcpServers": { "bridgeDocs": { "type": "http", "url": "https://docs.bridge.new/mcp", "tools": ["*"] } } } ``` The portable Copilot format above differs from editor-managed `.vscode/mcp.json`, which uses a `servers` object. Use the file for the connection you selected; do not mix the two shapes. If the portable destination is unavailable in your version, use the guided setup and its selected configuration file. **Example prompt:** > Use bridgeDocs to read the Custom Connections guide and its separate OpenAPI contract. Prepare a landing-page form that records consent, obtains a new CAPTCHA token for each attempt and shows a 202 as accepted with its requestId. Keep captureKey, request fields and the configured CAPTCHA action unchanged. Do not use a REST API Key in the page. [Official VS Code setup](https://code.visualstudio.com/docs/agent-customization/mcp-servers) · [Copilot configuration reference](https://code.visualstudio.com/docs/agents/reference/mcp-configuration). ## Check the connection Ask this after configuring any of the four clients: > Use the Bridge documentation MCP server to search for creating a Message. Read the MessageRequest schema from the published REST OpenAPI. Which three fields are required, and does a successful 201 prove WhatsApp delivery? Cite the exact Bridge source you read. Do not call the business API. A successful check uses a documentation tool and cites a Bridge page or schema. It should identify `conversationId`, `messageBody` and `enableExternalBroadcast` as required. It should distinguish a created Message from a provider delivery receipt. A plausible answer without a tool call or source is not a connection test. ## Read with any AI tool, without MCP No MCP connection is required to read Bridge documentation. Give an assistant that can fetch URLs the [trilingual documentation index](https://docs.bridge.new/llms.txt), then choose the sources for your task and language: | Language | Page index | Collected documentation | | --- | --- | --- | | English | [English index](https://docs.bridge.new/llms-en.json) | [English collection](https://docs.bridge.new/llms-full-en.json) | | Español | [Índice en español](https://docs.bridge.new/llms-es.json) | [Documentación en español](https://docs.bridge.new/llms-full-es.json) | | Português do Brasil | [Índice em português](https://docs.bridge.new/llms-pt-br.json) | [Documentação em português](https://docs.bridge.new/llms-full-pt-br.json) | The index points to individual `.md` pages and the exact OpenAPI files. The [combined collection](https://docs.bridge.new/llms-full.txt) includes all three languages; a language-specific collection is smaller. Collected endpoint descriptions do not replace the complete schemas in OpenAPI. The language-specific files use JSON: the index lists page URLs, and each collection provides the page text as Markdown in its `contentMarkdown` field. The general `llms.txt` and `llms-full.txt` remain plain Markdown. **Example prompt:** > Read https://docs.bridge.new/llms.txt and select the English sources for sending a PDF. Read the full attachment guide and the linked REST OpenAPI before writing code. Explain the upload sequence, required fields and delivery limitations. Preserve the published API signatures and cite the URLs you read. Prepare code only; do not make live requests. If you use MCP search, specify `language: "en"`, `language: "es"` or `language: "pt-BR"` to retrieve the requested language. HTTP exports use `.md`; MCP filesystem page reads use `.mdx`. For a concise capability and source guide, read [Bridge integration guidance](https://docs.bridge.new/skill.md). ## Build with the right contract The server provides documentation search, complete page/schema reading in a virtual documentation filesystem, and optional documentation feedback. The filesystem tool does not run commands on your computer. Feedback is separate from searching and reading; use it only when you intend to send a documentation comment. Give your assistant the task and relevant workflow: - [First conversation](https://docs.bridge.new/guides/first-conversation.md): Contact → Conversation → Message. - [Attachments](https://docs.bridge.new/guides/send-attachments.md): file bytes → checksum → presigned PUT → Message. - [Templates](https://docs.bridge.new/guides/send-template.md): discover variables before sending. - [Agent outbound](https://docs.bridge.new/guides/agent-outbound.md): select an Agent and understand `forceSend`, reuse and recovery. - [Webhook receiver](https://docs.bridge.new/webhooks/receive-events.md): verify, persist, acknowledge and process. The [documentation index](https://docs.bridge.new/llms.txt) locates pages. [Collected documentation](https://docs.bridge.new/llms-full.txt) gathers guides and endpoint descriptions; it does not include every schema. Before generating code, read the individual endpoint Markdown or the appropriate [REST OpenAPI](https://docs.bridge.new/api-reference/openapi.yaml) or [Custom Connections OpenAPI](https://docs.bridge.new/api-reference/campaign-leads.openapi.yaml). Ask the assistant to preserve hosts, methods, paths, authentication, identifiers, field names, types, required/nullable fields, enums, defaults, limits and response codes. If published sources conflict, identify the passages and confirm the current behavior before relying on them. ## If the server does not appear | Symptom | What to check | | --- | --- | | Server missing | Confirm the file location or configuration scope, the server name and the client/environment you are using. Keep existing configuration when adding the entry. | | Configured but no tools | Restart or reload the client, enable the server and check its MCP status or logs. A managed organization may restrict custom servers. | | Authentication prompt | Bridge's public documentation server needs no Bridge API Key. Check the URL and your client's or organization's policy. Do not paste workspace credentials into chat. | | Answer without citations | Ask explicitly to use `bridgeDocs`, search, and read the endpoint schema. Run the connection check again. | | MCP temporarily unavailable | Read the [index](https://docs.bridge.new/llms.txt), endpoint Markdown and OpenAPI directly. The documentation server does not have a separate uptime commitment. | Client interfaces change over time. Setup options can differ by version and organization policy; use the linked provider documentation if your menus differ. Provider instructions last checked: **November 14, 2026**. --- # REST API authentication Source: https://docs.bridge.new/credentials Generate and use a server-side API key for the REST Integrations API, and keep it separate from webhook credentials and Custom Connections. ## Overview Every request to the **REST Integrations API** at `https://api-connect-us.bridge.new` uses an **API Key** in the `x-api-key` header. This key identifies your application and authorizes it to access Bridge resources on behalf of your organization. | Integration surface | Credential handling | | --- | --- | | REST Integrations API | Server-side `x-api-key` sent to `https://api-connect-us.bridge.new`. | | Webhooks | Your receiver checks the configured webhook API key, HMAC signature and freshness policy. Follow [Verify signatures](https://docs.bridge.new/webhooks/verifying-signatures.md). | | Custom Connections | Browser-side public `captureKey` and reCAPTCHA; no authentication header. Follow its [integration guide](https://docs.bridge.new/lead-capture/integration.md). | **Note** You will need access to Bridge's admin console at https://admin.bridge.new. If you don't have one, please ask your Bridge Admin to create you a user. --- ## Generating an API Key ### Open the Admin Console Go to your [Bridge Dashboard](https://admin.bridge.new) and log in with your credentials. ### Navigate to API Keys In the left panel, go to **Developers → API Keys Management**. ### Create a new key Click **Generate New Key**. You can give it a descriptive name and set an expiration date. **Warning** **Important:**\ Your API Key will only be displayed once upon creation. Copy it immediately and store it in a secure location — you will not be able to retrieve it later. --- ## Using your API Key Include your REST API Key in the `x-api-key` header on every request to the REST Integrations host: ```bash curl -X GET "https://api-connect-us.bridge.new/bridge/api/health" \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript const response = await fetch("https://api-connect-us.bridge.new/bridge/api/health", { method: "GET", headers: { "x-api-key": "YOUR_API_KEY", }, }); const data = await response.json(); console.log(data); ``` ```python import requests response = requests.get( "https://api-connect-us.bridge.new/bridge/api/health", headers={"x-api-key": "YOUR_API_KEY"} ) print(response.json()) ``` **Note** Use the `GET /bridge/api/health` endpoint to verify that your API Key is valid and your connection is working correctly. --- ## Security Best Practices - **Use environment variables** — Store your API Key in an environment variable (e.g. `BRIDGE_API_KEY`) instead of hardcoding it in your source code. - **Never expose keys in client-side code** — API Keys should only be used in server-side applications. Never include them in frontend code, mobile apps, or public repositories. - **Set an expiration date** — Always configure an expiration when creating a key. Avoid using keys without a defined expiry. - **One key per application** — Use a separate API Key for each service or application that connects to Bridge. This limits the impact if a key is compromised. - **Rotate keys periodically** — Create a new key and update your applications before deactivating the old one. This ensures zero downtime during rotation. --- ## Troubleshooting | Error | Possible Cause | Solution | | ----- | -------------- | -------- | | `401 Unauthorized` | Invalid, expired, or missing API Key | Verify that your key is correct, active, and included in the `x-api-key` header | | `403 Forbidden` | The API Key does not have access to the requested resource | Check that your key has the necessary permissions for this endpoint | | Cannot retrieve API Key | The key is only shown once at creation time | Generate a new API Key from the Admin Console | For a complete list of error codes, see the [Error Codes](https://docs.bridge.new/error-codes.md) reference. --- ## Related Topics - [Error Codes](https://docs.bridge.new/error-codes.md) — Full reference of Bridge API error codes - [REST API Reference](https://docs.bridge.new/api-reference/health/health-check.md) — Explore all available endpoints - [Webhooks](https://docs.bridge.new/webhooks.md) — Set up real-time event notifications --- # Glossary and identifiers Source: https://docs.bridge.new/guides/identifiers Find the correct workspace, Contact, Bridge User, Agent, conversation, template, line, and media identifiers without confusing them. ## Start with the right integration The **REST Integrations API** reads or changes workspace resources from your server using `x-api-key`. **Webhooks** send events from Bridge to your receiver. **Custom Connections** registers leads from a landing page using its separate public endpoint, `captureKey`, and reCAPTCHA. An API Key is a server-side secret. A Custom Connections `captureKey` is designed to be in the landing page. These values are not interchangeable. See [Authentication](https://docs.bridge.new/credentials.md) and [Custom Connections](https://docs.bridge.new/lead-capture/index.md). ## People, Agents, and lines - A **Contact** is the external person your business communicates with. Contact endpoints and external conversation participants refer to this person. - A **Bridge User** is an internal human user. Internal-user lookup and handoff assignees refer to these users. - An **Agent** is an automated Agent exposed by the Agents API. Its type is `LEADSCOUT` or `SERVICE_AGENT`; it has its own identifier, availability, and lines. - A **provider** is a channel type, such as `WHATSAPP`. A **line** is a specific channel used for a conversation. A provider type, phone number, and `providerChannelId` are different values. - A **workspace** scopes the request. A **brand** is another identifier used where the operation requires or accepts it; it is not a workspace or a line. A Contact's `ownerId` refers to a Bridge User, not an automated Agent. Resolve it with the [internal-user read endpoint](https://docs.bridge.new/api-reference/internal-users-api/retrieve-an-internal-user-by-id.md). ## Where each identifier comes from Use identifiers from the intended workspace. Do not reuse an identifier merely because the same phone number, email, or name appears in another workspace. | Value you need | Where to obtain or verify it | What to pass | | --- | --- | --- | | `workspaceId` | Use the workspace identifier supplied for your integration. If it is missing, ask your Bridge administrator. The published REST contract does not provide a global workspace-list endpoint. | The workspace ID in the operation's path. Custom Connections also requires it in its body and, for browser requests, query string. | | Contact ID | [Look up a Contact](https://docs.bridge.new/api-reference/contacts-api/retrieve-a-contact-by-an-identifier.md) by `PHONE`, `EMAIL`, or `ID`; list, create, and upsert responses also return the Contact's `id`. | The returned `id` for `{contactId}` or an identifier object with `identifierType: "ID"`, where that operation accepts it. | | Bridge User ID | [Look up an internal user](https://docs.bridge.new/api-reference/internal-users-api/retrieve-an-internal-user-by-an-identifier.md) by `EMAIL` or `ID`, or use the internal-user list. | The returned `id` for `{userId}` or an internal identifier object. Internal-user lookup does not accept `PHONE`. | | Agent ID | [List Agents](https://docs.bridge.new/api-reference/agents-api/list-the-agents-of-a-workspace.md). Read `agents[].id`, `type`, and `available`. | `agents[].id` for `{agentId}` in Agent outbound. `available` indicates whether that Agent can start conversations. | | Agent's line ID | In the same Agents response, read that Agent's `lines[].providerChannelId`. | A line ID belonging to that Agent when the operation accepts `contact.providerChannelId`. Read the outbound reference for line-selection rules. | | General provider channel | [List provider channels](https://docs.bridge.new/api-reference/provider-channels-api/get-provider-channels-by-workspace-id.md). This response publishes `provider` and `identifier`, not a channel UUID. | Use these fields only for the purposes documented by the consuming operation. Do not substitute the phone-like `identifier` for `providerChannelId`. | | `brandId` | An Agent response can expose its `brandId`. For another flow, obtain the intended brand ID from your integration configuration or administrator; the published contract does not provide a general brand-list endpoint. | The brand ID accepted by the operation. A brand ID is not a line ID. | | `teamId` | Obtain the intended internal team ID from your Bridge administrator or integration configuration. The published REST contract does not provide a team-list endpoint. | The documented team assignment option on conversation creation; do not also supply `participants.internals`. | | Conversation ID | Create or retrieve a conversation and retain its returned `id`. Outbound responses contain `conversation.id`. | `{conversationId}` or `conversationId`, exactly where the operation requires it. | | Template | [Discover a template](https://docs.bridge.new/api-reference/templates-api/discover-a-templates-agnostic-variable-inventory.md) using its ID or name. The response returns `id`, `name`, and variable keys. | Use the selector expected by the sending operation; see the next section. | | `mediaId` | [Create presigned uploads](https://docs.bridge.new/api-reference/files-api/create-presigned-uploads-for-files.md). Each response array item has `mediaId` and `presignUrl`. Complete the required PUT upload. | The returned `mediaId` in `mediaIds`, or the media field supported by that operation. Do not send the presigned URL as a media ID. | **Note** Agents lists expose line IDs in the context of each Agent. This is not a general discovery method for every workspace line. If another flow requires a `providerChannelId` you cannot obtain from the published response, ask your Bridge administrator or [support](mailto:support@sainapsis.com) for the intended line ID. Do not generate one or derive one from a telephone number. ## Similar names can require different fields **Contact lookup** takes query parameters named `type` and `value`. An external participant in a conversation takes `identifier` and `identifierType`, plus the other fields required by that operation. Do not copy a lookup query directly into a participant body. **Template discovery** accepts an ID or name in the path parameter `{templateId}`. **Conversation onboarding** uses `onboardingTemplates[].templateId`. **Outbound template selection** uses the `template` object's `id` or `name`; read that endpoint's schema rather than renaming every selector to `templateId`. Use each returned variable's `key` in template `parameters`. Variable keys are not Meta slot indexes. The [template parameters guide](https://docs.bridge.new/templates-and-parameters.md) explains required values, defaults, and the difference between omitted and blank values. ## Keep result identifiers separate | Returned value | Identifies | What it does not establish by itself | | --- | --- | --- | | `messageId` | A message created through the message endpoint | A provider delivery receipt | | `trackingId` | An accepted LeadScout handoff request | Completed assignment of the requested users | | `requestId` | An accepted Custom Connections submission | Delivery of the opening WhatsApp message | | `eventId` | An identifier supplied with a webhook event; some event families use entity-derived values | A globally unique deduplication key or delivery-order guarantee | Follow [Receive events](https://docs.bridge.new/webhooks/receive-events.md) for event identity and duplicate handling. See [Responses and errors](https://docs.bridge.new/guides/responses.md) for status codes, asynchronous results, and retry decisions. For a complete flow, follow [your first conversation](https://docs.bridge.new/guides/first-conversation.md) or [sending an attachment](https://docs.bridge.new/guides/send-attachments.md). --- # Create a contact and send a message Source: https://docs.bridge.new/guides/first-conversation Follow a complete server-side flow from a Contact to a Conversation and a Message, preserving the returned identifiers. This recipe creates a Contact, starts a Conversation with an internal Bridge User, and creates a Message. Run it on your server. **Warning** Use a test Contact you are authorized to message. Creating a Conversation can run the workspace's onboarding templates before the separate Message request. Review that configuration first; setting the later Message's broadcast flag to false does not disable Conversation onboarding. ## Before you start - Get a server-side API Key from [Authentication](https://docs.bridge.new/credentials.md). - Obtain your workspace ID, an active WhatsApp line's `providerChannelId`, and an internal Bridge User's email. See [Identifiers and concepts](https://docs.bridge.new/guides/identifiers.md). - Use a new test phone number in international format. If the Contact already exists, use [contact lookup](https://docs.bridge.new/api-reference/contacts-api/retrieve-a-contact-by-an-identifier.md) instead of creating it again. - Check any required custom attributes and the workspace's onboarding sequence. This minimal example does not supply custom attributes or override templates. - Choose `enableExternalBroadcast` explicitly: `true` requests external delivery when conversation and recipient rules permit it; `false` still creates the Message but skips external broadcast. Neither value confirms provider delivery. This flag does not override visibility or permissions. ## The sequence | Step | Request | Value to keep | | --- | --- | --- | | Check access | `GET /bridge/api/health` | Successful HTTP response | | Create Contact | `POST /bridge/api/v1/workspaces/{workspaceId}/contacts` | Contact `id` | | Start Conversation | `POST /bridge/api/v1/workspaces/{workspaceId}/conversations` | Conversation `id` | | Create Message | `POST /bridge/api/v1/workspaces/{workspaceId}/messages` | `messageId` | The Contact's `id` becomes the external participant's `identifier` with `identifierType: "ID"`. The Conversation's `id` becomes the Message's `conversationId`. ## Run the example Use Node.js with built-in `fetch`. Save this as `first-conversation.mjs`. Supply these environment variables through your server's secret and configuration settings: | Variable | Value | | --- | --- | | `BRIDGE_API_KEY` | Your secret API Key | | `BRIDGE_WORKSPACE_ID` | The intended workspace ID | | `BRIDGE_PROVIDER_CHANNEL_ID` | The authorized WhatsApp line ID, not its phone number | | `BRIDGE_USER_EMAIL` | An internal Bridge User in the same workspace | | `TEST_CONTACT_PHONE` | A new, authorized test Contact's phone number | | `ENABLE_EXTERNAL_BROADCAST` | Exactly `true` or `false`; no default is assumed | The names and message below are examples. Replace them with your intended test content before running. ```javascript const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const providerChannelId = required("BRIDGE_PROVIDER_CHANNEL_ID"); const internalEmail = required("BRIDGE_USER_EMAIL"); const cellphone = required("TEST_CONTACT_PHONE"); const broadcast = required("ENABLE_EXTERNAL_BROADCAST"); if (!["true", "false"].includes(broadcast)) { throw new Error("ENABLE_EXTERNAL_BROADCAST must be true or false."); } const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; async function request(method, path, body, expectedStatus) { const response = await fetch(`${BASE}${path}`, { method, headers: { "x-api-key": apiKey, ...(body === undefined ? {} : { "Content-Type": "application/json" }), }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), }); const result = await response.json().catch(() => null); if (response.status !== expectedStatus) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`${method} ${path}: HTTP ${response.status}${code}`); } return result; } await request("GET", "/bridge/api/health", undefined, 200); const contact = await request("POST", `${workspacePath}/contacts`, { firstName: "Alex", lastName: "Example", languageCode: "EN", cellphone, }, 201); if (!contact?.id || contact.workspaceId !== workspaceId) { throw new Error("The Contact response does not identify the intended workspace."); } const conversation = await request("POST", `${workspacePath}/conversations`, { participants: { externals: [{ identifier: contact.id, identifierType: "ID", messageProviderType: "WHATSAPP", providerChannelId, }], internals: [{ identifier: internalEmail, identifierType: "EMAIL" }], }, name: "Integration test", status: "ACTIVE", }, 201); if (!conversation?.id || conversation.workspaceId !== workspaceId) { throw new Error("The Conversation response does not identify the intended workspace."); } const message = await request("POST", `${workspacePath}/messages`, { conversationId: conversation.id, messageBody: "Hello from our authorized Bridge integration test.", enableExternalBroadcast: broadcast === "true", }, 201); if (!message?.messageId) throw new Error("The Message response has no messageId."); console.log({ contactId: contact.id, conversationId: conversation.id, messageId: message.messageId, }); ``` ```bash node first-conversation.mjs ``` ## Understand the result - A `201` Contact response gives you the Contact's identity and workspace. Read `type` to see its actual `NORMAL` or `PARTIAL` classification. - A `201` Conversation response gives you the ID to use next. When no line is free, Bridge can recover a released Conversation with exactly the requested participants. That keeps its ID and history; the requested `name` and `status` are not applied in that recovery case. - A `201` Message response supplies `messageId`. It does not by itself prove that WhatsApp delivered the message to the Contact. This recipe explicitly assigns an internal Bridge User. For a team assignment, use the documented `teamId` option instead of `participants.internals`; they are mutually exclusive. ## If a step fails The example stops at the failed request and never retries a write automatically. A network failure can leave the outcome uncertain. Check the relevant resource before repeating a create or send operation. | Situation | Next action | | --- | --- | | Contact already exists | Use contact lookup and its returned `id`; do not keep creating the same Contact. | | Brand or line error | Confirm the authorized line or brand with your administrator; a line's phone number is not its ID. | | Template `0604`–`0608` | Follow [WhatsApp template parameters](https://docs.bridge.new/templates-and-parameters.md), including workspace configuration errors. | | Message rejected because the Conversation is released | Inspect the Conversation's state and the operation's error reference before taking another action. | | `429` | Follow [Rate limits](https://docs.bridge.new/rate-limits.md), including `Retry-After`. | See [Responses and errors](https://docs.bridge.new/guides/responses.md) for response shapes and recovery decisions. ## Next steps - [Upload and send an attachment](https://docs.bridge.new/guides/send-attachments.md). - [Choose and fill a WhatsApp template](https://docs.bridge.new/guides/send-template.md). - [Create a Contact](https://docs.bridge.new/api-reference/contacts-api/create-a-new-contact.md), [create a Conversation](https://docs.bridge.new/api-reference/conversations-api/creates-a-new-conversation-with-flexible-user-identification.md), and [create a Message](https://docs.bridge.new/api-reference/messages-api/create-a-new-message.md) for the complete request and response contracts. --- # Send PDFs and other attachments Source: https://docs.bridge.new/guides/send-attachments Send a PDF or another supported file in a conversation: calculate its checksum, upload it to the presigned URL, and attach its media ID to a Message. To send a PDF or another supported attachment, request an upload from Bridge, upload the file bytes to the returned URL, then create a Message containing the returned `mediaId`. The complete server-side example below sends a PDF. ## Before you start - Have an existing Conversation in the intended workspace. See [First conversation](https://docs.bridge.new/guides/first-conversation.md). - Choose a PDF you are authorized to share and confirm it meets the [Files API](https://docs.bridge.new/api-reference/files-api/create-presigned-uploads-for-files.md) limits. - Keep your Bridge API Key on your server. Do not add it to the presigned upload request. - Choose the Message's `enableExternalBroadcast` flag explicitly. ## Validate the file before requesting an upload Check the actual file on your server: its extension, MIME type and byte length must fit the published [Files API](https://docs.bridge.new/api-reference/files-api/create-presigned-uploads-for-files.md) rules. The presign request carries metadata and a checksum, not the file bytes or a size field. A `201` response prepares an upload; it is not proof that the actual bytes were inspected, that the uploaded size meets the published limits, or that a messaging provider will accept the file. If you omit `contentType`, still copy the returned `presignUrl.headers` into the PUT request: Bridge can derive `Content-Type` from the file name. If you supply it, use the MIME type of the actual file and keep it consistent with `fileType` and the extension. Renaming a file does not convert its contents. After PUT succeeds, upload processing may still be pending. If a Message request reports a [file upload error](https://docs.bridge.new/error-codes.md#file-upload-errors), preserve the full error and check the stage that failed before deciding whether another write is safe. ## Upload sequence | Stage | What happens | What it does not confirm | | --- | --- | --- | | `POST .../files` | Bridge returns `mediaId` and `presignUrl` data. | The bytes have not been uploaded yet. | | Presigned `PUT` | Your server sends the exact bytes using the returned upload URL and headers. | No Message has been created by this step. | | `POST .../messages` | You attach the uploaded `mediaId` through `mediaIds`. | The API response alone does not prove provider delivery. | The checksum is the **Base64-encoded SHA-256 digest of the complete file bytes**. It is not a hexadecimal digest and not a hash of the file name. ## Complete server-side example Use Node.js with built-in `fetch`. Save this as `send-attachment.mjs`. Set `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_CONVERSATION_ID`, `ATTACHMENT_PATH`, and `ENABLE_EXTERNAL_BROADCAST` (`true` or `false`). ```javascript import { readFile } from "node:fs/promises"; import { basename } from "node:path"; import { createHash } from "node:crypto"; const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const conversationId = required("BRIDGE_CONVERSATION_ID"); const filePath = required("ATTACHMENT_PATH"); const broadcast = required("ENABLE_EXTERNAL_BROADCAST"); if (!["true", "false"].includes(broadcast)) { throw new Error("ENABLE_EXTERNAL_BROADCAST must be true or false."); } if (!filePath.toLowerCase().endsWith(".pdf")) { throw new Error("This example is configured for a PDF document."); } const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; const bytes = await readFile(filePath); const checksumBase64 = createHash("sha256").update(bytes).digest("base64"); async function bridgePost(path, body) { const response = await fetch(`${BASE}${workspacePath}${path}`, { method: "POST", headers: { "x-api-key": apiKey, "Content-Type": "application/json" }, body: JSON.stringify(body), }); const result = await response.json().catch(() => null); if (response.status !== 201) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`Bridge ${path}: HTTP ${response.status}${code}`); } return result; } const uploads = await bridgePost("/files", [{ name: basename(filePath), fileType: "DOCUMENT", contentType: "application/pdf", checksumBase64, }]); const upload = uploads?.[0]; if (!upload?.mediaId || !upload.presignUrl?.url) { throw new Error("The upload response is missing its mediaId or URL."); } const method = upload.presignUrl.method ?? "PUT"; if (method !== "PUT") throw new Error("Expected a presigned PUT upload."); const uploadHeaders = new Headers(upload.presignUrl.headers ?? {}); const returnedChecksum = uploadHeaders.get("x-amz-checksum-sha256"); if (returnedChecksum !== null && returnedChecksum !== checksumBase64) { throw new Error("The returned checksum differs from the file checksum."); } if (returnedChecksum === null) { uploadHeaders.set("x-amz-checksum-sha256", checksumBase64); } const uploaded = await fetch(upload.presignUrl.url, { method, headers: uploadHeaders, body: bytes, }); if (!uploaded.ok) { throw new Error(`File upload failed: HTTP ${uploaded.status}; no Message was created.`); } const message = await bridgePost("/messages", { conversationId, messageBody: "Here is the document you requested.", enableExternalBroadcast: broadcast === "true", mediaIds: [upload.mediaId], }); if (!message?.messageId) throw new Error("The Message response has no messageId."); console.log({ mediaId: upload.mediaId, messageId: message.messageId }); ``` ```bash node send-attachment.mjs ``` ## Keep the upload request intact Use `presignUrl.url` without reconstructing its host, path, or query string. Use the returned method and required headers. The contract specifies `PUT` as the method's default if it is omitted, and the Files API requires `x-amz-checksum-sha256` with the same checksum sent to Bridge. The upload sends the same `bytes` that produced the checksum. Do not convert the PDF to text, wrap it in JSON, or send a different copy of the file after hashing it. For multiple files, preserve the association between each returned `mediaId`, its presigned data, and its corresponding file. Complete every required upload before attaching those IDs to a Message. Some media need more preparation after the storage upload, such as copying the file, generating a preview, conversion or upload to the messaging provider. These stages can fail independently. A successful PUT or a 201 Message response does not establish that processing or provider delivery has completed. Keep the original file and the returned identifiers for correlation; check the result before repeating a Message request. ## Handle a failed stage - **Bridge rejects the file request:** check the extension, `fileType`, content type, size, and checksum against the reference. - **Upload fails:** stop before creating the Message. Check the exact URL, method, headers, checksum, and bytes. Do not assume an upload lifetime or retry policy that the response does not provide. - **Message request fails or times out:** an uploaded file is not proof that a Message exists. Check the outcome before repeating the Message request. `STICKER` and `WEBSITE` appear in the `FileType` enum, but the published upload table does not specify their extension, MIME, and size rules. Confirm those rules before choosing either for an integration. See the [Files API](https://docs.bridge.new/api-reference/files-api/create-presigned-uploads-for-files.md), [Message API](https://docs.bridge.new/api-reference/messages-api/create-a-new-message.md), and [Responses and errors](https://docs.bridge.new/guides/responses.md). --- # Choose and fill a WhatsApp template Source: https://docs.bridge.new/guides/send-template Discover a template by ID or name, supply its agnostic variable keys, and use its returned ID in a Conversation request. Use this recipe when you want a Conversation to open with a particular WhatsApp template. The detailed [template reference](https://docs.bridge.new/templates-and-parameters.md) explains validation rules and every documented template error. ## Before you start - Know the template's **ID or name**. Both are accepted by `GET .../templates/{templateId}`. - Confirm the template is approved for the WhatsApp Business Account behind the intended line. - Have an existing test Contact ID, the authorized WhatsApp `providerChannelId`, and an internal Bridge User's email. See [Identifiers and concepts](https://docs.bridge.new/guides/identifiers.md). - Review the workspace's onboarding sequence: your override can replace the whole sequence or only its first template, depending on workspace configuration. **Warning** The final request starts a Conversation and can send onboarding templates. Use an authorized test Contact and intended content. ## 1. Discover the variables ```http GET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId} x-api-key: YOUR_API_KEY ``` URL-encode the supplied ID or name. Read the response's `id`, `name`, `variables`, and `driftWarning`. | Variable | Action | | --- | --- | | `callerMustSupply: true` | Supply a non-blank string under that variable's `key`. | | `callerMustSupply: false`, not custom | Omit it to keep Bridge's per-Contact value. A supplied value replaces that value for every Contact. | | `isCustom: true` | Supply your value, or omit it or send it blank to use its `default`. | Use the agnostic `key`, never the display `label`, a Meta position, or an invented variable name. `driftWarning` is diagnostic and does not by itself block sending. ## 2. Prepare your values Create a server-side JSON file containing only keys returned by discovery. For a template that actually declares `order_number` and `delivery_date`, it could contain: ```json { "order_number": "A-10492", "delivery_date": "October 3" } ``` Those two names are examples, not universal Bridge fields. Read your own template before using them. Keep values within the [WhatsApp value rules](https://docs.bridge.new/templates-and-parameters.md#whatsapp-value-rules); omit non-custom values you want Bridge to fill instead of sending blank strings. ## 3. Discover, check, and create the Conversation Use Node.js with built-in `fetch`. Save this as `send-template.mjs` and set `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_TEMPLATE_ID_OR_NAME`, `TEMPLATE_VALUES_PATH`, `BRIDGE_CONTACT_ID`, `BRIDGE_PROVIDER_CHANNEL_ID`, and `BRIDGE_USER_EMAIL`. ```javascript import { readFile } from "node:fs/promises"; const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const templateRef = required("BRIDGE_TEMPLATE_ID_OR_NAME"); const contactId = required("BRIDGE_CONTACT_ID"); const providerChannelId = required("BRIDGE_PROVIDER_CHANNEL_ID"); const internalEmail = required("BRIDGE_USER_EMAIL"); const parameters = JSON.parse(await readFile(required("TEMPLATE_VALUES_PATH"), "utf8")); if (parameters === null || Array.isArray(parameters) || typeof parameters !== "object") { throw new Error("The template values file must contain a JSON object."); } if (Object.entries(parameters).some(([key, value]) => Array.from(key).length > 128 || typeof value !== "string" || Array.from(value).length > 1024 )) { throw new Error("Parameter keys and values must respect the published string limits."); } if (Object.keys(parameters).length > 50) throw new Error("At most 50 parameters are allowed."); const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; async function request(method, path, body, expectedStatus) { const response = await fetch(`${BASE}${workspacePath}${path}`, { method, headers: { "x-api-key": apiKey, ...(body === undefined ? {} : { "Content-Type": "application/json" }), }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), }); const result = await response.json().catch(() => null); if (response.status !== expectedStatus) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`${method} ${path}: HTTP ${response.status}${code}`); } return result; } const template = await request( "GET", `/templates/${encodeURIComponent(templateRef)}`, undefined, 200, ); if (!template?.id) throw new Error("Template discovery returned no id."); const variables = template.variables ?? []; const known = new Set(variables.map((variable) => variable.key)); const unknown = Object.keys(parameters).filter((key) => !known.has(key)); const missing = variables.filter((variable) => variable.callerMustSupply && (typeof parameters[variable.key] !== "string" || !parameters[variable.key].trim()) ); if (unknown.length || missing.length) { throw new Error(`Check template keys: ${unknown.length} unknown, ${missing.length} missing.`); } const conversation = await request("POST", "/conversations", { participants: { externals: [{ identifier: contactId, identifierType: "ID", messageProviderType: "WHATSAPP", providerChannelId, }], internals: [{ identifier: internalEmail, identifierType: "EMAIL" }], }, onboardingTemplates: [{ templateId: template.id, parameters }], }, 201); if (!conversation?.id || conversation.workspaceId !== workspaceId) { throw new Error("The Conversation response does not identify the intended workspace."); } console.log({ templateId: template.id, conversationId: conversation.id }); ``` ```bash node send-template.mjs ``` The example uses the ID returned by discovery in `onboardingTemplates[].templateId`. The two outbound operations also accept a template ID or name, with the ID taking precedence when both are supplied. Their request shapes differ from `onboardingTemplates`; read the operation's contract before reusing this body elsewhere. The local checks catch unknown and missing keys. Bridge still performs its own validation, including approval for the selected line and the final WhatsApp value rules. Do not treat local validation as approval or a delivery guarantee. ## Recover from a rejected request | Error | What to do | | --- | --- | | Discovery `BRIDGE_TEMPLATE_0001` | Check the ID/name and workspace. This response does not reveal whether another workspace owns that identifier. | | `BRIDGE_CONVERSATION_0604` | Supply the non-blank values listed in `extra.missingVariables`. | | `BRIDGE_CONVERSATION_0605` | Remove keys listed in `extra.unknownKeys`; use discovery's agnostic keys. | | `BRIDGE_CONVERSATION_0607` | Correct the values listed in `extra.invalidVariables` according to their `reason`. | | `BRIDGE_CONVERSATION_0608` | Ask a workspace administrator to change the configured onboarding sequence. Changing your template values does not fix this configuration error. | Read the [complete template error reference](https://docs.bridge.new/templates-and-parameters.md#errors) for approval, ownership, unsupported parameters, and malformed requests. Do not retry a timed-out Conversation request automatically: determine its outcome first. --- # Start an Agent outbound conversation Source: https://docs.bridge.new/guides/agent-outbound Choose an Agent, send an opening template, understand forceSend and recovery, and request a LeadScout handoff. Use outbound when an existing Contact should receive an approved WhatsApp template and continue with an AI Agent. Use [create a conversation](https://docs.bridge.new/guides/first-conversation.md) for the general conversation workflow. ## Choose the operation | Your goal | Operation | How the Agent is selected | | --- | --- | --- | | Start with a specific LeadScout or Service Agent | `POST /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound` | You supply the Agent ID from `GET /agents`. | | Start with a LeadScout selected through the workspace's eligible lines | `POST /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound` | Bridge resolves the prospecting Agent for the line. | Both use the REST API host `https://api-connect-us.bridge.new` and a server-side `x-api-key`. They have separate request schemas. Read the [Agents outbound reference](https://docs.bridge.new/api-reference/agents-api/start-an-outbound-conversation-with-a-contact-as-a-given-agent.md) or [LeadScout outbound reference](https://docs.bridge.new/api-reference/leadscout-api/initiate-a-leadscout-outbound-conversation-with-a-known-lead.md) for the operation you use. ## Before you send 1. [Look up the Contact](https://docs.bridge.new/api-reference/contacts-api/retrieve-a-contact-by-an-identifier.md), or [create it](https://docs.bridge.new/api-reference/contacts-api/create-a-new-contact.md) if missing. Outbound requires a Contact that already exists in the workspace; you do not need to create a separate Conversation or Message first. 2. [List Agents](https://docs.bridge.new/api-reference/agents-api/list-the-agents-of-a-workspace.md). Choose an available Agent and read its `lines[].providerChannelId`. An AI Agent ID differs from a human Bridge User ID. 3. Choose an approved template. [Discover its variables](https://docs.bridge.new/guides/send-template.md#1-discover-the-variables), supply caller-required values, and check that it is approved for the destination line. Use only the discovery step as this prerequisite; the separate Conversation-creation step in that recipe is not needed for outbound. 4. Confirm that your business has the required opt-in. If you send `consent.status: "GRANTED"`, include `capturedAt`; this records your assertion of consent. For Agents outbound, `contact.providerChannelId` must belong to the chosen Agent when supplied. It is a preference: another eligible Agent line can be selected. For LeadScout outbound, an explicit line is respected. [Identifiers and their sources](https://docs.bridge.new/guides/identifiers.md) explains which values to use. ## Send a minimal Agent request Replace every placeholder. This example assumes the chosen template has no unresolved caller-required variables. Set `forceSend` deliberately; the example keeps the default behavior explicit. ```bash curl --fail-with-body --request POST \ "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/agents/$AGENT_ID/outbound" \ --header "x-api-key: $BRIDGE_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "contact": { "identifier": "f0000001-0000-4000-8000-000000000001", "identifierType": "ID", "messageProviderType": "WHATSAPP" }, "template": { "id": "f0000040-0000-4000-8000-000000000040" }, "forceSend": false }' ``` A successful request returns `201`. Store `conversation.id` and interpret these response fields: | Field | Meaning | | --- | --- | | `alreadyInitiated: true` | An existing active conversation was reused. The successful request still adds its new template and follow-ups. | | `recovered: true` | A released, recoverable conversation was recovered, retaining its ID. Its previous outbound context and `agentContext` are replaced. | | `additionalMessagesPersisted` | The number of follow-up messages stored. This is not a delivery receipt. | | `templateSent` | A summary of the opening template stored for sending. Do not interpret the field name as proof of recipient delivery. | New creation has neither reuse nor recovery set to true. Recovery can happen with `forceSend: false`. Additional messages are persisted in request order; do not rely on a promise that they wait for the Contact to reply. The shared outbound flow persists text follow-ups and does not attach their `mediaIds`. Use the documented `template.media` option for media on the opening template, or the [Message attachment workflow](https://docs.bridge.new/guides/send-attachments.md) for a separate message. ## What forceSend does Availability is evaluated for **this Contact's conversation on each line**. An occupied line here does not mean the corporate WhatsApp line is globally reserved for one Contact. The following rules remain subject to Agent availability, template validation, consent validation and session checks. On a narrow screen, scroll horizontally to compare all four choices. Keyboard users can focus this comparison and use the arrow keys. | Situation | LeadScout: false | LeadScout: true | Agents: false | Agents: true | | --- | --- | --- | --- | --- | | Selected line is free | Create | Create | Create | Create | | Selected line holds a released conversation marked recoverable | Recover the same ID | Recover the same ID | Recover the same ID | Recover the same ID | | Automatic selection finds only occupied, active conversations | `409 …0008` | Reuse the first eligible occupied conversation | `409 …0008` | Prefer one controlled by the requested Agent, then apply the controller check below | | Explicit line is occupied | `409 …0007` | Reuse that conversation | Try other free or recoverable Agent lines; otherwise `409 …0008` | Try other free or recoverable Agent lines; otherwise prefer an occupied line the Agent controls | | Selected occupied conversation is controlled by a human or another Agent | No active reuse | Legacy route permits reuse, subject to other checks; this does not itself promise a controller transfer | No active reuse | `409 BRIDGE_AI_AGENT_OUTBOUND_0006`; this rejection writes nothing | | Only blocked or released, nonrecoverable conversations are available | `409 …0008` | `409 …0008` | `409 …0008` | `409 …0008` | In this table, `…0007` is `BRIDGE_AI_LEADSCOUT_0007` and `…0008` is `BRIDGE_AI_LEADSCOUT_0008`. A released conversation is recoverable only when its stored recovery flag permits it; `forceSend` does not make it recoverable. For both routes, a LeadScout session that is still open and unexpired blocks a new outbound request with `409 BRIDGE_AI_LEADSCOUT_0017`. Failure to finalize an expired session returns `409 BRIDGE_AI_LEADSCOUT_0018`. A Service Agent can continue its open, unexpired service session; an expired session is closed before a new one opens. **Warning** `forceSend` is not an idempotency key. Repeating a successful request can add another template and more messages. It does not bypass blocked conversations, session checks, approval rules or validation. A timeout leaves the outcome uncertain: inspect the conversation before deciding whether to submit again. ## Handle conflicts and partial work | Result | Next step | | --- | --- | | `BRIDGE_AI_LEADSCOUT_0007` / `0008` | Check the Contact's existing conversation and eligible lines. Decide whether reuse is appropriate before enabling `forceSend`. | | `BRIDGE_AI_AGENT_OUTBOUND_0006` | Inspect `extra.conversationId` and its controller. Coordinate ownership before deliberately releasing it. Do not automatically interrupt a human conversation. | | `BRIDGE_AI_LEADSCOUT_0017` / `0018` | Resolve the existing session or contact support. Switching `forceSend` to true does not fix the session. | | `BRIDGE_AI_LEADSCOUT_0019` / `0020` / `0021` | Correct missing, conflicting or unknown template variables using discovery. | | `400 BRIDGE_AI_LEADSCOUT_0016` for an unknown template `mediaId` on Agents outbound | The conversation may already have been created or recovered before this error. Inspect it before retrying. | [Release conversation](https://docs.bridge.new/api-reference/conversations-api/release-conversation.md) is a separate operation with business effects. A `204` has no response body. Release only when ending that conversation is your intended action. ## Request a LeadScout handoff to a human For a LeadScout conversation, resolve the human's [Bridge User ID or email](https://docs.bridge.new/guides/identifiers.md), then call the [manual handoff endpoint](https://docs.bridge.new/api-reference/leadscout-api/request-a-manual-handoff-of-a-leadscout-conversation-to-internal-users.md). This operation is specific to LeadScout; do not assume it applies to a Service Agent. ```bash curl --fail-with-body --request POST \ "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/leadscout/conversations/$CONVERSATION_ID/handoff" \ --header "x-api-key: $BRIDGE_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "assignees": [ {"identifier": "f0000002-0000-4000-8000-000000000002", "identifierType": "ID"} ] }' ``` A `202` acknowledges the request. Save its `trackingId` and `conversationId`; acceptance does not prove that assignment has completed or that a human has read or answered the conversation. The reference does not publish a handoff tracking endpoint, so do not construct one from `trackingId`. Continue with [error handling](https://docs.bridge.new/error-codes.md) and [webhook receiving](https://docs.bridge.new/webhooks/receive-events.md) to connect this workflow to your system. --- # Read every page of results Source: https://docs.bridge.new/guides/pagination Follow opaque cursors across Contacts, Conversations, Bridge Users, and Agents without stopping on a short page. List endpoints return a collection and an optional `cursor`. Send that cursor unchanged to read the next page. Keep following cursors until it is null or absent. ## Choose the collection All four endpoints below accept `limit` from **1 to 100**, with a default of **20**. | Resource | Path after the workspace | Collection field | | --- | --- | --- | | Contacts | `/contacts` | `contacts` | | Conversations | `/conversations` | `conversations` | | Bridge Users | `/users` | `users` | | Agents | `/agents` | `agents` | Use [contact lookup](https://docs.bridge.new/api-reference/contacts-api/retrieve-a-contact-by-an-identifier.md) or [Bridge User lookup](https://docs.bridge.new/api-reference/internal-users-api/retrieve-an-internal-user-by-an-identifier.md) when you need one known person. A full list sweep is a different task. ## Server-side example This example reads Contacts. Save it as `list-contacts.mjs` and set `BRIDGE_API_KEY` and `BRIDGE_WORKSPACE_ID` on your server. The local `maxPages` guard prevents an accidentally unbounded run; it is not a Bridge API limit. The repeated-cursor guard stops and reports a problem rather than silently returning an incomplete list. ```javascript const BASE = "https://api-connect-us.bridge.new"; const apiKey = process.env.BRIDGE_API_KEY; const workspaceId = process.env.BRIDGE_WORKSPACE_ID; if (!apiKey || !workspaceId) { throw new Error("Set BRIDGE_API_KEY and BRIDGE_WORKSPACE_ID."); } async function* pages(resource, collection, filters = {}) { let cursor; const seen = new Set(); const maxPages = 10000; for (let pageNumber = 0; pageNumber < maxPages; pageNumber += 1) { const url = new URL( `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}/${resource}`, BASE, ); for (const [key, value] of Object.entries(filters)) { url.searchParams.set(key, String(value)); } url.searchParams.set("limit", "100"); if (cursor !== undefined) url.searchParams.set("cursor", cursor); const response = await fetch(url, { headers: { "x-api-key": apiKey } }); const body = await response.json().catch(() => null); if (response.status !== 200) { const code = body?.code ? ` (${body.code})` : ""; throw new Error(`List ${resource}: HTTP ${response.status}${code}`); } if (!Array.isArray(body?.[collection])) { throw new Error(`Expected the ${collection} collection.`); } yield body[collection]; if (body.cursor === null || body.cursor === undefined) return; if (typeof body.cursor !== "string" || seen.has(body.cursor)) { throw new Error("Invalid or repeated cursor; stopped without claiming completion."); } seen.add(body.cursor); cursor = body.cursor; } throw new Error("Local page guard reached; the sweep is incomplete."); } let count = 0; for await (const contacts of pages("contacts", "contacts")) { // Process or store this page before continuing. Avoid logging personal data. count += contacts.length; } console.log({ contactsRead: count }); ``` ```bash node list-contacts.mjs ``` Use `pages("conversations", "conversations", { status: "ACTIVE" })`, `pages("users", "users")`, or `pages("agents", "agents")` with the corresponding contract. Keep the same filters throughout one traversal. ## Do not stop on a short page A page containing fewer records than `limit` can still have another page. The Agents endpoint explicitly documents this behavior. The returned cursor is the continuation signal; collection length is not. Treat the cursor as opaque. Do not decode it, increment it, or build one yourself. `URL.searchParams` in the example preserves its value through URL encoding. ## Filters and rate limits - The Contact list's `ownerEmail` and `search` filters are deprecated. For a known email or phone, use contact lookup. To filter an inventory by `ownerId`, read that field from the returned rows in your own code. - The Bridge User list's `email` and `status` filters are deprecated. Use lookup for a known email, or inspect each returned User's `status`. - Each page request consumes the workspace's shared request budget. Follow [Rate limits](https://docs.bridge.new/rate-limits.md), including `Retry-After` on `429`. This minimal example stops on non-200 responses instead of retrying automatically. The published contracts do not promise a transactional snapshot of a list while records are changing. Do not describe this traversal as a guaranteed consistent export or infer an undocumented cursor lifetime. ## References - [List Contacts](https://docs.bridge.new/api-reference/contacts-api/list-contacts.md) - [List Conversations](https://docs.bridge.new/api-reference/conversations-api/retrieve-conversations-with-flexible-filtering-options.md) - [List Bridge Users](https://docs.bridge.new/api-reference/internal-users-api/list-internal-users.md) - [List Agents](https://docs.bridge.new/api-reference/agents-api/list-the-agents-of-a-workspace.md) - [Responses and errors](https://docs.bridge.new/guides/responses.md) --- # Responses, errors, and retries Source: https://docs.bridge.new/guides/responses Interpret creation, acceptance, empty responses, validation errors, and retry signals without confusing the REST and Custom Connections contracts. ## Read the result for this operation The HTTP status and response body describe the operation you called. They do not all mean that a person received a message. | Operation | Published success | What to do with it | | --- | --- | --- | | Create a message | `201`, with `messageId` | Retain the message ID. The published response does not include a provider delivery receipt; do not label it delivered from this response alone. | | Release a conversation | `204`, with no response body | Treat it as success and do not call a JSON parser on the empty body. | | Request LeadScout handoff | `202`, with `trackingId`, `conversationId`, `status`, and `assignees` | Retain the correlation ID. Assignment is asynchronous; assignees echo the request and do not prove that downstream resolution or assignment completed. | | Submit a Custom Connections lead | `202`, with `requestId` | Retain the request ID. Show that the lead was accepted; the opening WhatsApp message is sent later by a separate service. | The reference for each operation remains authoritative: [messages](https://docs.bridge.new/api-reference/messages-api/create-a-new-message.md), [release](https://docs.bridge.new/api-reference/conversations-api/release-conversation.md), [handoff](https://docs.bridge.new/api-reference/leadscout-api/request-a-manual-handoff-of-a-leadscout-conversation-to-internal-users.md), and [Custom Connections](https://docs.bridge.new/api-reference/campaign-leads/register-a-campaign-lead.md). **Note** A correlation ID is not a status URL. The published contract does not define a polling endpoint for `trackingId` or `requestId`. Keep it for correlation and support; do not construct a new endpoint from it. ## Parse the error shape the endpoint publishes REST Integrations and Custom Connections have separate error contracts. ### REST Integrations Many responses use `Problem`: `title` and `status` are required; `code`, `detail`, `errors`, `traceId`, `instance`, and `extra` are optional. When a `code` is present, use it to select a documented error handler rather than matching the human-readable `title`. Keep `traceId` when provided for a support request. Some published validation responses declare `HTTPValidationError`, whose `detail` is an array of entries with `loc`, `msg`, and `type`. The shared API error handler reviewed for this documentation returns request validation details as `Problem.errors[]` instead. The published response definitions are preserved; confirmation against the deployed API is still pending. See the [validation compatibility note](https://docs.bridge.new/error-codes.md#parse-validation-errors-defensively). Accept JSON errors with either `application/json` or `application/problem+json`. Inspect a `code` when present, then an `errors` array or a `detail` array for field errors. A string `detail` is an explanation, not an array. A `422` status alone does not identify one universal body shape. Keep a fallback for an error without `code`, and use the endpoint reference together with [Error codes](https://docs.bridge.new/error-codes.md) to choose the action. ### Custom Connections Its error body has required `type`, `title`, and `status`, and may include `detail`. Here **`type` is the machine-readable error identifier**. It is not the REST `code` field. The [Custom Connections error reference](https://docs.bridge.new/lead-capture/errors.md) lists these responses. Error responses do not carry the submission `requestId`; only a successful `202` does. For an error support request, retain the page URL and approximate time as described in that reference. ## Make retry decisions by operation and cause | Result | Next action | | --- | --- | | REST `429` | Follow `Retry-After` in seconds. The rate-limit guide states that the rejected request was not processed. The workspace budget is shared across API Keys. | | REST `401` or `403` | Correct the API Key, permissions, or workspace mismatch. A timed retry does not fix those causes. | | Validation or configuration error | Correct the documented cause first. Do not repeatedly send the same invalid request. | | Custom Connections `422` | The documented cause is CAPTCHA provider unavailability. Its error guide says retrying is safe; mint a fresh CAPTCHA token for the new attempt. | | Custom Connections CAPTCHA rejection | Check that the token is present, fresh, and minted for this attempt. The same error also covers a low score, so a new attempt alone does not prove the original cause. | | Timeout, connection loss, or an unclassified `5xx` during a mutation | Do not assume nothing happened. Inspect the operation's documented effects and any identifiers already obtained before deciding whether to repeat it. Do not assume a general idempotency guarantee. | See [Rate limits](https://docs.bridge.new/rate-limits.md) for pacing and [Custom Connections errors](https://docs.bridge.new/lead-capture/errors.md) for its distinct retry rules. ## Some failures can follow a write The [Agent outbound reference](https://docs.bridge.new/api-reference/agents-api/start-an-outbound-conversation-with-a-contact-as-a-given-agent.md) documents that an unknown `template.media.mediaId` can produce `BRIDGE_AI_LEADSCOUT_0016` after the conversation was created or recovered. A retry may therefore produce a different result. This is why a failure status alone is not a universal rollback guarantee. Follow the effects and recovery instructions for the specific operation. If those instructions are unclear or conflict, identify the uncertainty and contact [Bridge support](mailto:support@sainapsis.com) before retrying an action with external effects. --- # WhatsApp template parameters Source: https://docs.bridge.new/templates-and-parameters Open a conversation with your own WhatsApp templates, fill their variables, and handle every error the request can return. ## Overview When you create a conversation, `onboardingTemplates` lets you choose the WhatsApp templates it opens with, in order. A template can contain variables — an order number, a delivery date, the Contact's first name. Some of them Bridge fills on its own for each Contact; others only you can provide, and you send them in the entry's `parameters`. The flow has three steps: 1. Look up the template's variables. 2. Decide which values to send. 3. Send them with `POST .../conversations`. **Note** Every check described on this page runs before anything is created. If the request is rejected, **no conversation is created and no message is sent**, so you can correct it and send it again. --- ## 1. Find the template's variables ```http GET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId} x-api-key: YOUR_API_KEY ``` `templateId` accepts either the template's `id` or its `name`. The response lists its variables: ```json { "id": "f0000040-0000-4000-8000-000000000040", "name": "order_shipped_promo", "language": "es", "driftWarning": { "hasDrift": false, "stale": [], "missingLabels": [] }, "variables": [ { "key": "first_name", "label": "Contact first name", "callerMustSupply": false, "isCustom": false, "default": null }, { "key": "order_number", "label": "Order number", "callerMustSupply": true, "isCustom": false, "default": null }, { "key": "delivery_date", "label": "Delivery date", "callerMustSupply": true, "isCustom": false, "default": null }, { "key": "tracking_code", "label": "Tracking code", "callerMustSupply": false, "isCustom": true, "default": "pending" } ] } ``` `driftWarning` is diagnostic only: it reports differences between the declared variables and Meta's template snapshot and never blocks a send. The table below describes each item in `variables`. | Field | Meaning | | ----- | ------- | | `key` | The name to use in `parameters` | | `label` | A human-readable description of the variable | | `callerMustSupply` | `true` when you must supply a non-blank value because Bridge has no source for it; `false` otherwise | | `isCustom` | Whether this is a custom variable: a value only you know, with a default text | | `default` | For a custom variable, the text sent when you send no value for it; `null` otherwise | A template that is not in your workspace returns `404` with `BRIDGE_TEMPLATE_0001`. --- ## 2. Decide which values to send | Variable | What it means | What to do | | -------- | ------------- | ---------- | | `callerMustSupply: true` | Bridge has no source for this value | **Required.** Send a non-blank value for its `key` | | `callerMustSupply: false`, `isCustom: false` | Bridge fills it for each Contact, such as the Contact's first name | **Optional.** Omit it to keep Bridge's value | | `isCustom: true` | A value only you know, with a `default` | **Optional.** Send your value, or omit it (or send it blank) and its `default` is sent | A value you send for a `callerMustSupply: false` variable replaces Bridge's value and is used **for every Contact** in the conversation. **Warning** For a variable that is not custom, keep Bridge's value by **omitting the key**. A blank value is not treated as "use the default": it is sent as you wrote it. A required variable with a blank or whitespace-only value is rejected as missing. Only custom variables (`isCustom: true`) treat a blank value as not sent and fall back to their `default`. --- ## 3. Send the parameters Each entry in `onboardingTemplates` takes the template's `id` (as returned in step 1) and its `parameters`, keyed by variable `key`. Position in the list sets the sending order. ```http POST /bridge/api/v1/workspaces/{workspaceId}/conversations x-api-key: YOUR_API_KEY Content-Type: application/json ``` ```json { "participants": { "externals": [ { "identifier": "+13802098869", "identifierType": "PHONE", "messageProviderType": "WHATSAPP", "brandId": "YOUR_BRAND_ID" } ] }, "onboardingTemplates": [ { "templateId": "f0000040-0000-4000-8000-000000000040", "parameters": { "order_number": "A-10492", "delivery_date": "3 de octubre" } } ] } ``` In this example `first_name` and `tracking_code` are omitted, so each Contact receives their own first name and `tracking_code` is sent as its default, `pending`. Limits per template: at most **50** parameters, keys up to **128** characters, values up to **1,024** characters. Requests beyond these limits are rejected as malformed (see [Errors](https://docs.bridge.new/templates-and-parameters.md#errors)). Depending on how the workspace is set up, your templates replace its whole onboarding sequence or only its first template. In the second case, the rest of the configured sequence is still sent after yours. --- ## WhatsApp value rules WhatsApp rejects some values when the message is sent. Bridge checks them up front so the request fails while you can still fix it: | Rule | Limit | | ---- | ----- | | Line breaks and tabs | Not allowed — no `\n`, `\r` or `\t` | | Consecutive spaces | At most 4 in a row | | Header | The header text with your value in place fits in **60** characters | | URL button | The button's link with your value in place fits in **2,000** characters | | Body | The body text plus all its values fits in **1,024** characters | **Warning** The body limit includes the values Bridge fills in for each Contact, such as their first name. Bridge can only check the values it can see when you make the request, so leave room for them. Bridge never trims or rewrites your values: what you send is what the Contact receives. --- ## Errors All errors use the `application/problem+json` format described in [Error codes](https://docs.bridge.new/error-codes.md). Branch on `code`, never on `title`. | Code | Status | When | `extra` | | ---- | ------ | ---- | ------- | | `BRIDGE_CONVERSATION_0601` | 404 | The template does not exist | `templateId`, `workspaceId` | | `BRIDGE_CONVERSATION_0602` | 400 | The template belongs to another workspace | `templateId`, `workspaceId` | | `BRIDGE_CONVERSATION_0603` | 400 | The template is not approved for the line a participant will be reached on | `templateId`, `workspaceId`, `userIds` (the Contacts whose line it is not approved for, when known) | | `BRIDGE_CONVERSATION_0604` | 422 | A required variable is missing or blank | `templateId`, `missingVariables: [{key, label}]` | | `BRIDGE_CONVERSATION_0605` | 422 | A key in `parameters` is not one of the template's variables | `templateId`, `unknownKeys: [key]` | | `BRIDGE_CONVERSATION_0606` | 422 | `parameters` was sent for a template that is not a WhatsApp template | `templateId` | | `BRIDGE_CONVERSATION_0607` | 422 | A value breaks a [WhatsApp rule](https://docs.bridge.new/templates-and-parameters.md#whatsapp-value-rules) | `templateId`, `invalidVariables: [{key, label, reason}]` | | `BRIDGE_CONVERSATION_0608` | 422 | A template the workspace sends after yours needs values only the caller can provide | `templateId`, `origin: "WORKSPACE_CONFIGURATION"` | ### Missing values — `0604` ```json { "title": "A template named in the onboarding override is missing values only the caller can provide", "status": 422, "detail": "A template named in the onboarding override is missing values only the caller can provide", "code": "BRIDGE_CONVERSATION_0604", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "missingVariables": [ { "key": "delivery_date", "label": "Delivery date" } ] } } ``` ### Invalid values — `0607` ```json { "title": "Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent", "status": 422, "detail": "Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent", "code": "BRIDGE_CONVERSATION_0607", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "invalidVariables": [ { "key": "order_number", "label": "Order number", "reason": "NEWLINE" } ] } } ``` `reason` is the first rule the value breaks: | `reason` | Meaning | | -------- | ------- | | `NEWLINE` | The value contains `\n` or `\r` | | `TAB` | The value contains `\t` | | `CONSECUTIVE_SPACES` | The value has more than 4 spaces in a row | | `TOO_LONG` | The header or URL button exceeds its limit with the value in place | | `BODY_TOO_LONG` | The body exceeds 1,024 characters; every body value you sent is listed | ### `0608` is not fixed by changing the request `BRIDGE_CONVERSATION_0608` only occurs in workspaces where your templates replace just the first template of the onboarding sequence. It means a template the workspace sends after yours needs values that only the caller can provide, and the API cannot supply them. Ask a workspace admin to change the onboarding sequence. ### Malformed requests A request that does not match the schema — more than 50 parameters, a key over 128 characters, a value over 1,024, or an unknown field — is rejected with `422` **without a `code`**. It carries an `errors` list pointing at each problem instead: ```json { "title": "Unprocessable content", "status": 422, "errors": [ { "loc": ["body", "onboardingTemplates", 0, "parameters", "order_number"], "msg": "String should have at most 1024 characters", "type": "string_too_long" } ] } ``` ### Evaluation order Checks run in this order, and **the first error wins**: 1. Rate limit — `429` 2. Request shape — `422` without `code` 3. Participants, brand and line — `400` / `409`, for example `BRIDGE_BRAND_0101` or `BRIDGE_PROVIDER_CHANNEL_0001` 4. Each template, in list order: `0601` / `0602` → `0603` → `0606` → `0605` → `0604` → `0607` 5. `0608`, only in workspaces where your templates replace just the first template So fixing one error can reveal the next. Values for a later template are not checked until every earlier template passes. --- ## Related Topics - [Create a conversation](https://docs.bridge.new/api-reference/conversations-api/creates-a-new-conversation-with-flexible-user-identification.md) — Full request and response reference - [Error Codes](https://docs.bridge.new/error-codes.md) — Every code, including brand and line errors - [Rate limits](https://docs.bridge.new/rate-limits.md) — Handling `429` --- # Rate limits Source: https://docs.bridge.new/rate-limits How many requests the Bridge API accepts, the headers that tell you where you stand, and how to handle a 429 correctly. ## Overview The Bridge API accepts **50 requests every 5 seconds**. The limit applies to every endpoint, is enabled by default, and needs no configuration. **Note** The budget belongs to the **workspace**, not to the API Key. If you issue several keys for the same workspace — one per application, as recommended — they all draw from the same 50 requests. --- ## Knowing where you stand Every response to an authenticated request carries two headers, so you never have to guess how much budget is left: ```http RateLimit-Policy: "default";q=50;w=5 RateLimit: "default";r=43;t=3 ``` | Field | Meaning | | ----- | ------- | | `q` | Requests allowed per window | | `w` | Window length, in seconds | | `r` | Requests **remaining** in the current window | | `t` | Seconds until the window resets and `r` returns to `q` | A client that watches `r` and pauses as it approaches zero is never rejected at all. **Note** A request rejected **before** authentication — a missing or invalid API Key — carries neither header. See [Authentication](https://docs.bridge.new/credentials.md) for those responses. --- ## When you go over Requests beyond the budget are answered with `429 Too Many Requests`. Nothing is processed, so the request is safe to repeat. ```http HTTP/1.1 429 Too Many Requests Content-Type: application/problem+json Retry-After: 3 RateLimit-Policy: "default";q=50;w=5 RateLimit: "default";r=0;t=3 ``` ```json { "title": "Too Many Requests", "status": 429, "detail": "The workspace has exhausted its request budget for the current window", "code": "BRIDGE_RATE_LIMIT_0001" } ``` `Retry-After` is expressed in **seconds from now**, not as a date. Wait that long and the next request is served. **Warning** **A `429` is not an authentication problem.** `401` and `403` mean the API Key is missing, invalid, expired or not authorized, and **retrying them on a schedule will never succeed** — it only burns your budget. Only `429` should be retried automatically, and only after the delay it gives you. --- ## What consumes budget Every HTTP request counts as one, including requests that end in a validation error or a `404`. What matters is how many calls your client makes, not how much data comes back. That distinction shows up when you read: - **A single resource by id** — `GET .../contacts/{contactId}` — costs **one request**, whatever the size of the response. - **A list** — `GET .../contacts` — costs **one request per page**. Reading a list in full costs as many requests as it has pages. So page size decides the cost of a full sweep. Walking 500 contacts costs 5 requests at 100 per page, and 25 requests at 20 per page — same data, five times the budget. **Note** Prefer the largest page size an endpoint accepts when you are reading a list in full, and read a single resource by its id when you already know which one you need. --- ## Backing off in practice A client that paces itself from `RateLimit` and honours `Retry-After` on the rare miss needs no other logic: ```python import time import requests BASE = "https://api-connect-us.bridge.new" HEADERS = {"x-api-key": "YOUR_API_KEY"} def rate_limit_state(response): header = response.headers.get("RateLimit", "") fields = dict(part.split("=", 1) for part in header.split(";") if "=" in part) return int(fields.get("r", 1)), int(fields.get("t", 1)) def get(path): while True: response = requests.get(f"{BASE}{path}", headers=HEADERS) if response.status_code == 429: time.sleep(int(response.headers["Retry-After"])) continue remaining, reset_in = rate_limit_state(response) if remaining == 0: time.sleep(reset_in) return response ``` ```javascript const BASE = "https://api-connect-us.bridge.new"; const HEADERS = { "x-api-key": "YOUR_API_KEY" }; const sleep = (seconds) => new Promise((done) => setTimeout(done, seconds * 1000)); function rateLimitState(response) { const fields = Object.fromEntries( (response.headers.get("RateLimit") ?? "") .split(";") .filter((part) => part.includes("=")) .map((part) => part.split("=")) ); return { remaining: Number(fields.r ?? 1), resetIn: Number(fields.t ?? 1) }; } async function get(path) { while (true) { const response = await fetch(`${BASE}${path}`, { headers: HEADERS }); if (response.status === 429) { await sleep(Number(response.headers.get("Retry-After"))); continue; } const { remaining, resetIn } = rateLimitState(response); if (remaining === 0) await sleep(resetIn); return response; } } ``` **Warning** Do not retry a `429` immediately or on a fixed timer of your own. Retrying before `Retry-After` elapses is rejected again, and a tight retry loop keeps the workspace at zero budget for every other application sharing it. --- ## Standards These fields are not Bridge-specific: `RateLimit-Policy` and `RateLimit` follow the IETF [RateLimit header fields](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/) specification, `Retry-After` is [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#field.retry-after), and the `429` body is [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457.html). If you already handle `X-RateLimit-*` headers from another API, these are the standardised equivalents. When the two disagree, **`Retry-After` wins** — it is the authoritative retry signal, and `RateLimit` is pacing information. --- ## Related Topics - [Authentication](https://docs.bridge.new/credentials.md) — API Keys, and the `401` / `403` responses that must not be retried - [Error Codes](https://docs.bridge.new/error-codes.md) — Full reference, including `BRIDGE_RATE_LIMIT_0001` - [REST API Reference](https://docs.bridge.new/api-reference/health/health-check.md) — Every endpoint documents its `429` response --- # Error codes Source: https://docs.bridge.new/error-codes Interpret REST API error codes, validation responses and uncertain write outcomes, and choose the next action. ## Response format Example of a `Problem` response. Consult the endpoint reference for its HTTP status, media type and response schema: ```json { "title": "A template named in the onboarding override is missing values only the caller can provide", "status": 422, "detail": "A template named in the onboarding override is missing values only the caller can provide", "code": "BRIDGE_CONVERSATION_0604", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "missingVariables": [{ "key": "delivery_date", "label": "Delivery date" }] }, "instance": "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/{workspaceId}/conversations", "traceId": "Root=1-6702b8c4-3f1a2b4c5d6e7f8091a2b3c4" } ``` | Field | Meaning | | ----- | ------- | | `code` | When present, the stable error code listed on this page. **Branch on this field rather than the title.** Validation and server errors may omit it. | | `title` | A human-readable message. It may be longer than the title shown in the tables below, so never match on it | | `status` | The HTTP status code | | `detail` | More detail about this occurrence, when available | | `extra` | Machine-readable context for the error, such as the ids or keys involved, when available | | `instance` | The request URL | | `traceId` | Include it when you contact support | **Note** Read the response schema for the operation you call. Where it is `HTTPValidationError`, validation details are in a `detail` array; each entry contains `loc` (where), `msg` (what) and `type`. Other documented `422` responses use `Problem` and may include a `code` and `extra`. Do not assume all `422` responses have the same shape. ### Parse validation errors defensively Accept JSON error bodies with either `application/json` or `application/problem+json`. Check the HTTP status first, then inspect the body: 1. If `code` is present, use the matching entry on this page to choose the action. 2. If `errors` is an array, read its `loc`, `msg` and `type` entries as validation details. 3. If `detail` is an array, read it as the `HTTPValidationError` form. A string `detail` is an explanation, not a list of field errors. 4. Preserve `traceId`, status and the request URL for support. Do not require `code` or `extra` to exist, and do not match human-readable messages as identifiers. An invalid field and a rule involving several fields need not share a status. The reviewed outbound body rules raise `400` with `BRIDGE_CORE_0103` when `consent.status` is `GRANTED` without `capturedAt`, or when `template.media` supplies both or neither of `mediaId` and `url`. Invalid field types or UUIDs can instead produce `422` request-validation details. Handle the status and error body together; do not require an `errors` array for every invalid request. ### Legacy code strings Some legacy error handlers append a symbolic name to `code`, for example `BRIDGE_PRELOAD_FILE_0002 | PRELOAD_FILE_IS_PENDING`. Preserve the complete received value for logs and support. For catalog lookup, accept a known bare code or its explicitly recognized legacy form; do not compare human-readable `title` or `detail`, invent an unknown code, or rewrite the response body. The current deployed handler version has not been independently confirmed by this source review. **Warning** **Validation compatibility:** some published OpenAPI responses declare `HTTPValidationError.detail[]` and `application/json`, while the shared API error handler reviewed for this documentation returns validation details as `Problem.errors[]` with `application/problem+json`. This editorial update preserves those published response definitions. Handle both forms; confirmation against the deployed API remains pending before choosing one as the only accepted form in a strict generated client. ### Decide whether to retry | Result | Action | | --- | --- | | `400` or `422` | Correct the request using the code and field errors. Repeating unchanged input does not fix validation. | | `401` or `403` | Check the credential, workspace and permissions for the correct integration surface. Keep REST API keys on your server. | | `404` | Confirm the identifier and workspace. A lookup that finds no Contact is different from malformed input. | | `409` | Read the operation's code: an existing conversation, unavailable Agent or unfinished session needs a different resolution. Do not enable `forceSend` automatically. | | `429` | Follow the [rate-limit headers and backoff guidance](https://docs.bridge.new/rate-limits.md). | | Timeout, disconnected response or `5xx` after a write | Treat the outcome as uncertain. Inspect the affected resource before resubmitting; an error does not prove that no work was persisted. | The general retry guidance does not add idempotency to an endpoint. For outbound reuse, recovery and partial writes, see [Agent outbound and handoff](https://docs.bridge.new/guides/agent-outbound.md). Custom Connections has its own [error reference](https://docs.bridge.new/lead-capture/errors.md) and no REST API key. ## Message reply errors For `POST .../messages`, the reviewed reply checks define these additional legacy forms: - `BRIDGE_MESSAGE_0001 | MESSAGE_NOT_FOUND` (`404`): the Message named by `replyToMessageId` was not found. - `BRIDGE_MESSAGE_0002 | MESSAGE_IS_NOT_ON_CONVERSATION` (`403`): the reply target belongs to another Conversation. Use a target from the Conversation you are sending to. Preserve the full `code` string, including its symbolic suffix. These checks concern the reply target, not the attached file's `mediaId`. ## File upload errors The reviewed upload flow defines these legacy error strings. Their suffix is part of the received `code`, not a request field. Consult the operation response contract and keep the compatibility parsing above. The operation determines which file errors apply: `POST .../files` checks metadata and can return `0003` or `0004` below. `POST .../messages` can return `0001` or `0002` when an attached `mediaId` is missing or still pending. Outbound template media has its own error handling; do not substitute these codes for `BRIDGE_AI_LEADSCOUT_0016`. | Legacy `code` | Status | Action | | --- | --- | --- | | `BRIDGE_PRELOAD_FILE_0001 \| PRELOAD_FILE_NOT_FOUND` | 404 | Check the returned `mediaId` and the upload being referenced. | | `BRIDGE_PRELOAD_FILE_0002 \| PRELOAD_FILE_IS_PENDING` | 400 | The file is still pending. Confirm the PUT completed and allow upload processing; do not infer that a failed Message request persisted no work. | | `BRIDGE_PRELOAD_FILE_0003 \| PRELOAD_FILE_INVALID_MIME_TYPE` | 400 | Correct the MIME type and logical `fileType` combination. | | `BRIDGE_PRELOAD_FILE_0004 \| PRELOAD_FILE_INVALID_NAME` | 400 | Supply a file name with an extension allowed for that logical `fileType`. | ## Agent Error Codes Error codes for Agent operations. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_AI_AGENT_OUTBOUND_0001` | Agent Not Found | Agent not found in the workspace | | `BRIDGE_AI_AGENT_OUTBOUND_0002` | Agent Not Available | Agent is not available for outbound | | `BRIDGE_AI_AGENT_OUTBOUND_0003` | Agent Type Not Supported | Agent type is not supported for outbound | | `BRIDGE_AI_AGENT_OUTBOUND_0004` | No Channels For Agent | No active messaging line is bound to the agent | | `BRIDGE_AI_AGENT_OUTBOUND_0005` | Agent Not Assigned To Channel | Agent is not assigned to the requested channel | | `BRIDGE_AI_AGENT_OUTBOUND_0006` | Conversation Controlled By Other Agent | Active conversation is controlled by another agent | | `BRIDGE_AI_AGENT_OUTBOUND_0007` | Invalid Cursor | Pagination cursor is malformed or belongs to another workspace | `POST .../agents/{agentId}/outbound` returns `0001` and `0004` as `404`, `0002` and `0006` as `409`, and `0003` and `0005` as `422`. - `0002`: the Agent is a draft or has no line. `extra.reason` says which; the same reason appears as `unavailableReason` in `GET .../agents`. - `0006`: the Contact's conversation on the line the request resolved is held by another Agent or by a Bridge User. Nothing was sent. Release it with `POST .../conversations/{conversationId}/release`, using `extra.conversationId`, then retry. `extra` also carries `channelId`, and `controllingAgentId` (the Agent holding it) only when an Agent holds it: when a Bridge User does, the key is absent, not `null`. `GET .../agents` returns `0007` as `400` when the `cursor` is malformed or was issued for another workspace. Start again without a cursor. Keep the same `type` filter while paging: a cursor issued under one `type` filter is rejected if the request carries a different `type`. ### Other codes returned by `POST .../agents/{agentId}/outbound` | Code | Status | Meaning | | ---- | ------ | ------- | | `BRIDGE_CORE_0103` | 400 | The request is invalid: `consent.status` is `GRANTED` without `capturedAt`, `template` carries neither `id` nor `name`, or `template.media` does not carry exactly one of `mediaId` or `url` | | `BRIDGE_CORE_0301` | 403 | The workspace in the path differs from the one of the API key | | `BRIDGE_AI_LEADSCOUT_0001` | 404 | The Contact does not exist in the workspace | | `BRIDGE_AI_LEADSCOUT_0002` | 404 | The `handoffOverride` Bridge User does not exist in the workspace | | `BRIDGE_AI_LEADSCOUT_0003` | 409 | The `handoffOverride` Bridge User was deleted | | `BRIDGE_AI_LEADSCOUT_0004` | 404 | No template of the workspace matches `template.id` (or `template.name` when no id is sent) | | `BRIDGE_AI_LEADSCOUT_0005` | 409 | Template not approved | | `BRIDGE_AI_LEADSCOUT_0006` | 400 | Template ordered params mismatch | | `BRIDGE_AI_LEADSCOUT_0007` | 409 | Active conversation already exists: another request took the released conversation first. Retry | | `BRIDGE_AI_LEADSCOUT_0008` | 409 | No line of the Agent is free or recoverable for this Contact (see `forceSend`) | | `BRIDGE_AI_LEADSCOUT_0009` | 404 | No line configured for the requested `brandId` | | `BRIDGE_AI_LEADSCOUT_0016` | 400 | Outbound validation error | | `BRIDGE_AI_LEADSCOUT_0017` | 409 | Latest session is not finalized | | `BRIDGE_AI_LEADSCOUT_0018` | 409 | Could not finalize the expired session before starting a new one | | `BRIDGE_AI_LEADSCOUT_0019` | 422 | Missing required template variable(s) | | `BRIDGE_AI_LEADSCOUT_0020` | 422 | Conflicting template parameter sources for the same slot | | `BRIDGE_AI_LEADSCOUT_0021` | 422 | Unknown template parameter key | For `POST .../agents/{agentId}/outbound`, `5xx` errors carry no `code` or `extra`. ## LeadScout Error Codes Additional codes documented for [starting a LeadScout outbound conversation](https://docs.bridge.new/api-reference/leadscout-api/initiate-a-leadscout-outbound-conversation-with-a-known-lead.md) with `POST .../leadscout/outbound`: | Code | Status | Title | Meaning | | --- | --- | --- | --- | | `BRIDGE_AI_LEADSCOUT_0010` | 404 | Channel Not In Workspace | Provider channel not in workspace | | `BRIDGE_AI_LEADSCOUT_0011` | 404 | No Provider Channels | Workspace has no provider channels | | `BRIDGE_AI_LEADSCOUT_0012` | 404 | No Agent For Channel | No prospecting agent for channel | | `BRIDGE_AI_LEADSCOUT_0013` | 409 | Multiple Agents For Brand | Multiple prospecting agents for brand | | `BRIDGE_AI_LEADSCOUT_0014` | 409 | Multiple Agents For Channel | Multiple prospecting agents for channel | | `BRIDGE_AI_LEADSCOUT_0015` | 500 | Conversation Operation Failed | Conversation operation failed | ## Brand Error Codes Error codes for brand checks when creating a conversation. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_BRAND_0101` | Brand Required | The workspace has brands enabled; each external participant must resolve to a brand or a line | Returned as `400`. Send a `brandId` or a `providerChannelId` for every external participant; `extra.resources` lists the participants that had neither. ## Conversation Error Codes Error codes for conversation operations. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_CONVERSATION_0001` | Conversation Not Found | The requested conversation was not found | | `BRIDGE_CONVERSATION_0002` | Conversation Not In Workspace | The conversation does not belong to the specified workspace | | `BRIDGE_CONVERSATION_0003` | Conversation With Same Participants Already Exists | An active conversation with the same participants already exists | | `BRIDGE_CONVERSATION_0004` | Conversation Not Active | The conversation is inactive; no operations can be performed on it | | `BRIDGE_CONVERSATION_0005` | Conversation Operation Failed | An error occurred while operating on the conversation | | `BRIDGE_CONVERSATION_0006` | Conversation With Inconsistent State | The conversation is in an inconsistent state; contact support to resolve | | `BRIDGE_CONVERSATION_0007` | Conversation Is Released | Conversation is released (`409` from `POST .../messages`) | | `BRIDGE_CONVERSATION_0101` | Internal User Already In Conversation | The internal user is already a participant in this conversation | | `BRIDGE_CONVERSATION_0102` | Internal User Not In Conversation | The internal user is not a participant in this conversation | | `BRIDGE_CONVERSATION_0103` | External User Already In Conversation | The external user is already a participant in this conversation | | `BRIDGE_CONVERSATION_0104` | External User Not In Conversation | The external user is not a participant in this conversation | | `BRIDGE_CONVERSATION_0105` | External User Already Use This Channel | The external user is already using this messaging channel in some conversation | | `BRIDGE_CONVERSATION_0201` | External Participants Required | At least one external participant is required to operate in a conversation | | `BRIDGE_CONVERSATION_0202` | Internal Participants Required | At least one internal participant is required to operate in a conversation | | `BRIDGE_CONVERSATION_0203` | User Is Not Admin | The user is not an administrator of this conversation | | `BRIDGE_CONVERSATION_0204` | Last Admin Removal Forbidden | The conversation must have at least one administrator | | `BRIDGE_CONVERSATION_0205` | Min Internal Users Required | The conversation must have a minimum number of internal participants | | `BRIDGE_CONVERSATION_0206` | Max Internal Participants Exceeded | The maximum number of internal participants for this conversation has been exceeded | | `BRIDGE_CONVERSATION_0207` | Min External Participants Required | The conversation must have a minimum number of external participants | | `BRIDGE_CONVERSATION_0208` | Max External Participants Exceeded | The maximum number of external participants for this conversation has been exceeded | | `BRIDGE_CONVERSATION_0210` | Min Participants Required | The conversation must have a minimum number of participants | | `BRIDGE_CONVERSATION_0211` | Max Participants Exceeded | The conversation must have a maximum number of participants | | `BRIDGE_CONVERSATION_0212` | Max Initial Messages Exceeded | The maximum number of initial messages has been exceeded | | `BRIDGE_CONVERSATION_0213` | Messages Not In Conversation | The messages must belong to the same conversation | | `BRIDGE_CONVERSATION_0601` | Onboarding Template Not Found | A template named in the onboarding override does not exist | | `BRIDGE_CONVERSATION_0602` | Onboarding Template Not In Workspace | A template named in the onboarding override belongs to another workspace | | `BRIDGE_CONVERSATION_0603` | Onboarding Template Not Approved | A template named in the onboarding override is not approved for the line a participant will be reached on | | `BRIDGE_CONVERSATION_0604` | Onboarding Template Missing Parameters | A template named in the onboarding override is missing values only the caller can provide | | `BRIDGE_CONVERSATION_0605` | Onboarding Template Unknown Parameters | The onboarding override names parameters the template does not declare | | `BRIDGE_CONVERSATION_0606` | Onboarding Template Parameters Not Supported | Parameters were sent for an onboarding template that is not a WhatsApp provider template | | `BRIDGE_CONVERSATION_0607` | Onboarding Template Invalid Parameter Values | Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent | | `BRIDGE_CONVERSATION_0608` | Onboarding Configured Template Requires Caller Input | A template in the workspace's onboarding sequence needs values only the caller can provide; a workspace admin must change the onboarding sequence | When creating a conversation, `BRIDGE_CONVERSATION_0105` returns `409` with `extra.reason` set to `PARTICIPANTS_MISMATCH`: a released conversation holds the Contact's line with other Contacts or lines. Request the same Contacts and lines, or use another line. `BRIDGE_CONVERSATION_0601` returns `404`, `0602` and `0603` return `400`, and `0604` to `0608` return `422`. See [Onboarding template parameters](https://docs.bridge.new/templates-and-parameters.md) for what each one carries in `extra` and how to fix it. ## External User Error Codes Error codes for external user (contact) operations. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_EXTERNAL_0001` | External User Not Found | The requested external user was not found | | `BRIDGE_EXTERNAL_0002` | External User Already Exists | An external user with the same identification data already exists | | `BRIDGE_EXTERNAL_0004` | External User Not In Workspace | One or more external users do not belong to the specified workspace | | `BRIDGE_EXTERNAL_0005` | External User Without Configured Field | External user does not have configured field; check the workspace or external information settings | | `BRIDGE_EXTERNAL_0007` | Cellphone Owned By Another Contact | The phone number is already an active identity of a different external user | | `BRIDGE_EXTERNAL_0013` | Email Owned By Another Contact | The email address is already an active identity of a different external user | | `BRIDGE_EXTERNAL_0101` | External User Operation Failed | An error occurred while operating on the external user | ## Internal User Error Codes Error codes for internal user operations. | Code | Readable Title | Message | | ---- | -------------- | ------- | | `BRIDGE_INTERNAL_0001` | Internal User Not Found | The internal user was not found | | `BRIDGE_INTERNAL_0002` | Internal Users Not In Workspace | The provided internal users do not belong to the specified workspace | | `BRIDGE_INTERNAL_0003` | Inactive Internal User | One or more internal users are inactive in the workspace; check the user status in the workspace settings | | `BRIDGE_INTERNAL_0004` | Internal User Without Configured Field | Internal user does not have configured field; check the workspace or internal information settings | | `BRIDGE_INTERNAL_0101` | Internal User Does Not Support Operation | The internal user does not support this operation | ## Provider Channel Error Codes Error codes for provider channel operations. | Code | Readable Title | Message | | ---- | -------------- | ------- | | `BRIDGE_PROVIDER_CHANNEL_0001` | Provider Channel Not Found | The provider channel was not found; verify the workspace has channels configured | When creating a conversation, this code is returned as `409` when no WhatsApp line is free for a Contact and there is no released conversation to recover, or when the `providerChannelId` you named is not available for that Contact. ## Rate Limit Error Codes Error codes returned when a workspace exceeds its request budget. See [Rate limits](https://docs.bridge.new/rate-limits.md) for the budget, the headers and a client that paces itself. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_RATE_LIMIT_0001` | Too Many Requests | The workspace has exhausted its request budget for the current window | This is the only code that should be retried automatically, and only after the delay given in the `Retry-After` header. Authentication failures are not rate-limit errors and retrying them on a schedule will never succeed. ## Request Error Codes Error codes returned before an operation runs, when the request itself cannot be processed. See [Changelog](https://docs.bridge.new/changelog.md) for parameters an endpoint will stop accepting. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_CORE_0101` | Invalid Field Format | The field format is invalid; provide a valid value for the field | | `BRIDGE_CORE_0102` | Missing Required Field | The request is missing required fields; review the operation | | `BRIDGE_CORE_0103` | Bad Request | The request is invalid; review the body and parameters | | `BRIDGE_CORE_0104` | Invalid Cursor | The provided cursor is invalid; use a cursor obtained from a previous response | None of these should be retried unchanged. `detail` describes what is wrong and, when it can, names the field or parameter at fault; the same request will fail the same way until you change it. ## Template Error Codes Error codes for template operations. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_TEMPLATE_0001` | Provider Template Not Found | No provider template found for the given workspace and name | Returned as `404` by `GET .../templates/{templateId}` when the id or name does not match a WhatsApp template in your workspace. ## Workspace Error Codes Error codes for workspace operations. | Code | Title | Message | | ---- | -------------- | ------- | | `BRIDGE_WORKSPACE_0001` | Workspace Not Found | The requested workspace was not found | | `BRIDGE_WORKSPACE_0002` | Workspace Not In Organization | The workspace does not belong to the specified organization | | `BRIDGE_WORKSPACE_0003` | Workspace Without Available Provider Channels | The workspace has no provider channels available | | `BRIDGE_WORKSPACE_0004` | Workspace Without Configured Field | Workspace without configured field (`409` from `POST .../conversations/{conversationId}/release`) | --- # Changelog Source: https://docs.bridge.new/changelog Changes to the Bridge API that affect your integration, newest first. ## Overview Changes that affect the calls you already make, newest first. Additive changes — a new endpoint, a new optional field — are not listed here unless they replace something being removed; they appear in the [REST API](https://docs.bridge.new/api-reference/health/health-check.md) reference when they ship. **Note** The older entries below did not record effective dates. Their deployment dates have not been verified; their order does not establish a release date. The retirement date for deprecated list filters is **not yet announced**. Keep using the documented current contract until an effective change is published, and use the available lookup endpoints for new integrations. ## Documentation improvements This revision clarifies the existing API contract and introduces task-based integration guides. It renames the landing-page feature to **Custom Connections**, explains outbound conversation reuse and recovery, and improves error and webhook guidance. The existing API signatures and `/lead-capture` documentation URLs are preserved. A documentation revision date is not an API deployment or deprecation date. --- ## Creating a conversation recovers a released one `POST /conversations` used to return `409 BRIDGE_PROVIDER_CHANNEL_0001` when no line was free. Now, if the requested Contacts have a conversation released with recovery, it is recovered and returned with `201` and its existing `id`, so you may receive an `id` you already stored. If that conversation has other Contacts or lines, the request returns `409 BRIDGE_CONVERSATION_0105`. See the [REST API](https://docs.bridge.new/api-reference/health/health-check.md) reference for details. --- ## Finding a contact or a user by an identifier **Warning** **This will remove query parameters that exist today.** They still work and are marked deprecated in the [REST API](https://docs.bridge.new/api-reference/health/health-check.md) reference. The date they stop being accepted will be published here before that happens; the lookup endpoints that replace them are available now. ### What changes **Available now:** `GET /contacts/lookup` and `GET /users/lookup` return one contact or one Bridge User (an internal user, in the API reference) by an identifier. **Deprecated, to be removed:** the list endpoints will stop filtering. `GET /contacts` and `GET /users` will keep `limit` and `cursor` and nothing else. | Deprecated | Replacement | | ------- | ----------- | | `GET /contacts?search=` — a cellphone | `GET /contacts/lookup?type=PHONE&value=…` | | `GET /contacts?search=` — an email | `GET /contacts/lookup?type=EMAIL&value=…` | | `GET /contacts?search=` — a name | **none** | | `GET /contacts?ownerEmail=` | **none** | | `GET /users?email=` | `GET /users/lookup?type=EMAIL&value=…` | | `GET /users?status=` | **none** — every row already carries `status` | Once removed, a parameter will be **refused**, not ignored. Sending one will return `400` with `BRIDGE_CORE_0103`, and the response will name the parameter. We chose this deliberately: a call that silently ignored your filter would hand you the first page of your whole workspace and let you treat it as a match. ### What to do **If you search by cellphone or email**, move to the matching lookup endpoint. It answers with the same object the list returns for each row, and returns `404` when nothing matches. `type` takes the identifier types the API already uses elsewhere — the same values as `identifierType` on a conversation participant. Contacts accept `ID`, `EMAIL` and `PHONE`; Bridge Users accept `ID` and `EMAIL`, since a Bridge User's cellphone is not an addressable identifier in Bridge. `ID` is accepted for the same reason: code that already carries an `{identifierType, identifier}` pair should not have to branch on one of the values to build a different URL. It returns exactly what `GET /contacts/{contactId}` returns, and that remains the canonical URL for a contact — prefer it when the id is what you hold. ```bash # Before curl "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts?search=%2B14084029292" \ -H "x-api-key: $BRIDGE_API_KEY" # After curl "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts/lookup?type=PHONE&value=%2B14084029292" \ -H "x-api-key: $BRIDGE_API_KEY" ``` A `PHONE` is read the same way as the cellphone you send when you create a contact: a number without a country code is read in your workspace's default country, and spaces and separators are ignored. An `EMAIL` has its domain lowercased, but its local part is matched exactly as sent. **Note** A cellphone in international form begins with `+`, which must be percent-encoded as `%2B` in a query string. Most HTTP clients do this for you when you pass parameters as a map rather than building the URL by hand. A `value` that does not match its `type` — not a well-formed email, cellphone or UUID — is rejected with `422` and `BRIDGE_CORE_0101` before any lookup happens. Handle it separately from `404` if you pass user input straight through: one says *you sent something that is not an identifier*, the other says *nobody here holds it*. **If you filter Bridge Users by status**, read `status` off each row instead. It is derived rather than stored, and it is already in every response. Note that today the list returns only active users unless you pass `status`; once the parameter is removed it will return active and disabled users alike. The same applies to `GET /users/lookup`: it returns the Bridge User whether active or disabled, preferring the active one when an email matches both. `GET /users?email=` returns nothing for a disabled user today, so check `status` on the response if you only act on active users. **If you search contacts by name**, there will be no replacement, and it is worth knowing what you would lose. The parameter only matches the **exact full name** — first name, one space, last name. It never matches a prefix, a partial, or a surname on its own. If it works for you, you are passing the complete name already. **If you filter contacts by owner**, there will be no replacement. List the page and filter on `ownerId` in your own code. `ownerId` is the id of the owning Bridge User, not an email: get it once with `GET /users/lookup?type=EMAIL&value=…` and compare against its `id`. ### Why Filtering on those parameters makes the cost of the call depend on the size of your workspace rather than the size of the answer. Looking up one contact by phone number in a large workspace reads tens of thousands of records to return one — and asking for a bigger page makes it slower, not faster. The lookup endpoints read only the records that hold that identifier. This is also why the filters are being removed rather than fixed: where a replacement exists it is strictly better, and the name search, which has none, never matched anything but the exact full name. --- ## Related Topics - [Error Codes](https://docs.bridge.new/error-codes.md) — Full reference, including `BRIDGE_CORE_0103` and `BRIDGE_CORE_0101` - [REST API Reference](https://docs.bridge.new/api-reference/health/health-check.md) — The lookup endpoints, their parameters and their responses - [Rate limits](https://docs.bridge.new/rate-limits.md) — What the API accepts per workspace, and how to back off correctly --- # Receive Bridge webhooks Source: https://docs.bridge.new/webhooks Connect an HTTPS receiver to Bridge events and understand authentication, acknowledgement and asynchronous processing. Webhooks send events **from Bridge to your system**. Configure an HTTPS callback and subscribe to the event families your integration needs. Bridge sends JSON using `POST`; your receiver authenticates and stores the event before returning `2xx`. Use the [REST Integrations API](https://docs.bridge.new/credentials.md) when your system needs to read or change a Bridge resource. A webhook subscription does not create a complete two-way CRM integration by itself: your receiver must map identifiers, process the event and implement any intended write back through the documented REST operation. ## Build the receiver ### Choose your events Read the [event reference](https://docs.bridge.new/webhooks/events.md) and select the family and subscription version that matches your workflow. ### Verify and store each request Follow [Verify signatures](https://docs.bridge.new/webhooks/verifying-signatures.md) for the exact HMAC serialization and [Receive events](https://docs.bridge.new/webhooks/receive-events.md) for a durable inbox example. ### Configure and test the callback Enter the URL, webhook API key and client secret in the [Bridge Admin Console](https://docs.bridge.new/webhooks/configuration.md). Check the test callback before enabling your business workflow. ```mermaid sequenceDiagram participant B as Bridge participant R as Your receiver participant I as Durable inbox participant W as Your worker B->>R: POST JSON event and authentication headers R->>R: Verify API key, HMAC and freshness policy R->>I: Commit verified event or confirm exact duplicate I-->>R: Durable acceptance R-->>B: 2xx acknowledgement W->>I: Read unprocessed events W->>W: Apply business action idempotently ``` ## Keep the credentials separate | Header | Purpose | | --- | --- | | `X-Bridge-API-Key` | Webhook API key configured for this callback. Compare it with your expected value. | | `X-Bridge-Signature` | `sha256=` plus HMAC-SHA256 of Bridge's canonical event representation, using your webhook client secret. | | `X-Bridge-Timestamp` | Unix seconds for a receiver freshness check. The HMAC does **not** include this header. | These webhook credentials are separate from the REST API's `x-api-key` and the browser's Custom Connections `captureKey`. Keep the webhook client secret on your server. ## What an acknowledgement means A `2xx` response means your receiver accepted the event. It does not establish that your CRM update or other business action completed. Persist first and process outside the request, so a slow downstream service does not hold up acknowledgement. The current HTTP sender makes three attempts per delivery operation, with one- and two-second waits and a default ten-second socket timeout. This is not a promise of three attempts across the entire event pipeline. Read [retry, duplicate and ordering behavior](https://docs.bridge.new/webhooks/receive-events.md) before choosing your recovery policy. Do not assume exactly-once delivery, a global event order, or a public replay endpoint. The [event reference](https://docs.bridge.new/webhooks/events.md) describes payloads; the [receiver guide](https://docs.bridge.new/webhooks/receive-events.md) explains how to handle them reliably. --- # Verify webhook requests Source: https://docs.bridge.new/webhooks/verifying-signatures Verify the webhook API key and the exact HMAC representation used by Bridge, then deduplicate accepted events. Verify each request before accepting it into your system. Use the **webhook** API key and client secret configured for this callback; these are separate from your REST Integrations API key. ## Authentication headers | Header | Check | | --- | --- | | `X-Bridge-API-Key` | Constant-time comparison with the webhook API key you configured | | `X-Bridge-Signature` | `sha256=` followed by the lowercase HMAC-SHA256 hex digest | | `X-Bridge-Timestamp` | Unix seconds within your accepted freshness window; the example allows five minutes in either direction | Header names are case-insensitive. ## Exactly what is signed Bridge builds the HMAC input from the JSON event using the Python expression below, then encodes that string as UTF-8: ```python json.dumps(event, sort_keys=True).encode("utf-8") ``` This sorts object keys recursively, preserves array order, escapes non-ASCII characters, and uses Python's default spaces after commas and colons. It does not append a newline. The key is the client secret encoded as UTF-8. This is a Python JSON serialization convention, not RFC 8785 / JCS. Do not replace it with a digest of arbitrary raw request bytes, compact JSON, a generic JavaScript `JSON.stringify`, or a timestamp-prefixed string. Whitespace, Unicode escaping and number formatting can change the HMAC input even when the parsed object looks equivalent. Use the Python verifier below or test another implementation against the vector before connecting it. **Warning** The current HMAC input contains the event JSON only. **`X-Bridge-Timestamp` is not included in the signature.** Check freshness, but do not treat the timestamp alone as cryptographic replay protection: a previously valid payload and signature can be presented with a different timestamp. Authenticate the webhook API key and use a durable inbox and idempotent business processing as described in [Receive events](https://docs.bridge.new/webhooks/receive-events.md). ## Python verifier Save this as `bridge_webhooks.py`. It returns the verified parsed object so downstream code uses the same interpretation that was authenticated. Secrets should come from server-side environment variables or your secret store. ```python import hashlib import hmac import json import re import sqlite3 import time class VerificationError(ValueError): pass def canonical_payload(event): # Match Bridge's Python json.dumps defaults: sort recursively, ASCII escapes, # a space after commas and colons, then UTF-8. This is not RFC 8785 / JCS. return json.dumps(event, sort_keys=True).encode("utf-8") def _unique_object(pairs): result = {} for key, value in pairs: if key in result: raise VerificationError("Duplicate JSON object key") result[key] = value return result def verify_webhook(raw_body, headers, webhook_api_key, client_secret, *, now=None, tolerance=300): headers = {key.lower(): value for key, value in headers.items()} received_key = headers.get("x-bridge-api-key", "") if not received_key or not webhook_api_key or not client_secret: raise VerificationError("Missing webhook credentials") if not hmac.compare_digest(received_key.encode("utf-8"), webhook_api_key.encode("utf-8")): raise VerificationError("Invalid webhook API key") received_signature = headers.get("x-bridge-signature", "") if not re.fullmatch(r"sha256=[0-9a-f]{64}", received_signature): raise VerificationError("Invalid signature format") timestamp = headers.get("x-bridge-timestamp", "") if not re.fullmatch(r"[0-9]+", timestamp): raise VerificationError("Invalid timestamp") current_time = time.time() if now is None else now if abs(current_time - int(timestamp)) > tolerance: raise VerificationError("Timestamp outside the permitted window") try: event = json.loads(raw_body.decode("utf-8"), object_pairs_hook=_unique_object) except (UnicodeDecodeError, json.JSONDecodeError) as exc: raise VerificationError("Invalid JSON body") from exc if not isinstance(event, dict): raise VerificationError("Expected a JSON object") expected = "sha256=" + hmac.new( client_secret.encode("utf-8"), canonical_payload(event), hashlib.sha256 ).hexdigest() if not hmac.compare_digest(expected, received_signature): raise VerificationError("Invalid webhook signature") return event ``` The five-minute window is receiver policy; keep your server clock synchronized. The verifier also rejects ambiguous duplicate JSON keys. Do not disable authentication when debugging a mismatch: check the configured webhook credentials and compare the canonical input against the fixture below. ## Reproducible signature vector These values are synthetic fixtures, not live credentials or an event to send to Bridge. When testing freshness checks, set the verifier's `now` argument to `1800000000`. | Value | Fixture | | --- | --- | | Client secret | `bridge-docs-test-secret` | | Webhook API key | `bridge-docs-test-key` | | Timestamp header | `1800000000` | | Expected signature | `sha256=5536c29fd98baab6ffe46dd9517adb185b32202864cbb5a76146172fc0b39423` | Event object: ```json { "eventId": "evt_docs_001", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_docs", "timestamp": "2026-01-01T00:00:00Z", "payload": { "name": "José", "tags": [ "café", "one" ], "active": true, "count": 2 } } ``` Exact signed JSON string (the `\u` sequences below are literal ASCII backslashes, not decoded characters): ```text {"entity": "contact", "eventId": "evt_docs_001", "eventType": "contact.updated", "payload": {"active": true, "count": 2, "name": "Jos\u00e9", "tags": ["caf\u00e9", "one"]}, "timestamp": "2026-01-01T00:00:00Z", "workspaceId": "ws_docs"} ``` Changing a field must fail verification. Changing only input key order or sending literal Unicode instead of JSON Unicode escapes must still verify after parsing and rebuilding the same canonical representation. ## After verification Commit the event to a durable inbox before acknowledging it. A valid HMAC confirms the authenticated event representation; it does not prove that your business action has run, that the event is new, or that it is the latest state of the resource. Continue with [delivery, duplicates and ordering](https://docs.bridge.new/webhooks/receive-events.md). --- # Receive events reliably Source: https://docs.bridge.new/webhooks/receive-events Verify, persist and acknowledge webhooks, then process duplicates and out-of-order events safely. A webhook receiver has two jobs: accept an authenticated event quickly, then process it reliably. Keep slow CRM calls, enrichment and other business work outside the HTTP request. ## Receive → verify → persist → acknowledge 1. Read the request body and headers. 2. Verify the webhook API key, canonical HMAC and timestamp policy with [the verifier](https://docs.bridge.new/webhooks/verifying-signatures.md). 3. Atomically store the verified event in a durable inbox, or confirm that this exact event is already there. 4. Return a `2xx` response promptly. Process stored events in a worker and make each business action idempotent. Return success only after durable acceptance. If storage is unavailable, return a non-`2xx` response so the delivery attempt is not acknowledged. A duplicate that is already stored should receive `2xx` again. ## Retry behavior The current sender makes up to **three HTTP attempts** for one delivery operation. It waits **one second**, then **two seconds**, before the remaining attempts. Any `2xx` response stops those attempts. A non-`2xx` response, a connection failure or a request exception can trigger the next attempt. The default socket timeout is **10 seconds** per attempt; acknowledge in a few seconds rather than relying on a 30-second allowance. The payload, signature and timestamp headers are reused within that delivery operation. These three attempts are a bound for one send operation, **not an end-to-end ceiling on all deliveries of an event**. If an upstream event is delivered again, it can invoke the sender again. No total retry count or replay horizon is promised here. Do not rely on a `Retry-After` response header to set Bridge's retry timing. If all attempts fail, the delivery is considered failed. Do not assume indefinite automatic retry or a public replay endpoint. For investigation, keep the event's workspace, type, ID and approximate time, and contact Bridge support. Do not include webhook credentials in support messages or application logs. ## Duplicates and event identity Your service may have committed an event even when Bridge did not receive your `2xx` response. Retrying it must not create a second CRM update, invoice, message or other business effect. Scope an inbox record to `workspaceId`, `eventType` and `eventId`. Also store a digest of the verified event. Do not assume `eventId` is a globally unique ID across every notification family: some notifications use an entity-derived ID. Retain distinct payloads that share an ID, then apply business idempotency for the operation your worker performs. The example below deduplicates exact repeated events using all three identifiers plus the SHA-256 fingerprint of the canonical event. This is an inbox key for this example, not a new Bridge request field. Do not expire a deduplication record merely because the five-minute timestamp window has passed. That header is not signed, so the window does not establish a safe replay expiry. Choose retention around your business reconciliation needs and keep destination-side business actions idempotent. The example does not automatically delete inbox records. ## Minimal durable receiver Add these definitions to the `bridge_webhooks.py` module from [Verify webhook requests](https://docs.bridge.new/webhooks/verifying-signatures.md). The verifier module already includes the imports used below. ```python class SQLiteInbox: """Single-service example inbox. Use a shared durable store for multiple replicas.""" def __init__(self, path): self.path = str(path) with sqlite3.connect(self.path) as db: db.execute("""CREATE TABLE IF NOT EXISTS webhook_inbox ( workspace_id TEXT NOT NULL, event_type TEXT NOT NULL, event_id TEXT NOT NULL, fingerprint TEXT NOT NULL, body TEXT NOT NULL, received_at REAL NOT NULL, processed INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(workspace_id, event_type, event_id, fingerprint) )""") def accept(self, event): identifiers = [event.get(key) for key in ("workspaceId", "eventType", "eventId")] if not all(isinstance(value, str) and value for value in identifiers): raise VerificationError("Missing event envelope identifiers") body = canonical_payload(event) fingerprint = hashlib.sha256(body).hexdigest() with sqlite3.connect(self.path, timeout=3) as db: cursor = db.execute( """INSERT OR IGNORE INTO webhook_inbox (workspace_id, event_type, event_id, fingerprint, body, received_at) VALUES (?, ?, ?, ?, ?, ?)""", (*identifiers, fingerprint, body.decode("utf-8"), time.time()), ) inserted = cursor.rowcount == 1 # Context manager commits before the request can be acknowledged. return inserted def make_wsgi_app(inbox, webhook_api_key, client_secret): """Verify, commit an inbox record, then acknowledge; workers process it later.""" def app(environ, start_response): if environ.get("REQUEST_METHOD") != "POST": start_response("405 Method Not Allowed", [("Allow", "POST")]) return [b""] try: length = int(environ.get("CONTENT_LENGTH") or "0") if length < 1: raise VerificationError("Missing JSON body") raw_body = environ["wsgi.input"].read(length) headers = { "x-bridge-api-key": environ.get("HTTP_X_BRIDGE_API_KEY", ""), "x-bridge-signature": environ.get("HTTP_X_BRIDGE_SIGNATURE", ""), "x-bridge-timestamp": environ.get("HTTP_X_BRIDGE_TIMESTAMP", ""), } event = verify_webhook(raw_body, headers, webhook_api_key, client_secret) inbox.accept(event) # A duplicate exact event is also acknowledged. except (VerificationError, ValueError): status, body = "400 Bad Request", b'{"accepted":false}' except sqlite3.Error: status, body = "503 Service Unavailable", b'{"accepted":false}' else: status, body = "200 OK", b'{"accepted":true}' start_response(status, [("Content-Type", "application/json"), ("Content-Length", str(len(body)))]) return [body] return app ``` Create the WSGI application in your server configuration: ```python import os from bridge_webhooks import SQLiteInbox, make_wsgi_app application = make_wsgi_app( SQLiteInbox(os.environ["WEBHOOK_INBOX_PATH"]), os.environ["BRIDGE_WEBHOOK_API_KEY"], os.environ["BRIDGE_WEBHOOK_CLIENT_SECRET"], ) ``` Use a durable database path for this single-service example. When you run multiple receiver replicas, use a shared store with an equivalent atomic uniqueness constraint. Enforce your service's request-size and network policies at the HTTP server, and terminate HTTPS there. This example stops at durable acceptance. A worker must read rows with `processed=0`, perform the business action idempotently, and mark them processed only after success. A local acknowledgement is not proof that the business action completed. ## Ordering and reconciliation Do not rely on a global delivery order. Different resource families and independent delivery attempts can interleave. Route on the published `eventType` and use the schema for that subscription. Where a payload includes `sequence`, treat it as a resource/stream ordering hint, not a global counter shared by all workspaces or event families. Do not invent it for events whose schema has no sequence. Preserve source timestamps and identifiers, and avoid replacing newer state with an older notification. Where the REST API supports reading the resource, fetch current state when an event leaves the result uncertain; otherwise use the event-family guidance or contact support. Do not require a universal `version` field in every event envelope. For the supported event families in this webhook service, the configured subscription version selects that family's registered transformer and payload schema. Follow the documented schema for that family and subscription; do not infer a version property that its envelope does not publish. ## Check the receiver before launch Verify the provided signature vector, a changed payload, a wrong API key, expired and future timestamps, duplicate delivery after a process restart, storage failure, and two distinct payloads sharing an ID. A re-timestamped replay of a previously signed payload demonstrates why the durable inbox is needed in addition to the timestamp check. Use Bridge's console test webhook to validate the connection and configured credentials after deploying your receiver. A successful test demonstrates the callback path; it does not establish delivery or ordering guarantees for every business event. --- # Configure webhooks Source: https://docs.bridge.new/webhooks/configuration Configure a callback URL, webhook credentials and event subscriptions in the Bridge Admin Console. You can manage all webhook settings directly from the [Bridge Admin Console](https://admin.bridge.new). This includes defining your webhook endpoint, authentication keys, and selecting which event types to subscribe to. --- ## Setting Up Webhooks Follow these steps to configure your webhook in the Bridge Admin Console: 1. **Log in** to your Bridge Admin Console. 2. Navigate to **Developers → Webhooks**. 3. Provide the following details: - **Webhook URL:** The full HTTPS URL of your endpoint. - **API Key:** Used for identifying your workspace. - **Client Secret:** Used to generate and verify webhook signatures (HMAC-SHA256). 4. **Select Event Types** you want to subscribe to. --- ## Native CRM connectors and custom webhooks A native CRM connector and a custom webhook are separate delivery paths. For a connected CRM, check the connector's active configuration and the features shown in the console. This page does not establish that every event is synchronized, that no setup is required, or that updates have a fixed real-time deadline. Configure a custom webhook when your service needs to receive an event and apply its own processing. You can subscribe to an event family that is also used by a native connector. If your receiver writes to the same CRM, coordinate the two paths to avoid applying the same business action twice. A custom webhook acknowledgement confirms your receiver's acceptance only. Use [durable acceptance and idempotent processing](https://docs.bridge.new/webhooks/receive-events.md); do not assume that two delivery paths provide exactly-once CRM updates. --- ## Event Subscription Options Bridge currently supports the following event categories: ### Conversation Summary Notifications v1 Receive a notification once per day, per conversation, when Bridge AI generates the daily summary. - `conversation_summary.created` ### Tasks Notifications v1 Receive notifications when tasks are created or their state changes. - `task.created` - `task.status_changed` - `task.assigned` - `task.unassigned` - `task.remove_reminder` - `task.field_updated` ### Contact Updates v1 Receive notifications when contacts are created, updated, or deleted. - `contact.created` - `contact.updated` - `contact.deleted` ### Call Notifications v1 Receive a single webhook for each lifecycle phase of a call (created, ringing, started, finished) plus the AI transcript once it is ready. Calls are not deleted. - `call.created` - `call.updated` - `call.transcription.created` ### Meeting Notifications v1 Receive a notification when a meeting reaches the CREATED state. Meetings are not deleted, so only the `meeting.updated` event is emitted. - `meeting.updated` ### Email Notifications v1 Receive a notification once an email has been processed and the AI summary is available. Emails are not deleted, so only the `email.updated` event is emitted. - `email.updated` --- ## Verifying Your Configuration Once you save your webhook configuration, Bridge automatically sends a **test webhook** to your endpoint to ensure it is reachable and correctly responding. Your endpoint must respond with: - **HTTP Status Code:** `200–299` - **Content-Type:** `application/json` (optional) - **Response Time:** acknowledge promptly after durable acceptance. The sender uses a default 10-second socket timeout per HTTP attempt; do not rely on a 30-second allowance. See [retry behavior](https://docs.bridge.new/webhooks/receive-events.md#retry-behavior). --- ## Managing Webhooks You can manage your webhook configuration anytime from the console: | Action | Description | | ------------------ | ------------------------------------------------------------------- | | **Edit** | Update the URL, API key, or subscribed events | | **Disable Events** | Temporarily pause specific event types without deleting the webhook | | **Delete** | Permanently remove a webhook configuration | --- ## Related Topics - [Overview](https://docs.bridge.new/webhooks.md) - [Verifying Signatures](https://docs.bridge.new/webhooks/verifying-signatures.md) - [Event Types](https://docs.bridge.new/webhooks/events.md) --- # Webhook events Source: https://docs.bridge.new/webhooks/events Event families, payload examples and subscription versions for Bridge webhooks. Bridge webhooks deliver structured event payloads in JSON format whenever specific actions occur in your workspace. Each event follows a consistent schema to make parsing and validation simple. --- ## Common Event Structure The following illustrates the common envelope; `"string"` is a type placeholder, not an event value to send. Read the family-specific payload examples below. Do not assume that `eventId` is globally unique across notification families. ```json { "eventId": "string", "eventType": "string", "entity": "string", "workspaceId": "string", "timestamp": "string", "payload": {} } ``` --- ## Conversation Summary Notifications v1 Triggered once per day, per conversation, when Bridge AI generates the daily summary. The summary captures the key points exchanged along with the internal and external participants involved. ### Event types | Event Type | Description | | --------------------------------- | ---------------------------------------------------- | | `conversation_summary.created` | A daily conversation summary was generated | ### Example payload ```json { "eventId": "evt_summary_001", "eventType": "conversation_summary.created", "entity": "conversation_summary", "workspaceId": "ws_123", "timestamp": "2026-05-19T05:03:15.910Z", "payload": { "conversationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "summaryDate": "2026-05-19", "summary": "- Advisor asked the customer about their preferred schedule and offered to book a product demo.\n- Customer replied they are unavailable on Monday morning.\n- Advisor offered alternative slots later in the week and is waiting for confirmation.", "externalUsers": [ { "id": "c1d2e3f4-a5b6-7890-cdef-012345678901", "first_name": "Ana", "last_name": "Garcia", "cellphone": "+57300000000" } ], "internalUsers": [ { "id": "d4e5f6a7-b8c9-0123-defa-234567890123", "first_name": "Bob", "last_name": "Smith", "cellphone": "+57301000000", "email": "bob.smith@example.com" } ], "initMessageId": "f1e2d3c4-b5a6-7890-fedc-ba0987654321", "endMessageId": "a9b8c7d6-e5f4-3210-abcd-ef9876543210", "createdAt": "2026-05-19T05:03:15.910Z", "updatedAt": "2026-05-19T05:03:15.910Z" } } ``` --- ## Task Updates v1 Triggered when tasks are created or their state changes (status, assignment, reminders). Payloads vary by event type. The `details` field in the payload describes what changed for that specific event. ### Event types | Event Type | Description | | ---------------------- | ------------------------------------------------- | | `task.created` | A new task was created | | `task.status_changed` | The task status changed (for example, from OPEN to CLOSED) | | `task.assigned` | A user was assigned to the task | | `task.unassigned` | A user was unassigned from the task | | `task.remove_reminder` | A task reminder was removed | | `task.field_updated` | A task field was updated | ### Example payloads ```json Created { "eventId": "evt_123456789", "eventType": "task.created", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:30:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example task description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:30:00.000Z" }, "assignees": [ { "assigneeId": "user_456", "assigneeType": "USER" } ], "conversations": [ { "id": "conv_123", "status": "ACTIVE", "createdAt": "2026-01-14T09:10:00.000Z", "updatedAt": "2026-01-14T09:10:00.000Z" } ] } } ``` ```json Assigned { "eventId": "evt_123456790", "eventType": "task.assigned", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:31:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "assignee": { "assigneeId": "user_456" } } } } ``` ```json Unassigned { "eventId": "evt_123456791", "eventType": "task.unassigned", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:32:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "assignee": { "assigneeId": "user_456" } } } } ``` ```json Status changed (open → closed) { "eventId": "evt_123456792", "eventType": "task.status_changed", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:33:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "statusChange": { "fromStatus": "OPEN", "toStatus": "CLOSED" } } } } ``` ```json Status changed (closed → open) { "eventId": "evt_123456793", "eventType": "task.status_changed", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:34:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example task description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:34:00.000Z" }, "conversations": [ { "id": "conv_123", "status": "ACTIVE", "createdAt": "2026-01-14T09:10:00.000Z", "updatedAt": "2026-01-14T09:10:00.000Z" } ], "details": { "statusChange": { "fromStatus": "CLOSED", "toStatus": "OPEN" } } } } ``` ```json Reminder removed { "eventId": "evt_123456794", "eventType": "task.remove_reminder", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:35:00.000Z", "payload": { "taskId": "task_456", "actorType": "USER", "actorId": "user_123", "details": { "reminder": { "reminderId": "rem_123" } } } } ``` ```json Field updated { "eventId": "evt_123456795", "eventType": "task.field_updated", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:36:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example updated description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:36:00.000Z" }, "details": { "fieldUpdate": { "changedFields": ["description"] } } } } ``` --- ## Contact Updates v1 Triggered when contact records are created, updated, or deleted. ### Event types | Event Type | Description | | ----------------- | ---------------------------- | | `contact.created` | A new contact was created | | `contact.updated` | A contact record was updated | | `contact.deleted` | A contact record was deleted | ### Example payloads Ownership fields depend on whether the contact is linked to an external CRM: - **CRM-synced contacts** carry `crmContactId` and `crmLastSyncedAt` (the contact's identity is owned by the CRM, not by an internal Bridge user). - **Bridge-native contacts** (no CRM link) carry `internalUserOwnerId` instead — the Bridge user that owns the record. These groups are mutually exclusive: a synced contact will not include `internalUserOwnerId`, and a non-synced contact will not include `crmContactId` or `crmLastSyncedAt`. Each entry in `openAttributes` and `closedAttributes` includes a human-readable `name` alongside the `customAttributeId`. For closed attributes, `closedCustomAttributeIds` is an array of `{ id, content }` objects, where `content` is the selected option's display label. ```json CRM-synced { "eventId": "evt_contact_001", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:30:00.000Z", "payload": { "id": "contact_123", "firstName": "John", "lastName": "Doe", "email": "john@example.com", "cellphone": "+1234567890", "languageCode": "EN", "openAttributes": [ { "customAttributeId": "attr_open_1", "name": "Account Number", "content": "14" } ], "closedAttributes": [ { "customAttributeId": "attr_closed_1", "name": "Preferred Language", "closedCustomAttributeIds": [ { "id": "opt_1", "content": "ENGLISH" } ] }, { "customAttributeId": "attr_closed_2", "name": "Software Tools", "closedCustomAttributeIds": [ { "id": "opt_2", "content": "Go" }, { "id": "opt_3", "content": "Postgres" } ] } ], "crmContactId": "crm_456", "crmLastSyncedAt": "2026-01-10T09:00:00.000Z", "createdAt": "2026-01-01T00:00:00.000Z", "updatedAt": "2026-01-15T10:30:00.000Z" } } ``` ```json Bridge-native (no CRM) { "eventId": "evt_contact_002", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:32:00.000Z", "payload": { "id": "contact_456", "firstName": "Jane", "lastName": "Smith", "email": "jane@example.com", "cellphone": "+1987654321", "languageCode": "EN", "openAttributes": [ { "customAttributeId": "attr_open_2", "name": "Education level", "content": "Secondary" } ], "closedAttributes": [ { "customAttributeId": "attr_closed_1", "name": "Preferred Language", "closedCustomAttributeIds": [ { "id": "opt_1", "content": "ENGLISH" } ] }, { "customAttributeId": "attr_closed_3", "name": "Gender", "closedCustomAttributeIds": [ { "id": "opt_4", "content": "FEMALE" } ] } ], "internalUserOwnerId": "user_789", "createdAt": "2026-01-05T15:47:49.000Z", "updatedAt": "2026-01-15T10:32:00.000Z" } } ``` --- ## Call Notifications v1 Triggered as a call moves through its lifecycle. Bridge emits at most one webhook per lifecycle phase per call, so your integration receives a clean four-phase timeline (created, ringing, started, finished) rather than every intermediate state transition Bridge writes internally. The current phase is derivable from the call state and the participants' statuses: | Phase | How to detect | | -------- | ------------------------------------------------------------------------ | | created | state is CREATED and no participant has joined or is ringing | | ringing | a participant has status RINGING and nobody has joined yet | | started | state is STARTED and two participants are JOINED | | finished | state is FINISHED | Missed calls (nobody answered) skip the started phase — the integration receives created, ringing, and finished only. Once a call finishes, Bridge runs the recording through an asynchronous AI transcription pipeline. When the transcript is ready, the integration receives an additional `call.transcription.created` event with the full transcript broken down into time-coded segments per speaker. This event arrives **after** the `call.updated (finished)` event, typically several seconds to a few minutes later depending on call length. Diarization (multi-speaker labelling) depends on the audio source quality — mono recordings may produce a single speaker label for the entire transcript. ### Event types | Event Type | Description | | ----------------------------- | ----------------------------------------------------------- | | `call.created` | A new call was provisioned | | `call.updated` | A call lifecycle phase changed (ringing, started, finished) | | `call.transcription.created` | The AI transcript for a finished call is ready | ### Example payloads ```json Created { "eventId": "evt_call_001", "eventType": "call.created", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:05.815Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "CREATED", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:05.815Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "INITIALIZED" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "INITIALIZED" } ] } } } ``` ```json Ringing { "eventId": "evt_call_002", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:06.243Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "CREATED", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:06.243Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "INITIALIZED" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "RINGING" } ] } } } ``` ```json Started { "eventId": "evt_call_003", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:12.771Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "STARTED", "startedAt": "2026-05-04T00:48:12.125Z", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:12.771Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "JOINED", "joinedAt": "2026-05-04T00:48:12.125Z" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "JOINED", "joinedAt": "2026-05-04T00:48:12.124Z" } ] } } } ``` ```json Finished { "eventId": "evt_call_004", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:20.113Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "FINISHED", "startedAt": "2026-05-04T00:48:12.125Z", "finishedAt": "2026-05-04T00:48:19.389Z", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:20.113Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "LEFT", "joinedAt": "2026-05-04T00:48:12.125Z", "leftAt": "2026-05-04T00:48:19.388Z" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "LEFT", "joinedAt": "2026-05-04T00:48:12.124Z", "leftAt": "2026-05-04T00:48:19.387Z" } ] } } } ``` ```json Transcription created { "eventId": "evt_call_005", "eventType": "call.transcription.created", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:50:14.231Z", "payload": { "callId": "call_abc123", "transcriptionId": "txn_xyz789", "conversationId": "conv_xyz", "duration": "27", "startedAt": "2026-05-04T00:48:12.125Z", "finishedAt": "2026-05-04T00:48:19.389Z", "transcript": [ { "speaker": "0", "text": "Hi, how can I help you today?", "start": 1.44, "end": 5.2 }, { "speaker": "1", "text": "I have a question about your product.", "start": 5.5, "end": 12.3 } ] } } ``` Each transcript segment carries the diarized `speaker` label (typically `"0"`, `"1"`, ...), the `text`, and `start`/`end` offsets in seconds from the call start. --- ## Meeting Notifications v1 Triggered when a meeting reaches the CREATED state. Meeting cancellations are surfaced through the corresponding email notification. ### Event types | Event Type | Description | | ----------------- | ------------------------------------------ | | `meeting.updated` | A meeting reached the `CREATED` state | ### Example payload ```json { "eventId": "evt_meeting_001", "eventType": "meeting.updated", "entity": "meeting", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:46:40.954Z", "payload": { "meetingId": "meeting_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "subject": "Meeting with John Smith", "providerType": "TEAMS", "status": "CREATED", "organizerInternalUserId": "user_internal_1", "internalParticipants": ["user_internal_1"], "externalParticipants": ["user_external_1"], "startDateTime": "2026-05-04T01:00:00.000Z", "endDateTime": "2026-05-04T01:15:00.000Z", "createdAt": "2026-05-04T00:46:29.944Z", "updatedAt": "2026-05-04T00:46:40.954Z", "provider": { "joinUrl": "https://teams.microsoft.com/l/meetup-join/...", "calendarEventId": "AAMkADhlMWVlMWJhLWUyZTMtNDllOC...", "chatId": "MWM1Zjg4MmUtZjk0Mi00YjJkLTgyNTItNmRiODNiZmM1NWEw", "providerMeetingId": "MSowODJkZmFjYy1iNDZmLTRiNDItOGYzOS0xMzI0NDcyMzUwMWUq..." } } } ``` --- ## Email Notifications v1 Triggered once an email has been processed and the AI summary is available. The `sentFromBridge` field indicates direction: true for outbound emails sent from the workspace, false for inbound emails received. ### Event types | Event Type | Description | | --------------- | ---------------------------------------------------- | | `email.updated` | An email reached the summarized state | ### Example payload ```json { "eventId": "evt_email_001", "eventType": "email.updated", "entity": "email", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:45:31.261Z", "payload": { "emailId": "email_abc123", "conversationId": "conv_xyz", "threadId": "AAQkADhlMWVlMWJhLWUyZTMtNDllOC05MDg2LWMzNjFkMTI5MjM4MA...", "providerType": "OUTLOOK", "status": "PROCESSED", "subject": "Project update", "sender": "jane@example.com", "recipients": [ { "recipientEmail": "john@example.com" } ], "summary": "Jane confirms the project is on track and shares next steps.", "importance": "NORMAL", "sentFromBridge": true, "hasAttachments": false, "sentAt": "2026-05-04T00:45:09.000Z", "createdAt": "2026-05-04T00:45:09.000Z", "updatedAt": "2026-05-04T00:45:31.261Z" } } ``` --- ## Notes - Bridge may add new event categories in the future. - Always check the event type field to determine which handler to execute. - Configure and support the version selected for each event subscription. The common envelope does not declare a universal `version` field; do not require or invent one. See [receiving events](https://docs.bridge.new/webhooks/receive-events.md) for duplicates and ordering. --- ## Related Topics - [Overview](https://docs.bridge.new/webhooks.md) - [Verifying Signatures](https://docs.bridge.new/webhooks/verifying-signatures.md) - [Console Configuration](https://docs.bridge.new/webhooks/configuration.md) --- # Custom Connections Source: https://docs.bridge.new/lead-capture/index Use Custom Connections to register leads from your landing page and queue an opening WhatsApp message. ## What this does Your landing page posts a lead to Bridge. Bridge then opens the WhatsApp conversation for you, using an approved template. You do not send the message; we do. **Warning** **A `202` response means the lead was accepted, not that a message was sent.** The first WhatsApp message is transmitted later by a separate service. Your thank-you copy must say something like "we'll message you shortly" — never "we've messaged you". ## What you need, and where it comes from Four values: the endpoint URL, your `captureKey`, the reCAPTCHA site key, and the reCAPTCHA action name. You do not assemble them by hand. In the Bridge admin console, under **LeadScout → Capture snippet**, an administrator of your workspace generates an integration example that already contains all four. They hand that block to whoever builds the page — that person never needs console access. **Note** The example is a starting point, not a drop-in script. You own your form markup and your consent wording; see [Consent requirements](https://docs.bridge.new/lead-capture/consent.md). ## Where to go next ### [Consent requirements](https://docs.bridge.new/lead-capture/consent.md) What your opt-in must say, and what you are attesting to. ### [Template requirements](https://docs.bridge.new/lead-capture/templates.md) Choose a supported Utility or Marketing template and understand the category requirements. ### [Integration guide](https://docs.bridge.new/lead-capture/integration.md) Add the form integration and handle CAPTCHA, consent, responses, and errors. ### [Error reference](https://docs.bridge.new/lead-capture/errors.md) Every response the endpoint can return, and which ones you can fix. --- # Consent requirements Source: https://docs.bridge.new/lead-capture/consent What your opt-in must say, and what you are attesting to when you send consent.status GRANTED. ## What your form must carry Your landing page must ask for an explicit opt-in before you submit a lead. The wording is yours to write, but it has to do two things Meta requires: - **Name your business.** Not "us", not "our partners" — the business the person will hear from. - **Say the person will receive WhatsApp communication from it.** Not "we may contact you"; name the channel. Meta lists a website form as a compliant way to collect this, so a checkbox on your landing page is enough — provided it says both of those things. **Warning** A pre-ticked box is not an opt-in. Neither is a line of small print under a submit button that the visitor never interacts with. The visitor has to take the action. ## What you are attesting to **Note** Sending `consent.status: "GRANTED"` is an attestation **you** are making. We do not and cannot verify that the visitor ticked a box — we record that you told us they did, and when. If your WhatsApp sending is ever restricted, that record is what is presented on your behalf. This is why `capturedAt` matters more than it looks. It must be the moment the visitor actually consented — not the moment your server got around to sending the request, and not a timestamp generated during a nightly batch. If the two ever have to be defended, the gap between them is the first thing anyone will look at. Send it as an ISO 8601 timestamp: ```json { "consent": { "status": "GRANTED", "capturedAt": "2026-08-26T14:32:07.184Z" } } ``` If consent was not given, do not submit the lead. A submission with any status other than `GRANTED` is rejected with `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED`. ## An example to adapt This is illustrative, not boilerplate to paste. Only you know what you will send and why, and the wording has to match that. > ☐ I agree to receive WhatsApp messages from **Acme Motors** about the quote I just > requested. What makes it work: it names the business, it names the channel, and it says what the messages will be about. What would break it: dropping the business name, saying "messages" without saying WhatsApp, or bundling the consent into a general terms-and-conditions checkbox that also covers unrelated things. --- # Template requirements Source: https://docs.bridge.new/lead-capture/templates Supported template categories and guidelines for opening conversations through Custom Connections. ## Supported template categories The template that opens the conversation can be either a **utility** or a **marketing** template: - **Utility templates**: Strictly transactional, echoing what the visitor just submitted (such as confirming receipt of an enquiry). These qualify for lower WhatsApp conversation rates. - **Marketing templates**: May include promotional language, discounts, special offers, or direct sales pitches. These are billed at standard WhatsApp marketing conversation rates. **Note** **Authentication** templates cannot be used with Custom Connections. Any template configured with the `AUTHENTICATION` category will be rejected. You configure and submit your templates directly in Meta WhatsApp Manager, and getting them approved is a prerequisite for going live. ## Meta classification and deliverability **Warning** Meta classifies templates by their content, not strictly by the category you select during submission. If a template submitted as UTILITY contains promotional language, Meta may reclassify it as MARKETING or reject it. Choosing the right category upfront prevents unintended classification issues and ensures expected deliverability and billing. ## Category examples **Utility (Transactional)** — acknowledges an enquiry without promotional offers: ```text Hi {{1}}, thanks for your enquiry about the {{2}}. A member of our team will follow up here shortly. ``` **Marketing (Promotional)** — includes promotional language, discounts, or sales offers: ```text Hi {{1}}, thanks for your enquiry about the {{2}}. Book this week and get 15% off — reply YES to claim. ``` ## Practical guidance - **Choose Utility** when your primary goal is rapid transactional follow-up confirming the visitor's request. Keep it strictly focused on echoing their submission without promotional hooks to maintain the utility category and lower messaging rate. - **Choose Marketing** when you want to immediately provide introductory discounts, promotional incentives, or catalog offers upon capture. - **Avoid Authentication templates**: Authentication templates are intended exclusively for one-time passwords and verification codes, and are rejected for campaign lead dispatches. - Once the person replies, you are in a normal conversation session and template category constraints no longer apply to incoming or agent responses. --- # Integration guide Source: https://docs.bridge.new/lead-capture/integration Connect a landing-page form to Bridge: example, CAPTCHA, consent, responses, and error handling. ## The example The Bridge admin console supplies a generated integration example with your workspace's configuration. The expanded example below adds validation and submission feedback. Copy the configuration values from your generated example into the placeholders before running it. Replace the form markup and the consent wording with your own. **Acme Motors is a fictional business used in the example below.** Replace it with the business the visitor will hear from, and describe the WhatsApp messages they are agreeing to receive. See [Consent requirements](https://docs.bridge.new/lead-capture/consent.md). The script shows validation, submission feedback, and error handling. Keep the request fields and reCAPTCHA action from your generated configuration unchanged. ```html

``` ## What the example does - Checks the form's required fields before obtaining a CAPTCHA token. - Records `consent.capturedAt` when the visitor selects the checkbox. If the browser restores an old checked state, it asks for a fresh consent action. - Allows one submission at a time and keeps the button disabled after acceptance to avoid another submission from this form instance. - Shows a `202` as accepted and queued, and displays the returned `requestId` as a support reference. It never says a WhatsApp message was delivered. - Shows recoverable CAPTCHA failures and creates a fresh token on each manual attempt. It does not retry a POST automatically. - Treats a network failure after submission as an uncertain outcome; it does not claim that the lead was rejected or safe to resend. This is client-side feedback, not a backend deduplication guarantee. Adapt the visible messages to your page and retain the [error reference](https://docs.bridge.new/lead-capture/errors.md) for diagnosis. ## Your capture key is not an API key **Note** If you have read the [Authentication](https://docs.bridge.new/credentials.md) page, it tells you never to put a key in frontend code. That rule is about the Integrations API key, and it still holds. Your `captureKey` is a different kind of value. Unlike the `x-api-key` used by the Integrations API, your `captureKey` is designed to live in your page's HTML where anyone can read it. It grants no read access to anything: it only identifies which workspace a submission belongs to. Abuse is bounded by two other checks — the reCAPTCHA token, and the fact that submissions are only accepted from the domains registered for your workspace. Never use your Integrations API key here, and never put one in a page. ## Put the workspace id on the URL The workspace id goes in the request body **and** on the URL as `?workspaceId=...`. It has to be in both places: a browser sends a CORS preflight before the real request, and that preflight carries no body — so without the id on the URL we cannot tell which workspace you are, cannot return the header that authorises your domain, and the browser blocks the request before it is ever sent. The failure this causes is confusing, which is why it is worth getting right the first time: you will see a CORS error in the browser console and no request in our logs at all, because the real request never left the page. ## Mint the captcha token when the form is submitted A reCAPTCHA v3 token is valid for about two minutes. Minting it when the page loads means it is often already expired by the time somebody finishes typing, and it comes back rejected — as a `403`, which looks like a permissions problem rather than a timing one. ## Mint a new token for every attempt A token verifies exactly once. If a submission fails and you retry with the same token, the replay is indistinguishable from an attack and returns the same error a bot would get. Always call `grecaptcha.execute` again before retrying. ## What to send The [endpoint reference](https://docs.bridge.new/api-reference/campaign-leads/register-a-campaign-lead.md) carries the full contract. These are the fields whose meaning is not obvious from the schema alone: ### `brandId` (`string`) The brand your landing page sells — not a line, channel or phone number id. Required only if your workspace has brands enabled. **A line id is never required.** ### `landingUri` (`string`) The page's origin and path, without the query string. Your UTMs travel separately in `utm`, and a raw query string often carries click ids or session tokens that should not be stored. Send `https://example.com/offer`, not `https://example.com/offer?gclid=...`. ### `consent` (`object`) Your attestation that the visitor opted in, and when. See [Consent requirements](https://docs.bridge.new/lead-capture/consent.md) — the wording on your form is not optional. ### `utm` (`object`) Collected from the query string against an allowlist: `utm_*` parameters plus any extra names you configure in the console. This is an allowlist rather than a denylist on purpose — over-collecting here is not reversible. ## After you submit A `202` means the lead was accepted and queued. It does **not** mean a message was sent — that happens later, in a separate service. Tell the visitor you will message them shortly. Anything else is an error. See the [error reference](https://docs.bridge.new/lead-capture/errors.md) for what each one means and whether it is yours to fix. --- # Error reference Source: https://docs.bridge.new/lead-capture/errors Every response the Custom Connections endpoint can return, and whether you can fix it. Error responses are [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem details: a `type`, a `title`, a `status`, and sometimes a `detail`. **Note** **Error responses do not carry a request id.** Only a successful `202` does. If you need to raise something with support, report the page URL and the approximate time instead. ## Every response | Status | `type` | What happened | Can you fix it? | | --- | --- | --- | --- | | `400` | `invalid_payload` | A field is missing or malformed. | Yes | | `400` | `BRIDGE.CAMPAIGN_LEADS.INVALID_PHONE` | The phone number could not be read as a real number. | Yes — validate before submitting | | `400` | `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED` | `consent.status` was not `GRANTED`. | Yes | | `400` | `BRIDGE.CAMPAIGN_LEADS.BRAND_OR_LINE_REQUIRED` | Your workspace has brands enabled and no `brandId` was sent. | Yes | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_DISABLED` | The Custom Connections feature is not enabled for this workspace. | No — contact Bridge | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_KEY_MISMATCH` | The capture key is missing or wrong. | Yes | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_REJECTED` | The captcha token was missing, expired, already used, or scored too low. | Sometimes — see below | | `403` | `BRIDGE.CAMPAIGN_LEADS.ORIGIN_NOT_ALLOWED` | The page's domain is not registered for this workspace. | No — contact Bridge | | `422` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_PROVIDER_UNAVAILABLE` | We could not reach the captcha provider. | Retrying is safe | | `500` | `unexpected_error` | Something failed on our side. | No | Only the first failure is reported. Checks run in this order: workspace and capture key, then the phone number, then consent, then the brand, then the captcha and finally the domain. Fixing one error can reveal the next. ## About the captcha rejection `CAPTCHA_REJECTED` covers four different situations. Check the token handling in your integration before attributing a rejection to the score: - **The token expired.** It was minted too early. A reCAPTCHA v3 token lasts about two minutes; mint it when the form is submitted, not when the page loads. - **The token was already used.** A token verifies once. If you retried a failed submission without minting a new token, the replay is rejected. - **No token was sent.** Make sure your client obtains a token and includes it in `recaptchaToken` on every submission. - **The score was too low.** The anti-bot check rejected this attempt. Do not bypass it. All four situations return the same code, so the response alone does not identify the cause. First check that the token is present, minted on submit, and fresh for every attempt. ## About the 422 This is a transient failure on our side: we could not reach the captcha provider, so we could not decide whether the submission was genuine. **Retrying is safe.** The lead is preserved when this happens, and a retry cannot produce a duplicate message. Mint a fresh captcha token for the retry, as you would for any other one. ## About the domain error The ordering here is genuinely surprising, so it is worth stating plainly. Your page's domain is checked against the domains registered for your workspace — but the domain we check is the one the **captcha provider reports**, not the one in the request's own headers. That check happens *after* the token verifies. The practical consequence: a page served from an unregistered domain fails at the captcha stage with `ORIGIN_NOT_ALLOWED`, not with a CORS error. If you are seeing this while your integration otherwise works, the domain is missing from your workspace configuration — contact Bridge to have it added. --- # Health check Source: https://docs.bridge.new/api-reference/health/health-check **Operation reference:** `get /bridge/api/health` **operationId:** `health_bridge_api_health_get` Health check endpoint to verify that the API is up and running. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Get conversation by id Source: https://docs.bridge.new/api-reference/conversations-api/get-conversation-by-id **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}` **operationId:** `get_conversation_by_id_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__get` Get a specific conversation by its unique identifier within the workspace. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Update conversation Source: https://docs.bridge.new/api-reference/conversations-api/update-conversation **Operation reference:** `patch /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}` **operationId:** `update_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__patch` Update conversation details including participants, status, and name. Support partial updates - only include the fields you want to change. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Retrieve conversations with flexible filtering options Source: https://docs.bridge.new/api-reference/conversations-api/retrieve-conversations-with-flexible-filtering-options **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations` **operationId:** `get_conversations_bridge_api_v1_workspaces__workspaceId__conversations_get` Retrieve conversations with flexible filtering options. Can search by external user identifiers (ID, email, phone) or internal participants, with support for pagination and status filtering. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Creates a new conversation with flexible user identification Source: https://docs.bridge.new/api-reference/conversations-api/creates-a-new-conversation-with-flexible-user-identification **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations` **operationId:** `create_conversation_bridge_api_v1_workspaces__workspaceId__conversations_post` Create a new conversation with flexible user identification. External users can be identified by ID, email, or phone. Internal users are only assigned when explicitly specified; otherwise, conversations are auto-assigned by round-robin through a team or left open for any available internal user. When no line is free and the Contacts have a released conversation with exactly the requested participants, that conversation is recovered and returned instead, keeping its `id` and history. The request's `name` and `status` are not applied to it. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Release conversation Source: https://docs.bridge.new/api-reference/conversations-api/release-conversation **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}/release` **operationId:** `release_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__release_post` Release a conversation: mark as released, remove external participants, move to RELEASED section. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Create a new message Source: https://docs.bridge.new/api-reference/messages-api/create-a-new-message **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/messages` **operationId:** `create_message_bridge_api_v1_workspaces__workspaceId__messages_post` Create a new message within a specified conversation. For a text message or an uploaded attachment, include all required fields: `conversationId`, `messageBody`, and `enableExternalBroadcast`. Attach uploaded files with their returned identifiers in `mediaIds`; see [Send an attachment](https://docs.bridge.new/guides/send-attachments.md). A successful response returns `messageId`; it does not contain a provider delivery receipt. See [Responses and retries](https://docs.bridge.new/guides/responses.md). [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Retrieve a contact by an identifier Source: https://docs.bridge.new/api-reference/contacts-api/retrieve-a-contact-by-an-identifier **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/lookup` **operationId:** `retrieve_contact_by_identifier_bridge_api_v1_workspaces__workspaceId__contacts_lookup_get` Get a specific contact by any of its identifiers within the workspace. `type=ID` returns the same contact as GET /contacts/{contactId}, which is the canonical URL for a contact and the one to prefer when the id is what you hold. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Retrieve a contact by id Source: https://docs.bridge.new/api-reference/contacts-api/retrieve-a-contact-by-id **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}` **operationId:** `retrieve_contact_by_id_bridge_api_v1_workspaces__workspaceId__contacts__contactId__get` Get a specific contact by its unique identifier within the workspace. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Update contact Source: https://docs.bridge.new/api-reference/contacts-api/update-contact **Operation reference:** `patch /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}` **operationId:** `update_contact_bridge_api_v1_workspaces__workspaceId__contacts__contactId__patch` Update a contact in the specified workspace. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # List contacts Source: https://docs.bridge.new/api-reference/contacts-api/list-contacts **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts` **operationId:** `get_contacts_bridge_api_v1_workspaces__workspaceId__contacts_get` Retrieve a paginated list of contacts within the workspace. Ordered by creation date. The `ownerEmail` and `search` filters are deprecated and will be removed; to find one contact by an identifier, use /contacts/lookup. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Create a new contact Source: https://docs.bridge.new/api-reference/contacts-api/create-a-new-contact **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts` **operationId:** `create_contact_bridge_api_v1_workspaces__workspaceId__contacts_post` Create a new contact in the specified workspace. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Create or update a contact Source: https://docs.bridge.new/api-reference/contacts-api/create-or-update-a-contact **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts/partial` **operationId:** `create_partial_contact_bridge_api_v1_workspaces__workspaceId__contacts_partial_post` Create or update a contact using only cellphone. Classifies as NORMAL or PARTIAL. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Create presigned uploads for files Source: https://docs.bridge.new/api-reference/files-api/create-presigned-uploads-for-files **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/files` **operationId:** `create_preloaded_files_bridge_api_v1_workspaces__workspaceId__files_post` Upload an attachment, such as a PDF, image, or document, before creating a message. This operation returns presigned PUT data; the file bytes are uploaded separately. After the upload succeeds, use the returned `mediaId` in the sending operation. Follow [Send an attachment](https://docs.bridge.new/guides/send-attachments.md) for the checksum, upload, and message steps. Generates presigned URLs to upload files (Presigned PUT). Validates extension, contentType, and type-specific limits. Checksum required: send SHA-256 digest in checksumBase64 (Base64). Upload must include header x-amz-checksum-sha256 with the same value. --- To upload your files, you MUST use the returned presigned URL with the HTTP PUT method. Ensure that you upload the file exactly to the URL indicated, without modifications (as required by AWS S3 Presigned URL PUT usage). Refer to the official AWS S3 documentation on Presigned PUT URLs for details: [AWS S3 Presigned PUT Documentation](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html). Be sure to include all required headers as specified in the response (e.g., 'x-amz-checksum-sha256' with the correct SHA-256 value). If you fail to use the correct HTTP method or headers, AWS will reject the upload request.
TypeExtensionContent TypeMax Size
Image.jpegimage/jpeg16 MB
.jpgimage/jpeg
.pngimage/png
.webpimage/webp
GIF.gifimage/gif3 MB
.mp4video/mp4
Video.avivideo/x-msvideo64 MB
.movvideo/quicktime
.mp4video/mp4
Audio.m4aaudio/mp416 MB
.mp3audio/mpeg
.oggaudio/ogg
.wavaudio/wav
Document.docapplication/msword100 MB
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.pdfapplication/pdf
.pptapplication/vnd.ms-powerpoint
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.txttext/plain
.xlsapplication/vnd.ms-excel
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
[Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Retrieve custom attributes by workspaceid Source: https://docs.bridge.new/api-reference/custom-attributes-api/retrieve-custom-attributes-by-workspaceid **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/settings/attributes` **operationId:** `get_custom_attributes_by_workspace_bridge_api_v1_workspaces__workspaceId__settings_attributes_get` Return the custom attributes for the specified workspace. By default, only **active** attributes are returned (those without a past `deletedAt`). **Filters:** - `category` — Filter by `OPEN` or `CLOSED`. Omit to return all categories. - `includeArchived` — Set to `true` to include archived attributes (those with a past `deletedAt`). Default: `false`. - `isRequired` — Set to `true` to return only required attributes, `false` for optional only. Omit to return all. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Get provider channels by workspace id Source: https://docs.bridge.new/api-reference/provider-channels-api/get-provider-channels-by-workspace-id **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels` **operationId:** `get_provider_channels_by_workspace_id_bridge_api_v1_workspaces__workspaceId__provider_channels_get` Get provider channels by workspace identifier. This response exposes each channel's `provider` and phone-like `identifier`; it does not return a `providerChannelId`. For an Agent's lines, read `agents[].lines[].providerChannelId` from the Agents list. Do not substitute a phone number for a channel ID. See [Concepts and IDs](https://docs.bridge.new/guides/identifiers.md). [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Get provider channels by workspace id and provider type Source: https://docs.bridge.new/api-reference/provider-channels-api/get-provider-channels-by-workspace-id-and-provider-type **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels/{messageProviderType}` **operationId:** `get_provider_channels_by_workspace_id_and_provider_type_bridge_api_v1_workspaces__workspaceId__provider_channels__messageProviderType__get` Get provider channels by workspace identifier and provider type. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Initiate a leadscout outbound conversation with a known lead Source: https://docs.bridge.new/api-reference/leadscout-api/initiate-a-leadscout-outbound-conversation-with-a-known-lead **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound` **operationId:** `initiate_leadscout_outbound_bridge_api_v1_workspaces__workspaceId__leadscout_outbound_post` Start a LeadScout outbound conversation with a known Contact. The Contact must already exist. Bridge resolves a prospecting Agent for an eligible WhatsApp line. The template is referenced by template.id or template.name; the id wins when both are supplied. It must exist and be APPROVED, and any handoffOverride Bridge User must be valid. An explicit contact.providerChannelId is respected. Without one, automatic selection prefers a free line, then a released recoverable conversation with this Contact, then an occupied active conversation only when forceSend=true. Availability is per Contact on each line, not global line occupancy. forceSend=true reuses an eligible active conversation; it does not ignore it or create a fresh one. A successful reuse returns alreadyInitiated=true and persists the new template and follow-ups. A recoverable released conversation can be recovered with either value, retains its ID, and returns recovered=true. Blocked and released nonrecoverable conversations are not made usable by this flag. The legacy route can reuse a conversation held by a human or another Agent; unlike Agents outbound, it does not enforce the requested-Agent controller check. A nonexpired open LeadScout session still blocks a new outbound request with 409 BRIDGE_AI_LEADSCOUT_0017; inability to finalize an expired session returns 409 BRIDGE_AI_LEADSCOUT_0018. Other validation still applies. Additional messages are persisted; persistence does not prove delivery or a wait for the lead to reply. A failed request can leave partial work, so do not treat forceSend as idempotency or blindly retry an uncertain result. See [the complete outbound guide](https://docs.bridge.new/guides/agent-outbound.md) for the false/true matrix, response flags, differences from Agents outbound, errors and handoff. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Request a manual handoff of a leadscout conversation to internal users Source: https://docs.bridge.new/api-reference/leadscout-api/request-a-manual-handoff-of-a-leadscout-conversation-to-internal-users **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/conversations/{conversationId}/handoff` **operationId:** `request_leadscout_handoff_bridge_api_v1_workspaces__workspaceId__leadscout_conversations__conversationId__handoff_post` Request a manual handoff of a LeadScout-controlled conversation to one or more internal users. The request is acknowledged with `202 Accepted`; assignment is processed asynchronously. The response echoes the requested assignees and a tracking id for correlation. Internal-user resolution (by ID or EMAIL) happens downstream and is not reflected in this response. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Discover a templates agnostic variable inventory Source: https://docs.bridge.new/api-reference/templates-api/discover-a-templates-agnostic-variable-inventory **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId}` **operationId:** `get_template_discovery_bridge_api_v1_workspaces__workspaceId__templates__templateId__get` Return a template's variables — agnostic `key`/`label`/`callerMustSupply`/`isCustom`/`default`. Never a Meta slot address or index. `templateId` accepts either the template's `id` or its `name`. Outbound operations accept `template.id` or `template.name`, with a nonblank id taking precedence. Conversation onboarding uses `onboardingTemplates[].templateId`. Use the selector required by the sending operation. See [the template recipe](https://docs.bridge.new/guides/send-template.md). A variable with `callerMustSupply: true` has no declared source — the caller must include its `key` in `parameters` when sending, or the send fails with a 422 naming that same `key`. A variable with `callerMustSupply: false` is either resolved by Bridge on its own (e.g. the recipient's first name) or already has a value the caller may optionally override. A variable with `isCustom: true` is a value only the caller knows, with a `default`: send it in `parameters` to use your own value, or leave it out (or blank) and `default` goes out. Error codes: - BRIDGE_CORE_0301: workspace in the path does not match the caller's own workspace (403) - BRIDGE_TEMPLATE_0001: no PROVIDER_TEMPLATE found for this workspace and identifier — covers an unknown id/name, a template that belongs to another workspace, and a template that is not a PROVIDER_TEMPLATE, identically (404); this endpoint never confirms the existence of a template outside the caller's own workspace [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Retrieve an internal user by an identifier Source: https://docs.bridge.new/api-reference/internal-users-api/retrieve-an-internal-user-by-an-identifier **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/users/lookup` **operationId:** `retrieve_internal_user_by_identifier_bridge_api_v1_workspaces__workspaceId__users_lookup_get` Get a specific Bridge User by any of its identifiers within the workspace. `type=ID` returns the same user as GET /users/{userId}, which is the canonical URL for an internal user and the one to prefer when the id is what you hold. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Retrieve an internal user by id Source: https://docs.bridge.new/api-reference/internal-users-api/retrieve-an-internal-user-by-id **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/users/{userId}` **operationId:** `retrieve_internal_user_by_id_bridge_api_v1_workspaces__workspaceId__users__userId__get` Get a specific internal user (human agent) by its unique identifier within the workspace. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # List internal users Source: https://docs.bridge.new/api-reference/internal-users-api/list-internal-users **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/users` **operationId:** `get_internal_users_bridge_api_v1_workspaces__workspaceId__users_get` Retrieve a paginated list of internal users within the workspace. Ordered by creation date. The `email` and `status` filters are deprecated and will be removed; to find one internal user by an identifier, use /users/lookup. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # List the agents of a workspace Source: https://docs.bridge.new/api-reference/agents-api/list-the-agents-of-a-workspace **Operation reference:** `get /bridge/api/v1/workspaces/{workspaceId}/agents` **operationId:** `list_agents_bridge_api_v1_workspaces__workspaceId__agents_get` List the workspace's Agents with their status, availability and lines. Every Agent is listed whatever its status; `available` tells whether it can start conversations. A page can hold fewer than `limit` items; keep paging while `cursor` is not null. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Start an outbound conversation with a contact as a given agent Source: https://docs.bridge.new/api-reference/agents-api/start-an-outbound-conversation-with-a-contact-as-a-given-agent **Operation reference:** `post /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound` **operationId:** `start_agent_outbound_bridge_api_v1_workspaces__workspaceId__agents__agentId__outbound_post` Start an outbound conversation with a known Contact, answered by the given Agent. Works for LeadScout and Service Agents. The Contact is resolved first, then the Agent, which must exist in the workspace and be available (see `GET /agents`). The template is referenced by `template.id` or `template.name` (the id wins when both are sent), must exist and be APPROVED, and a `handoffOverride` Bridge User must be valid. If `template.media.mediaId` is unknown, the request fails with 400 `BRIDGE_AI_LEADSCOUT_0016` only after the conversation was created or recovered, so a retry after that error may answer differently. Body rules (`consent.status=GRANTED` without `capturedAt`, `template.media` without exactly one of `mediaId` or `url`) fail with 400 `BRIDGE_CORE_0103`. The conversation opens on one of the Agent's active WhatsApp lines, controlled by the Agent, with the template as its first message. A line is picked in this order: - A free line. - Otherwise, a line holding a released conversation with this Contact that can be recovered. Recovering returns `recovered=true` and replaces the previous outbound context and `agentContext`. This happens even with `forceSend=false`. - Otherwise, when no line is free or recoverable: `forceSend=false` (default) fails with 409 `BRIDGE_AI_LEADSCOUT_0008`; `forceSend=true` reuses a line occupied by an active conversation with this Contact, preferring one this Agent controls. If the chosen conversation is held by another Agent or a Bridge User, the call fails with 409 `BRIDGE_AI_AGENT_OUTBOUND_0006` and nothing is written. Release it first, then retry. Lines whose conversation is blocked or was released without recovery are never used, so if no line is occupied by an active conversation the call fails with 409 `BRIDGE_AI_LEADSCOUT_0008` even with `forceSend=true`. `contact.providerChannelId` is a preference: the pinned line is used when it is free or recoverable; otherwise the same order applies over all the Agent's lines. Among occupied lines, one this Agent controls comes first; if none does, the pinned line is the one reused (and may fail with 0006). Reusing a conversation depends on the Agent type: - LeadScout: if its LeadScout session is still open and not expired, the call fails with 409 `BRIDGE_AI_LEADSCOUT_0017` (`extra` carries `conversationId`, `sessionId` and `stage`). If an expired session cannot be finalized, it fails with 409 `BRIDGE_AI_LEADSCOUT_0018`. - Service Agent: an open, unexpired service session is continued; an expired one is closed as abandoned and a new one opens. See [the complete outbound guide](https://docs.bridge.new/guides/agent-outbound.md) for prerequisites, the forceSend decision table, recovery, partial work and safe retry decisions. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Register a campaign lead Source: https://docs.bridge.new/api-reference/campaign-leads/register-a-campaign-lead **Operation reference:** `post /leadscout/campaign-leads` **operationId:** `create_campaign_lead_leadscout_campaign_leads_post` Registers a lead captured by a tenant's landing page and queues the first outbound WhatsApp message. A 202 means the lead was accepted, not that a message was sent. [Exact OpenAPI contract](https://docs.bridge.new/api-reference/campaign-leads.openapi.yaml) This corpus contains guides and operation descriptions. It does not embed every request and response schema. Read the linked OpenAPI contract before generating a request. --- # Integra tus sistemas con Bridge Source: https://docs.bridge.new/es/index Conecta tu CRM, automatizaciones o landing page mediante la API REST, los webhooks y Custom Connections. Implementa con tu herramienta de programación preferida ## Conecta tu asistente de programación con IA Dale a tu herramienta de programación la documentación actual de Bridge. Elígela abajo para ver la configuración, un ejemplo de prompt y la prueba de conexión. [Codex →](https://docs.bridge.new/es/connect-your-agent.md#codex) [Claude Code →](https://docs.bridge.new/es/connect-your-agent.md#claude-code) [Cursor →](https://docs.bridge.new/es/connect-your-agent.md#cursor) [GitHub Copilot →](https://docs.bridge.new/es/connect-your-agent.md#github-copilot) Leer la documentación no requiere una clave de API de Bridge. El acceso al espacio de trabajo se configura por separado. ## Elige tu integración ### [API REST](https://docs.bridge.new/es/credentials.md) Crea contactos, conversaciones y mensajes desde tu servidor. **Acceso:** `x-api-key` desde el servidor. ### [Webhooks](https://docs.bridge.new/es/webhooks.md) Recibe eventos de Bridge en tu endpoint HTTPS. **Acceso:** verifica las credenciales del webhook y su vigencia. ### [Custom Connections](https://docs.bridge.new/es/lead-capture/index.md) Captura leads de landing pages y encola un mensaje inicial de WhatsApp. **Acceso:** `captureKey` y reCAPTCHA; sin clave de la API REST. ## Haz tu primera solicitud a la API REST ### Obtén tus credenciales de API Sigue la guía de [autenticación](https://docs.bridge.new/es/credentials.md) para generar una clave de API en la consola de administración de Bridge. Si necesitas acceso, pídeselo al administrador de Bridge. Guarda la clave en tu servidor. ### Comprueba la conexión Usa el encabezado `x-api-key` para llamar a la [comprobación de estado](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md) autenticada en `https://api-connect-us.bridge.new/bridge/api/health`. Continúa en la pestaña **API REST**. Cada endpoint detalla sus campos, respuestas y ejemplos. **Nota** Custom Connections usa otro endpoint y una `captureKey` pública. Sigue su [guía de integración](https://docs.bridge.new/es/lead-capture/integration.md). Un `202` confirma la aceptación de la solicitud, no la entrega del mensaje de WhatsApp. ## Implementa a partir del contrato publicado - [Crea un contacto y envía un mensaje](https://docs.bridge.new/es/guides/first-conversation.md): sigue el flujo completo de contacto → conversación → mensaje. - [Envía un PDF u otro adjunto](https://docs.bridge.new/es/guides/send-attachments.md): checksum, URL de carga, carga del archivo y mensaje. - [Envía una plantilla de WhatsApp](https://docs.bridge.new/es/guides/send-template.md): consulta las variables y proporciona los valores que debe aportar quien hace la solicitud. - [Inicia una conversación saliente con un agente y transfiérela](https://docs.bridge.new/es/guides/agent-outbound.md): elige un agente y entiende `forceSend`, la reutilización y la recuperación. - [Consulta los identificadores](https://docs.bridge.new/es/guides/identifiers.md) y [recorre los resultados paginados](https://docs.bridge.new/es/guides/pagination.md): usa los IDs y cursores correctos. - [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md): administra el presupuesto compartido y maneja respuestas `429`. - [Códigos de error](https://docs.bridge.new/es/error-codes.md): interpreta los errores de la API REST. Custom Connections tiene su propia [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md). - [Parámetros de plantillas de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md): abre conversaciones con plantillas y proporciona sus variables. - [Registro de cambios](https://docs.bridge.new/es/changelog.md): revisa los cambios que afectan las integraciones. Lee sin MCP mediante el [índice trilingüe](https://docs.bridge.new/llms.txt), el [índice en español](https://docs.bridge.new/llms-es.json), la [documentación reunida en español](https://docs.bridge.new/llms-full-es.json) o la [guía para agentes de IA](https://docs.bridge.new/skill.md). Consulta los esquemas exactos en el [OpenAPI de integraciones REST](https://docs.bridge.new/es/api-reference/openapi.yaml) o el [OpenAPI de Custom Connections](https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml). Si necesitas ayuda para usar la aplicación Bridge, visita el [Centro de ayuda](https://help.bridge.new). --- # Conecta tu asistente de programación con IA Source: https://docs.bridge.new/es/connect-your-agent Conecta Codex, Claude Code, Cursor o GitHub Copilot a la documentación actual de Bridge e implementa a partir del contrato exacto de la API. Dale a tu asistente acceso a la documentación actual de Bridge antes de pedirle que construya tu integración. Elige tu herramienta, agrega el endpoint público MCP y comprueba la conexión. | Configuración | Valor | | --- | --- | | URL del servidor | `https://docs.bridge.new/mcp` | | Conexión | HTTP remoto / Streamable HTTP | | Nombre local sugerido | `bridgeDocs` | | Credenciales de Bridge | No se necesitan para este servidor de documentación | **Nota** Esto conecta tu asistente a la **documentación de Bridge**. No lo conecta a tu espacio de trabajo ni le da permiso para crear contactos o enviar mensajes. Tu integración usa por separado las [credenciales de la API REST](https://docs.bridge.new/es/credentials.md) o la configuración pública de [Custom Connections](https://docs.bridge.new/es/lead-capture/index.md). El servidor de documentación también ofrece una herramienta opcional para enviar comentarios sobre la documentación a Bridge. ## Elige tu asistente de programación ### [Codex](https://docs.bridge.new/es/connect-your-agent.md#codex) Configuración de CLI y del IDE local. ### [Claude Code](https://docs.bridge.new/es/connect-your-agent.md#claude-code) Agrega un comando y comprueba la conexión. ### [Cursor](https://docs.bridge.new/es/connect-your-agent.md#cursor) Agrega el servidor al archivo MCP de tu proyecto. ### [GitHub Copilot](https://docs.bridge.new/es/connect-your-agent.md#github-copilot) Configuración guiada en VS Code o configuración portátil del proyecto. ## Codex **Antes de comenzar:** debes tener instalado Codex CLI o la extensión de Codex para tu IDE. Para la CLI, agrega el servidor desde la terminal: ```bash codex mcp add bridgeDocs --url https://docs.bridge.new/mcp codex mcp list ``` La lista debe incluir `bridgeDocs` con la URL de documentación de Bridge. Que aparezca confirma la configuración; usa [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection) para confirmar que realmente puede leer la documentación. Si prefieres editar la configuración, agrega esta entrada a `~/.codex/config.toml`. Conserva las demás opciones y los otros servidores: ```toml [mcp_servers.bridgeDocs] url = "https://docs.bridge.new/mcp" ``` Reinicia el cliente o la extensión después de cambiar su configuración. En la interfaz de terminal de Codex, `/mcp` muestra los servidores activos. Los clientes locales de Codex pueden compartir la configuración en el mismo equipo; los entornos remotos pueden tener configuraciones y políticas independientes. **Ejemplo de prompt:** > Usa bridgeDocs para leer el contrato REST de Bridge y la guía de primera conversación. Prepara una integración en Node.js que cree un contacto, inicie una conversación y cree un mensaje. Enumera primero los identificadores y la configuración necesarios. Conserva todos los campos y tipos de la API, cita tus fuentes y no hagas solicitudes reales a la API. [Guía oficial de MCP para Codex](https://learn.chatgpt.com/docs/extend/mcp?surface=cli). ## Claude Code **Antes de comenzar:** debes tener instalado Claude Code. Agrega el servidor a tu configuración personal para usarlo en distintos proyectos: ```bash claude mcp add --transport http bridgeDocs --scope user https://docs.bridge.new/mcp claude mcp list ``` Si prefieres una configuración compartida del proyecto, usa `--scope project` en lugar de `--scope user`. Revisa la configuración resultante antes de guardarla en el repositorio. Inicia Claude Code y usa `/mcp` para inspeccionar `bridgeDocs`. Después ejecuta [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection). El endpoint de documentación de Bridge no necesita una clave de API de Bridge ni iniciar sesión con OAuth. **Ejemplo de prompt:** > Usa bridgeDocs para leer las guías actuales de verificación y recepción de webhooks de Bridge. Implementa un receptor en Python con la representación HMAC documentada y aceptación duradera antes de confirmar la recepción. Agrega pruebas sin conexión usando el vector de firma publicado. Explica la limitación de la marca de tiempo y el manejo de duplicados, y cita las páginas utilizadas. [Guía oficial de MCP para Claude Code](https://code.claude.com/docs/en/mcp). ## Cursor **Antes de comenzar:** abre tu proyecto de integración en Cursor. Crea o actualiza `.cursor/mcp.json` en ese proyecto. Combina la entrada con los servidores existentes: ```json { "mcpServers": { "bridgeDocs": { "url": "https://docs.bridge.new/mcp" } } } ``` Para una configuración personal entre proyectos, usa `~/.cursor/mcp.json`. En la barra lateral **Customize** de Cursor, comprueba que el servidor esté habilitado. Abre una conversación de Agent y ejecuta [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection); las herramientas MCP pertinentes aparecen en **Available Tools**. Revisa las solicitudes de uso de herramientas cuando Cursor te lo pida. **Ejemplo de prompt:** > Usa bridgeDocs para encontrar el flujo completo de adjuntos PDF. Implementa una carga desde el servidor que calcule el SHA-256 en Base64 de los bytes exactos del archivo, solicite una carga prefirmada, ejecute el PUT obligatorio y cree un mensaje con el mediaId devuelto. Conserva los campos documentados y explica cómo manejar los fallos de cada etapa. No envíes una clave de API de Bridge a la URL de carga. [Guía oficial de MCP para Cursor](https://cursor.com/docs/mcp). ## GitHub Copilot **Antes de comenzar:** habilita GitHub Copilot en VS Code y abre la carpeta de tu proyecto. Selecciona **Copilot** como destino de la sesión. 1. Abre la paleta de comandos con `Command` + `Shift` + `P` en macOS o `Ctrl` + `Shift` + `P` en Windows/Linux. 2. Ejecuta **MCP: Add Server** y elige **HTTP (HTTP or Server-Sent Events)**. 3. Introduce `https://docs.bridge.new/mcp` y llama al servidor `bridgeDocs`. 4. Elige **Global → Copilot Global** para tu configuración personal, cuando esté disponible. Revisa el destino que muestra tu versión de VS Code y cualquier solicitud de confianza del servidor. 5. Abre una conversación de Copilot, habilita las herramientas de documentación de Bridge para esa sesión y ejecuta [la comprobación de conexión](https://docs.bridge.new/es/connect-your-agent.md#check-the-connection). Para un proyecto compartido con la configuración portátil actual de Copilot, crea o combina esta entrada en `.mcp.json`, en la raíz del espacio de trabajo: ```json { "mcpServers": { "bridgeDocs": { "type": "http", "url": "https://docs.bridge.new/mcp", "tools": ["*"] } } } ``` El formato portátil de Copilot anterior difiere de `.vscode/mcp.json`, administrado por el editor, que usa un objeto `servers`. Usa el archivo correspondiente a la conexión elegida; no mezcles ambos formatos. Si el destino portátil no está disponible en tu versión, usa la configuración guiada y el archivo que seleccione. **Ejemplo de prompt:** > Usa bridgeDocs para leer la guía de Custom Connections y su contrato OpenAPI independiente. Prepara un formulario de landing page que registre el consentimiento, obtenga un token CAPTCHA nuevo en cada intento y presente un 202 como aceptado con su requestId. Conserva captureKey, los campos de solicitud y la acción CAPTCHA configurada. No uses una clave de la API REST en la página. [Configuración oficial de VS Code](https://code.visualstudio.com/docs/agent-customization/mcp-servers) · [Referencia de configuración de Copilot](https://code.visualstudio.com/docs/agents/reference/mcp-configuration). ## Comprueba la conexión Después de configurar cualquiera de los cuatro clientes, pregunta lo siguiente: > Usa el servidor MCP de documentación de Bridge para buscar cómo crear un mensaje. Lee el esquema MessageRequest en el OpenAPI REST publicado. ¿Qué tres campos son obligatorios y un 201 exitoso demuestra la entrega por WhatsApp? Cita la fuente exacta de Bridge que leíste. No llames a la API de negocio. Una comprobación exitosa usa una herramienta de documentación y cita una página o esquema de Bridge. Debe identificar `conversationId`, `messageBody` y `enableExternalBroadcast` como obligatorios y distinguir un mensaje creado de una confirmación de entrega del proveedor. Una respuesta plausible sin uso de herramientas ni fuente no es una prueba de conexión. ## Lee la documentación con cualquier IA, sin MCP No necesitas conectar MCP para leer la documentación de Bridge. Dale a un asistente que pueda abrir URLs el [índice trilingüe de documentación](https://docs.bridge.new/llms.txt) y elige las fuentes para tu tarea e idioma: | Idioma | Índice de páginas | Documentación reunida | | --- | --- | --- | | English | [English index](https://docs.bridge.new/llms-en.json) | [English collection](https://docs.bridge.new/llms-full-en.json) | | Español | [Índice en español](https://docs.bridge.new/llms-es.json) | [Documentación en español](https://docs.bridge.new/llms-full-es.json) | | Português do Brasil | [Índice em português](https://docs.bridge.new/llms-pt-br.json) | [Documentação em português](https://docs.bridge.new/llms-full-pt-br.json) | El índice enlaza a las páginas `.md` individuales y a los archivos OpenAPI exactos. La [colección completa](https://docs.bridge.new/llms-full.txt) incluye los tres idiomas; la colección de un solo idioma es más pequeña. Las descripciones de endpoints reunidas no sustituyen los esquemas completos de OpenAPI. Los archivos por idioma usan JSON: el índice enumera las URLs y cada colección contiene el texto de las páginas como Markdown en su campo `contentMarkdown`. Los archivos generales `llms.txt` y `llms-full.txt` mantienen el formato Markdown. **Ejemplo de prompt:** > Lee https://docs.bridge.new/llms.txt y elige las fuentes en español para enviar un PDF. Lee la guía completa de adjuntos y el OpenAPI REST enlazado antes de escribir código. Explica la secuencia de carga, los campos obligatorios y las limitaciones de entrega. Conserva las firmas publicadas de la API y cita las URLs que leíste. Prepara solo el código; no hagas solicitudes reales. Si buscas mediante MCP, especifica `language: "es"` para español, `language: "pt-BR"` para portugués o `language: "en"` para inglés. Las páginas públicas usan `.md`; las lecturas de páginas en el filesystem MCP usan `.mdx`. Consulta también la [guía de capacidades y fuentes de Bridge](https://docs.bridge.new/skill.md). ## Implementa con el contrato correcto El servidor permite buscar documentación, leer páginas y esquemas completos en un sistema de archivos virtual de documentación y, opcionalmente, enviar comentarios. La herramienta de archivos no ejecuta comandos en tu equipo. Los comentarios son una función separada de la búsqueda y lectura: úsala solo cuando realmente quieras enviar un comentario sobre la documentación. Indica al asistente la tarea y el flujo correspondiente: - [Primera conversación](https://docs.bridge.new/es/guides/first-conversation.md): contacto → conversación → mensaje. - [Adjuntos](https://docs.bridge.new/es/guides/send-attachments.md): bytes del archivo → checksum → PUT prefirmado → mensaje. - [Plantillas](https://docs.bridge.new/es/guides/send-template.md): consulta las variables antes de enviar. - [Conversaciones salientes de agentes](https://docs.bridge.new/es/guides/agent-outbound.md): selecciona un agente y entiende `forceSend`, la reutilización y la recuperación. - [Receptor de webhooks](https://docs.bridge.new/es/webhooks/receive-events.md): verifica, guarda, confirma y procesa. El [índice de documentación](https://docs.bridge.new/llms.txt) permite encontrar las páginas. La [documentación reunida](https://docs.bridge.new/llms-full.txt) agrupa guías y descripciones de endpoints, pero no incluye todos los esquemas. Antes de generar código, lee el Markdown del endpoint individual o el [OpenAPI REST](https://docs.bridge.new/es/api-reference/openapi.yaml) o [OpenAPI de Custom Connections](https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml) que corresponda. Pídele al asistente que conserve hosts, métodos, rutas, autenticación, identificadores, nombres de campos, tipos, campos obligatorios y que admiten null, enums, valores predeterminados, límites y códigos de respuesta. Si las fuentes publicadas se contradicen, identifica los fragmentos y confirma el comportamiento actual antes de basarte en ellos. ## Si no aparece el servidor | Síntoma | Qué revisar | | --- | --- | | Falta el servidor | Confirma la ubicación del archivo o el alcance de la configuración, el nombre del servidor y el cliente o entorno que usas. Conserva la configuración existente al agregar la entrada. | | Está configurado, pero no hay herramientas | Reinicia o recarga el cliente, habilita el servidor y revisa su estado MCP o sus registros. La organización puede restringir los servidores personalizados. | | Solicita autenticación | El servidor público de documentación de Bridge no necesita una clave de API de Bridge. Comprueba la URL y las políticas del cliente o de tu organización. No pegues credenciales del espacio de trabajo en el chat. | | Responde sin citas | Pide explícitamente usar `bridgeDocs`, buscar y leer el esquema del endpoint. Ejecuta nuevamente la comprobación de conexión. | | MCP no está disponible temporalmente | Lee directamente el [índice](https://docs.bridge.new/llms.txt), el Markdown del endpoint y el OpenAPI. El servidor de documentación no tiene un compromiso de disponibilidad separado. | Las interfaces de los clientes cambian con el tiempo. Las opciones pueden variar según la versión y las políticas de la organización; consulta la documentación del proveedor enlazada si tus menús son distintos. Instrucciones de proveedores verificadas por última vez: **14 de noviembre de 2026**. --- # Autenticación de la API REST Source: https://docs.bridge.new/es/credentials Genera y usa una clave de API desde tu servidor para la API REST de integraciones, sin confundirla con las credenciales de webhooks o Custom Connections. ## Descripción general Toda solicitud a la **API REST de integraciones** en `https://api-connect-us.bridge.new` usa una **clave de API** en el encabezado `x-api-key`. Esta clave identifica tu aplicación y la autoriza a acceder a los recursos de Bridge en nombre de tu organización. | Tipo de integración | Manejo de credenciales | | --- | --- | | API REST de integraciones | `x-api-key` desde el servidor, enviada a `https://api-connect-us.bridge.new`. | | Webhooks | Tu receptor comprueba la clave de API del webhook configurada, la firma HMAC y la política de vigencia. Sigue la guía para [verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md). | | Custom Connections | `captureKey` pública y reCAPTCHA desde el navegador; sin encabezado de autenticación. Sigue su [guía de integración](https://docs.bridge.new/es/lead-capture/integration.md). | **Nota** Necesitas acceso a la consola de administración de Bridge en https://admin.bridge.new. Si no tienes una cuenta, pídele al administrador de Bridge que te cree un usuario. --- ## Genera una clave de API ### Abre la consola de administración Ve al [panel de Bridge](https://admin.bridge.new) e inicia sesión con tus credenciales. ### Ve a la administración de claves En el panel izquierdo, abre **Developers → API Keys Management**. ### Crea una clave Haz clic en **Generate New Key**. Puedes asignarle un nombre descriptivo y una fecha de vencimiento. **Advertencia** **Importante:**\ Tu clave de API se muestra una sola vez al crearla. Cópiala de inmediato y guárdala en un lugar seguro; no podrás volver a consultarla. --- ## Usa tu clave de API Incluye tu clave de la API REST en el encabezado `x-api-key` de cada solicitud al host de integraciones REST: ```bash curl -X GET "https://api-connect-us.bridge.new/bridge/api/health" \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript const response = await fetch("https://api-connect-us.bridge.new/bridge/api/health", { method: "GET", headers: { "x-api-key": "YOUR_API_KEY", }, }); const data = await response.json(); console.log(data); ``` ```python import requests response = requests.get( "https://api-connect-us.bridge.new/bridge/api/health", headers={"x-api-key": "YOUR_API_KEY"} ) print(response.json()) ``` **Nota** Usa el endpoint `GET /bridge/api/health` para comprobar que la clave de API es válida y que la conexión funciona. --- ## Buenas prácticas de seguridad - **Usa variables de entorno:** guarda la clave en una variable de entorno, por ejemplo `BRIDGE_API_KEY`, en lugar de escribirla directamente en el código fuente. - **Nunca expongas las claves en código del cliente:** las claves de API solo deben usarse en aplicaciones del servidor. Nunca las incluyas en código frontend, aplicaciones móviles ni repositorios públicos. - **Configura un vencimiento:** establece siempre una fecha de vencimiento al crear la clave. Evita usar claves sin vencimiento definido. - **Una clave por aplicación:** usa una clave de API distinta para cada servicio o aplicación que se conecte a Bridge. Así limitas el impacto si una clave se filtra. - **Rota las claves periódicamente:** crea una nueva clave y actualiza tus aplicaciones antes de desactivar la anterior. Esto evita interrupciones durante la rotación. --- ## Solución de problemas | Error | Posible causa | Solución | | ----- | -------------- | -------- | | `401 Unauthorized` | La clave de API es inválida, venció o no se envió | Comprueba que la clave sea correcta, esté activa y se incluya en el encabezado `x-api-key` | | `403 Forbidden` | La clave de API no tiene acceso al recurso solicitado | Comprueba que tenga los permisos necesarios para este endpoint | | No puedes volver a consultar la clave de API | La clave se muestra una sola vez al crearla | Genera una nueva clave en la consola de administración | Consulta la lista completa en la referencia de [códigos de error](https://docs.bridge.new/es/error-codes.md). --- ## Temas relacionados - [Códigos de error](https://docs.bridge.new/es/error-codes.md): referencia completa de errores de la API de Bridge. - [Referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md): consulta todos los endpoints disponibles. - [Webhooks](https://docs.bridge.new/es/webhooks.md): configura notificaciones de eventos en tiempo real. --- # Glosario e identificadores Source: https://docs.bridge.new/es/guides/identifiers Encuentra los identificadores correctos de espacios de trabajo, contactos, usuarios de Bridge, agentes, conversaciones, plantillas, líneas y archivos sin confundirlos. ## Empieza con la integración correcta La **API REST de integraciones** lee o modifica recursos del espacio de trabajo desde tu servidor mediante `x-api-key`. Los **webhooks** envían eventos de Bridge a tu receptor. **Custom Connections** registra leads desde una landing page con su endpoint público independiente, `captureKey` y reCAPTCHA. Una clave de API es un secreto que se guarda en el servidor. La `captureKey` de Custom Connections está diseñada para aparecer en la landing page. Estos valores no son intercambiables. Consulta [Autenticación](https://docs.bridge.new/es/credentials.md) y [Custom Connections](https://docs.bridge.new/es/lead-capture/index.md). ## Personas, agentes y líneas - Un **contacto** es la persona externa con la que se comunica tu negocio. Los endpoints de contactos y los participantes externos de las conversaciones se refieren a esa persona. - Un **usuario de Bridge** es un usuario humano interno. Las consultas de usuarios internos y los destinatarios de una transferencia se refieren a estos usuarios. - Un **agente** es un agente automatizado expuesto por la API de agentes. Su tipo es `LEADSCOUT` o `SERVICE_AGENT`; tiene su propio identificador, disponibilidad y líneas. - Un **proveedor** es un tipo de canal, como `WHATSAPP`. Una **línea** es un canal específico usado para una conversación. El tipo de proveedor, el teléfono y el `providerChannelId` son valores distintos. - Un **espacio de trabajo** delimita el alcance de la solicitud. Una **marca** es otro identificador usado cuando la operación lo exige o lo admite; no es un espacio de trabajo ni una línea. El `ownerId` de un contacto se refiere a un usuario de Bridge, no a un agente automatizado. Puedes resolverlo con el [endpoint de consulta de un usuario interno](https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-id.md). ## De dónde sale cada identificador Usa identificadores del espacio de trabajo correcto. No reutilices un identificador solo porque el mismo teléfono, correo o nombre aparece en otro espacio de trabajo. | Valor que necesitas | Dónde obtenerlo o verificarlo | Qué debes enviar | | --- | --- | --- | | `workspaceId` | Usa el identificador proporcionado para tu integración. Si no lo tienes, pídeselo al administrador de Bridge. El contrato REST publicado no ofrece un endpoint global para listar espacios de trabajo. | El ID del espacio de trabajo en la ruta de la operación. Custom Connections también lo exige en el cuerpo y, para solicitudes desde un navegador, en la cadena de consulta. | | ID de contacto | [Consulta un contacto](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) por `PHONE`, `EMAIL` o `ID`; las respuestas de listado, creación y upsert también devuelven el `id` del contacto. | El `id` devuelto para `{contactId}` o un objeto identificador con `identifierType: "ID"`, cuando la operación lo admita. | | ID de usuario de Bridge | [Consulta un usuario interno](https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-un-identificador.md) por `EMAIL` o `ID`, o usa el listado de usuarios internos. | El `id` devuelto para `{userId}` o un objeto identificador interno. La consulta de usuarios internos no admite `PHONE`. | | ID de agente | [Lista los agentes](https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace.md). Lee `agents[].id`, `type` y `available`. | `agents[].id` para `{agentId}` en la operación de conversación saliente de agentes. `available` indica si el agente puede iniciar conversaciones. | | ID de línea del agente | En la misma respuesta de agentes, lee `lines[].providerChannelId` de ese agente. | Un ID de línea perteneciente al agente cuando la operación admite `contact.providerChannelId`. Consulta las reglas de selección de línea en la referencia de conversaciones salientes. | | Canal de proveedor general | [Lista los canales de proveedor](https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-de-proveedores-por-workspace.md). Esta respuesta publica `provider` e `identifier`, no el UUID del canal. | Usa estos campos únicamente para las finalidades documentadas por la operación que los consume. No sustituyas `providerChannelId` por el `identifier` que representa un teléfono. | | `brandId` | La respuesta de un agente puede incluir su `brandId`. Para otro flujo, obtén el ID de marca correcto de la configuración de integración o del administrador; el contrato publicado no ofrece un endpoint general de listado de marcas. | El ID de marca que acepta la operación. Un ID de marca no es un ID de línea. | | `teamId` | Obtén del administrador de Bridge o de la configuración de integración el ID del equipo interno correcto. El contrato REST publicado no ofrece un endpoint de listado de equipos. | La opción documentada de asignación a un equipo al crear una conversación; no envíes también `participants.internals`. | | ID de conversación | Crea o consulta una conversación y conserva el `id` devuelto. Las respuestas de conversaciones salientes incluyen `conversation.id`. | `{conversationId}` o `conversationId`, exactamente donde lo exija la operación. | | Plantilla | [Consulta una plantilla](https://docs.bridge.new/es/api-reference/templates-api/descubrir-las-variables-agn%C3%B3sticas-de-una-plantilla.md) por ID o nombre. La respuesta devuelve `id`, `name` y las claves de sus variables. | Usa el selector que espera la operación de envío; consulta la sección siguiente. | | `mediaId` | [Solicita las cargas prefirmadas](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md). Cada elemento del array de respuesta contiene `mediaId` y `presignUrl`. Completa la carga PUT requerida. | El `mediaId` devuelto en `mediaIds` o en el campo de medios que admita esa operación. No envíes la URL prefirmada como ID de medios. | **Nota** Los listados de agentes exponen IDs de línea en el contexto de cada agente. No son un mecanismo general para descubrir todas las líneas del espacio de trabajo. Si otro flujo requiere un `providerChannelId` que no puedes obtener de la respuesta publicada, pide al administrador de Bridge o a [soporte](mailto:support@sainapsis.com) el ID de línea correcto. No lo generes ni lo deduzcas de un teléfono. ## Nombres parecidos pueden exigir campos distintos La **consulta de contactos por identificador** usa parámetros de consulta llamados `type` y `value`. Un participante externo de una conversación usa `identifier` e `identifierType`, además de los otros campos que exija esa operación. No copies los parámetros de una consulta directamente al cuerpo de un participante. La **consulta de plantillas** acepta un ID o nombre en el parámetro de ruta `{templateId}`. Las **plantillas de inicio de conversación** usan `onboardingTemplates[].templateId`. La **selección de plantilla para conversaciones salientes** usa `id` o `name` dentro del objeto `template`; lee el esquema del endpoint en lugar de renombrar todos los selectores como `templateId`. Usa la `key` devuelta de cada variable en los `parameters` de la plantilla. Las claves de variables no son índices de posiciones de Meta. La [guía de parámetros de plantillas](https://docs.bridge.new/es/templates-and-parameters.md) explica los valores obligatorios, los predeterminados y la diferencia entre omitir un valor y enviarlo en blanco. ## Mantén separados los identificadores de resultado | Valor devuelto | Qué identifica | Qué no demuestra por sí solo | | --- | --- | --- | | `messageId` | Un mensaje creado mediante el endpoint de mensajes | Una confirmación de entrega del proveedor | | `trackingId` | Una solicitud aceptada de transferencia de LeadScout | Que haya terminado la asignación de los usuarios solicitados | | `requestId` | Un envío aceptado de Custom Connections | Que se haya entregado el mensaje inicial de WhatsApp | | `eventId` | Un identificador proporcionado con un evento de webhook; algunas familias de eventos usan valores derivados de la entidad | Una clave de deduplicación globalmente única o una garantía del orden de entrega | Sigue [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md) para la identidad de eventos y el manejo de duplicados. Consulta [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md) para los estados HTTP, resultados asíncronos y decisiones de reintento. Para un flujo completo, sigue [Primera conversación](https://docs.bridge.new/es/guides/first-conversation.md) o [Envío de adjuntos](https://docs.bridge.new/es/guides/send-attachments.md). --- # Crea un contacto y envía un mensaje Source: https://docs.bridge.new/es/guides/first-conversation Sigue un flujo completo desde el servidor: contacto, conversación y mensaje, conservando los identificadores devueltos. Esta guía crea un contacto, inicia una conversación con un usuario interno de Bridge y crea un mensaje. Ejecútala en tu servidor. **Advertencia** Usa un contacto de prueba al que tengas autorización para escribir. Crear una conversación puede ejecutar las plantillas de inicio del espacio de trabajo antes de la solicitud independiente que crea el mensaje. Revisa primero esa configuración: establecer en false el indicador de envío externo del mensaje posterior no desactiva las plantillas de inicio de la conversación. ## Antes de comenzar - Obtén una clave de API para usar desde el servidor en [Autenticación](https://docs.bridge.new/es/credentials.md). - Consigue el ID del espacio de trabajo, el `providerChannelId` de una línea activa de WhatsApp y el correo de un usuario interno de Bridge. Consulta [Identificadores y conceptos](https://docs.bridge.new/es/guides/identifiers.md). - Usa un número nuevo de prueba en formato internacional. Si el contacto ya existe, usa la [consulta de contactos por identificador](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) en lugar de crearlo otra vez. - Revisa los atributos personalizados obligatorios y la secuencia de plantillas de inicio del espacio de trabajo. Este ejemplo mínimo no proporciona atributos personalizados ni reemplaza las plantillas. - Elige `enableExternalBroadcast` explícitamente: `true` solicita el envío externo cuando lo permiten las reglas de la conversación y del destinatario; `false` crea el mensaje, pero omite ese envío externo. Ningún valor confirma la entrega por parte del proveedor. Este indicador no anula reglas de visibilidad ni permisos. ## La secuencia | Paso | Solicitud | Valor que debes conservar | | --- | --- | --- | | Comprueba el acceso | `GET /bridge/api/health` | Respuesta HTTP exitosa | | Crea el contacto | `POST /bridge/api/v1/workspaces/{workspaceId}/contacts` | `id` del contacto | | Inicia la conversación | `POST /bridge/api/v1/workspaces/{workspaceId}/conversations` | `id` de la conversación | | Crea el mensaje | `POST /bridge/api/v1/workspaces/{workspaceId}/messages` | `messageId` | El `id` del contacto se convierte en el `identifier` del participante externo, con `identifierType: "ID"`. El `id` de la conversación se convierte en el `conversationId` del mensaje. ## Ejecuta el ejemplo Usa Node.js con `fetch` integrado. Guarda el ejemplo como `first-conversation.mjs`. Proporciona estas variables de entorno mediante la configuración y el sistema de secretos de tu servidor: | Variable | Valor | | --- | --- | | `BRIDGE_API_KEY` | Tu clave de API secreta | | `BRIDGE_WORKSPACE_ID` | ID del espacio de trabajo correcto | | `BRIDGE_PROVIDER_CHANNEL_ID` | ID de la línea de WhatsApp autorizada, no su teléfono | | `BRIDGE_USER_EMAIL` | Usuario interno de Bridge del mismo espacio de trabajo | | `TEST_CONTACT_PHONE` | Teléfono de un contacto nuevo de prueba al que tienes autorización para escribir | | `ENABLE_EXTERNAL_BROADCAST` | Exactamente `true` o `false`; no se asume un valor predeterminado | Los nombres y el mensaje que aparecen abajo son ejemplos. Reemplázalos con el contenido previsto para tu prueba antes de ejecutarla. ```javascript const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const providerChannelId = required("BRIDGE_PROVIDER_CHANNEL_ID"); const internalEmail = required("BRIDGE_USER_EMAIL"); const cellphone = required("TEST_CONTACT_PHONE"); const broadcast = required("ENABLE_EXTERNAL_BROADCAST"); if (!["true", "false"].includes(broadcast)) { throw new Error("ENABLE_EXTERNAL_BROADCAST must be true or false."); } const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; async function request(method, path, body, expectedStatus) { const response = await fetch(`${BASE}${path}`, { method, headers: { "x-api-key": apiKey, ...(body === undefined ? {} : { "Content-Type": "application/json" }), }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), }); const result = await response.json().catch(() => null); if (response.status !== expectedStatus) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`${method} ${path}: HTTP ${response.status}${code}`); } return result; } await request("GET", "/bridge/api/health", undefined, 200); const contact = await request("POST", `${workspacePath}/contacts`, { firstName: "Alex", lastName: "Example", languageCode: "EN", cellphone, }, 201); if (!contact?.id || contact.workspaceId !== workspaceId) { throw new Error("The Contact response does not identify the intended workspace."); } const conversation = await request("POST", `${workspacePath}/conversations`, { participants: { externals: [{ identifier: contact.id, identifierType: "ID", messageProviderType: "WHATSAPP", providerChannelId, }], internals: [{ identifier: internalEmail, identifierType: "EMAIL" }], }, name: "Integration test", status: "ACTIVE", }, 201); if (!conversation?.id || conversation.workspaceId !== workspaceId) { throw new Error("The Conversation response does not identify the intended workspace."); } const message = await request("POST", `${workspacePath}/messages`, { conversationId: conversation.id, messageBody: "Hello from our authorized Bridge integration test.", enableExternalBroadcast: broadcast === "true", }, 201); if (!message?.messageId) throw new Error("The Message response has no messageId."); console.log({ contactId: contact.id, conversationId: conversation.id, messageId: message.messageId, }); ``` ```bash node first-conversation.mjs ``` ## Entiende el resultado - Una respuesta `201` al crear el contacto proporciona su identidad y espacio de trabajo. Lee `type` para conocer su clasificación real: `NORMAL` o `PARTIAL`. - Una respuesta `201` de conversación proporciona el ID que debes usar en el siguiente paso. Cuando no hay líneas libres, Bridge puede recuperar una conversación liberada que tenga exactamente los participantes solicitados. Se conservan su ID e historial; en ese caso de recuperación no se aplican el `name` ni el `status` solicitados. - Una respuesta `201` de mensaje proporciona `messageId`. Por sí sola, no demuestra que WhatsApp haya entregado el mensaje al contacto. Esta guía asigna explícitamente un usuario interno de Bridge. Para asignar mediante un equipo, usa la opción documentada `teamId` en lugar de `participants.internals`: son mutuamente excluyentes. ## Si falla un paso El ejemplo se detiene en la solicitud que falla y nunca reintenta automáticamente una escritura. Un fallo de red puede dejar el resultado incierto. Comprueba el recurso correspondiente antes de repetir una operación de creación o envío. | Situación | Qué hacer | | --- | --- | | El contacto ya existe | Consúltalo por identificador y usa el `id` devuelto; no sigas intentando crear el mismo contacto. | | Error de marca o línea | Confirma con el administrador cuál es la línea o marca autorizada; el teléfono de una línea no es su ID. | | Plantilla `0604`–`0608` | Sigue [Parámetros de plantillas de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md), incluidos los errores de configuración del espacio de trabajo. | | El mensaje se rechaza porque la conversación está liberada | Revisa el estado de la conversación y la referencia de errores de la operación antes de actuar. | | `429` | Sigue [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md), incluido `Retry-After`. | Consulta [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md) para conocer los formatos de respuesta y las decisiones de recuperación. ## Próximos pasos - [Carga y envía un adjunto](https://docs.bridge.new/es/guides/send-attachments.md). - [Elige y completa una plantilla de WhatsApp](https://docs.bridge.new/es/guides/send-template.md). - Consulta los contratos completos de solicitud y respuesta de [crear un contacto](https://docs.bridge.new/es/api-reference/contacts-api/crear-contacto.md), [crear una conversación](https://docs.bridge.new/es/api-reference/conversations-api/crear-conversaci%C3%B3n-con-identificaci%C3%B3n-flexible-de-usuarios.md) y [crear un mensaje](https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje.md). --- # Enviar PDF y otros adjuntos Source: https://docs.bridge.new/es/guides/send-attachments Envía un PDF u otro archivo compatible en una conversación: calcula su checksum, súbelo a la URL prefirmada y adjunta su ID de medios al mensaje. Para enviar un PDF u otro adjunto compatible, solicita la carga a Bridge, sube los bytes del archivo a la URL devuelta y crea un mensaje que incluya el `mediaId` recibido. El ejemplo completo desde el servidor que aparece más abajo envía un PDF. ## Antes de comenzar - Debes tener una conversación existente en el espacio de trabajo correcto. Consulta [Primera conversación](https://docs.bridge.new/es/guides/first-conversation.md). - Elige un PDF que tengas autorización para compartir y comprueba que cumpla los límites de la [API de archivos](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md). - Guarda la clave de API de Bridge en tu servidor. No la agregues a la solicitud de carga prefirmada. - Elige explícitamente el indicador `enableExternalBroadcast` del mensaje. ## Valida el archivo antes de solicitar una carga Comprueba el archivo real en tu servidor: su extensión, tipo MIME y longitud en bytes deben cumplir las reglas publicadas de la [API de archivos](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md). La solicitud de URL prefirmada contiene metadatos y una suma de comprobación, no los bytes del archivo ni un campo de tamaño. Una respuesta `201` prepara una carga; no demuestra que se hayan inspeccionado los bytes reales, que el tamaño cargado cumpla los límites publicados ni que un proveedor de mensajería vaya a aceptar el archivo. Si omites `contentType`, copia igualmente `presignUrl.headers` en la solicitud PUT: Bridge puede deducir `Content-Type` a partir del nombre del archivo. Si lo proporcionas, usa el tipo MIME del archivo real y mantenlo coherente con `fileType` y la extensión. Cambiar el nombre de un archivo no convierte su contenido. Después de un PUT exitoso, el procesamiento de la carga puede seguir pendiente. Si una solicitud de Message devuelve un [error de carga de archivos](https://docs.bridge.new/es/error-codes.md#file-upload-errors), conserva el error completo y comprueba qué etapa falló antes de decidir si es seguro realizar otra escritura. ## Secuencia de carga | Etapa | Qué ocurre | Qué no confirma | | --- | --- | --- | | `POST .../files` | Bridge devuelve `mediaId` y los datos de `presignUrl`. | Los bytes todavía no se han cargado. | | `PUT` prefirmado | Tu servidor envía los bytes exactos con la URL de carga y los encabezados devueltos. | Este paso no crea ningún mensaje. | | `POST .../messages` | Adjuntas el `mediaId` cargado mediante `mediaIds`. | La respuesta de la API por sí sola no demuestra la entrega por parte del proveedor. | El checksum es el **resumen SHA-256 de todos los bytes del archivo, codificado en Base64**. No es un resumen hexadecimal ni un hash del nombre del archivo. ## Ejemplo completo desde el servidor Usa Node.js con `fetch` integrado. Guarda el ejemplo como `send-attachment.mjs`. Configura `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_CONVERSATION_ID`, `ATTACHMENT_PATH` y `ENABLE_EXTERNAL_BROADCAST` (`true` o `false`). ```javascript import { readFile } from "node:fs/promises"; import { basename } from "node:path"; import { createHash } from "node:crypto"; const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const conversationId = required("BRIDGE_CONVERSATION_ID"); const filePath = required("ATTACHMENT_PATH"); const broadcast = required("ENABLE_EXTERNAL_BROADCAST"); if (!["true", "false"].includes(broadcast)) { throw new Error("ENABLE_EXTERNAL_BROADCAST must be true or false."); } if (!filePath.toLowerCase().endsWith(".pdf")) { throw new Error("This example is configured for a PDF document."); } const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; const bytes = await readFile(filePath); const checksumBase64 = createHash("sha256").update(bytes).digest("base64"); async function bridgePost(path, body) { const response = await fetch(`${BASE}${workspacePath}${path}`, { method: "POST", headers: { "x-api-key": apiKey, "Content-Type": "application/json" }, body: JSON.stringify(body), }); const result = await response.json().catch(() => null); if (response.status !== 201) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`Bridge ${path}: HTTP ${response.status}${code}`); } return result; } const uploads = await bridgePost("/files", [{ name: basename(filePath), fileType: "DOCUMENT", contentType: "application/pdf", checksumBase64, }]); const upload = uploads?.[0]; if (!upload?.mediaId || !upload.presignUrl?.url) { throw new Error("The upload response is missing its mediaId or URL."); } const method = upload.presignUrl.method ?? "PUT"; if (method !== "PUT") throw new Error("Expected a presigned PUT upload."); const uploadHeaders = new Headers(upload.presignUrl.headers ?? {}); const returnedChecksum = uploadHeaders.get("x-amz-checksum-sha256"); if (returnedChecksum !== null && returnedChecksum !== checksumBase64) { throw new Error("The returned checksum differs from the file checksum."); } if (returnedChecksum === null) { uploadHeaders.set("x-amz-checksum-sha256", checksumBase64); } const uploaded = await fetch(upload.presignUrl.url, { method, headers: uploadHeaders, body: bytes, }); if (!uploaded.ok) { throw new Error(`File upload failed: HTTP ${uploaded.status}; no Message was created.`); } const message = await bridgePost("/messages", { conversationId, messageBody: "Here is the document you requested.", enableExternalBroadcast: broadcast === "true", mediaIds: [upload.mediaId], }); if (!message?.messageId) throw new Error("The Message response has no messageId."); console.log({ mediaId: upload.mediaId, messageId: message.messageId }); ``` ```bash node send-attachment.mjs ``` ## Conserva intacta la solicitud de carga Usa `presignUrl.url` sin reconstruir su host, ruta ni cadena de consulta. Usa el método devuelto y los encabezados obligatorios. El contrato establece `PUT` como método predeterminado cuando se omite, y la API de archivos exige `x-amz-checksum-sha256` con el mismo checksum enviado a Bridge. La carga envía los mismos `bytes` con los que se calculó el checksum. No conviertas el PDF a texto, no lo envuelvas en JSON ni envíes otra copia del archivo después de calcular el hash. Si cargas varios archivos, conserva la relación entre cada `mediaId` devuelto, sus datos prefirmados y el archivo correspondiente. Completa todas las cargas necesarias antes de adjuntar esos IDs a un mensaje. Algunos medios necesitan más preparación después de la carga: copiar el archivo, generar una vista previa, convertirlo o cargarlo al proveedor de mensajería. Estas etapas pueden fallar por separado. Un PUT correcto o una respuesta 201 al crear el mensaje no demuestran que el procesamiento ni la entrega del proveedor hayan terminado. Conserva el archivo original y los identificadores recibidos para correlacionar el resultado antes de repetir una solicitud de mensaje. ## Maneja una etapa fallida - **Bridge rechaza la solicitud del archivo:** comprueba la extensión, `fileType`, el tipo de contenido, el tamaño y el checksum contra la referencia. - **La carga falla:** detente antes de crear el mensaje. Comprueba la URL exacta, el método, los encabezados, el checksum y los bytes. No asumas una vigencia de carga ni una política de reintentos que la respuesta no indique. - **La solicitud de mensaje falla o agota el tiempo de espera:** que el archivo se haya cargado no demuestra que exista un mensaje. Comprueba el resultado antes de repetir la solicitud que lo crea. `STICKER` y `WEBSITE` aparecen en el enum `FileType`, pero la tabla de carga publicada no especifica sus reglas de extensión, MIME y tamaño. Confirma esas reglas antes de usarlos en una integración. Consulta la [API de archivos](https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos.md), la [API de mensajes](https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje.md) y [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md). --- # Elige y completa una plantilla de WhatsApp Source: https://docs.bridge.new/es/guides/send-template Consulta una plantilla por ID o nombre, proporciona sus claves de variables independientes del proveedor y usa el ID devuelto en una solicitud de conversación. Usa esta guía cuando quieras abrir una conversación con una plantilla específica de WhatsApp. La [referencia detallada de plantillas](https://docs.bridge.new/es/templates-and-parameters.md) explica las reglas de validación y todos los errores de plantilla documentados. ## Antes de comenzar - Debes conocer el **ID o nombre** de la plantilla. `GET .../templates/{templateId}` acepta ambos. - Confirma que la plantilla esté aprobada para la cuenta de WhatsApp Business asociada a la línea que usarás. - Debes tener el ID de un contacto de prueba existente, el `providerChannelId` de la línea autorizada de WhatsApp y el correo de un usuario interno de Bridge. Consulta [Identificadores y conceptos](https://docs.bridge.new/es/guides/identifiers.md). - Revisa la secuencia de plantillas de inicio del espacio de trabajo: según su configuración, tu reemplazo puede sustituir toda la secuencia o solo la primera plantilla. **Advertencia** La solicitud final inicia una conversación y puede enviar plantillas de inicio. Usa un contacto de prueba autorizado y el contenido previsto. ## 1. Consulta las variables ```http GET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId} x-api-key: YOUR_API_KEY ``` Codifica para URL el ID o nombre proporcionado. Lee `id`, `name`, `variables` y `driftWarning` en la respuesta. | Variable | Qué hacer | | --- | --- | | `callerMustSupply: true` | Proporciona una cadena que no esté en blanco bajo la `key` de esa variable. | | `callerMustSupply: false`, no personalizada | Omítela para conservar el valor que Bridge obtiene para cada contacto. Un valor enviado reemplaza ese valor para todos los contactos. | | `isCustom: true` | Proporciona tu valor, omítelo o envíalo en blanco para usar su `default`. | Usa la `key` independiente del proveedor, nunca el `label` visible, una posición de Meta ni un nombre de variable inventado. `driftWarning` es informativo y por sí solo no bloquea el envío. ## 2. Prepara los valores Crea en tu servidor un archivo JSON que contenga únicamente claves devueltas por la consulta. Si la plantilla realmente declara `order_number` y `delivery_date`, podría contener lo siguiente: ```json { "order_number": "A-10492", "delivery_date": "October 3" } ``` Esos dos nombres son ejemplos, no campos universales de Bridge. Consulta tu propia plantilla antes de usarlos. Respeta las [reglas de valores de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md#whatsapp-value-rules); omite los valores no personalizados que quieras que Bridge complete, en lugar de enviar cadenas en blanco. ## 3. Consulta, comprueba y crea la conversación Usa Node.js con `fetch` integrado. Guarda el ejemplo como `send-template.mjs` y configura `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_TEMPLATE_ID_OR_NAME`, `TEMPLATE_VALUES_PATH`, `BRIDGE_CONTACT_ID`, `BRIDGE_PROVIDER_CHANNEL_ID` y `BRIDGE_USER_EMAIL`. ```javascript import { readFile } from "node:fs/promises"; const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const templateRef = required("BRIDGE_TEMPLATE_ID_OR_NAME"); const contactId = required("BRIDGE_CONTACT_ID"); const providerChannelId = required("BRIDGE_PROVIDER_CHANNEL_ID"); const internalEmail = required("BRIDGE_USER_EMAIL"); const parameters = JSON.parse(await readFile(required("TEMPLATE_VALUES_PATH"), "utf8")); if (parameters === null || Array.isArray(parameters) || typeof parameters !== "object") { throw new Error("The template values file must contain a JSON object."); } if (Object.entries(parameters).some(([key, value]) => Array.from(key).length > 128 || typeof value !== "string" || Array.from(value).length > 1024 )) { throw new Error("Parameter keys and values must respect the published string limits."); } if (Object.keys(parameters).length > 50) throw new Error("At most 50 parameters are allowed."); const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; async function request(method, path, body, expectedStatus) { const response = await fetch(`${BASE}${workspacePath}${path}`, { method, headers: { "x-api-key": apiKey, ...(body === undefined ? {} : { "Content-Type": "application/json" }), }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), }); const result = await response.json().catch(() => null); if (response.status !== expectedStatus) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`${method} ${path}: HTTP ${response.status}${code}`); } return result; } const template = await request( "GET", `/templates/${encodeURIComponent(templateRef)}`, undefined, 200, ); if (!template?.id) throw new Error("Template discovery returned no id."); const variables = template.variables ?? []; const known = new Set(variables.map((variable) => variable.key)); const unknown = Object.keys(parameters).filter((key) => !known.has(key)); const missing = variables.filter((variable) => variable.callerMustSupply && (typeof parameters[variable.key] !== "string" || !parameters[variable.key].trim()) ); if (unknown.length || missing.length) { throw new Error(`Check template keys: ${unknown.length} unknown, ${missing.length} missing.`); } const conversation = await request("POST", "/conversations", { participants: { externals: [{ identifier: contactId, identifierType: "ID", messageProviderType: "WHATSAPP", providerChannelId, }], internals: [{ identifier: internalEmail, identifierType: "EMAIL" }], }, onboardingTemplates: [{ templateId: template.id, parameters }], }, 201); if (!conversation?.id || conversation.workspaceId !== workspaceId) { throw new Error("The Conversation response does not identify the intended workspace."); } console.log({ templateId: template.id, conversationId: conversation.id }); ``` ```bash node send-template.mjs ``` El ejemplo usa el ID devuelto por la consulta en `onboardingTemplates[].templateId`. Las dos operaciones de conversaciones salientes también aceptan el ID o nombre de una plantilla; si envías ambos, el ID tiene prioridad. Sus cuerpos de solicitud son distintos de `onboardingTemplates`: lee el contrato de la operación antes de reutilizar este cuerpo en otra. Las comprobaciones locales detectan claves desconocidas o faltantes. Bridge realiza igualmente su propia validación, incluida la aprobación para la línea elegida y las reglas finales de valores de WhatsApp. La validación local no equivale a aprobación ni garantiza la entrega. ## Cómo corregir una solicitud rechazada | Error | Qué hacer | | --- | --- | | Consulta `BRIDGE_TEMPLATE_0001` | Comprueba el ID o nombre y el espacio de trabajo. Esta respuesta no revela si el identificador pertenece a otro espacio de trabajo. | | `BRIDGE_CONVERSATION_0604` | Proporciona valores que no estén en blanco para las variables de `extra.missingVariables`. | | `BRIDGE_CONVERSATION_0605` | Quita las claves de `extra.unknownKeys`; usa las claves independientes del proveedor devueltas por la consulta. | | `BRIDGE_CONVERSATION_0607` | Corrige los valores de `extra.invalidVariables` según su `reason`. | | `BRIDGE_CONVERSATION_0608` | Pídele a un administrador que cambie la secuencia de plantillas de inicio del espacio de trabajo. Cambiar los valores de tu plantilla no resuelve este error de configuración. | Consulta la [referencia completa de errores de plantillas](https://docs.bridge.new/es/templates-and-parameters.md#errors) para los errores de aprobación, pertenencia, parámetros no admitidos y solicitudes mal formadas. No reintentes automáticamente una solicitud de conversación que agotó el tiempo de espera: primero determina su resultado. --- # Inicia una conversación saliente con un agente Source: https://docs.bridge.new/es/guides/agent-outbound Elige un agente, envía una plantilla inicial, entiende forceSend y la recuperación, y solicita una transferencia de LeadScout. Usa las operaciones de conversaciones salientes cuando un contacto existente deba recibir una plantilla aprobada de WhatsApp y continuar con un agente de IA. Para el flujo general, consulta [Crear una conversación](https://docs.bridge.new/es/guides/first-conversation.md). ## Elige la operación | Objetivo | Operación | Cómo se elige el agente | | --- | --- | --- | | Iniciar con un LeadScout o Service Agent específico | `POST /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound` | Proporcionas el ID de agente obtenido de `GET /agents`. | | Iniciar con un LeadScout seleccionado mediante las líneas elegibles del espacio de trabajo | `POST /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound` | Bridge determina el agente de prospección de la línea. | Ambas usan el host de la API REST `https://api-connect-us.bridge.new` y una `x-api-key` desde el servidor. Sus esquemas de solicitud son distintos. Lee la [referencia de conversaciones salientes de agentes](https://docs.bridge.new/es/api-reference/agents-api/iniciar-conversaci%C3%B3n-saliente-con-un-contact-como-agent-espec%C3%ADfico.md) o la [referencia de LeadScout](https://docs.bridge.new/es/api-reference/leadscout-api/iniciar-conversaci%C3%B3n-saliente-de-leadscout-con-un-lead-conocido.md) según la operación que uses. ## Antes de enviar 1. [Consulta el contacto](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) o [créalo](https://docs.bridge.new/es/api-reference/contacts-api/crear-contacto.md) si no existe. Estas operaciones exigen que el contacto ya exista en el espacio de trabajo; no necesitas crear antes una conversación o un mensaje independiente. 2. [Lista los agentes](https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace.md). Elige uno disponible y lee su `lines[].providerChannelId`. El ID de un agente de IA no es el de un usuario humano de Bridge. 3. Elige una plantilla aprobada. [Consulta sus variables](https://docs.bridge.new/es/guides/send-template.md#1-discover-the-variables), proporciona los valores que debe aportar quien hace la solicitud y comprueba que esté aprobada para la línea de destino. Para este requisito solo necesitas el paso de consulta; no ejecutes el paso de creación de conversación de esa guía antes de una operación de conversación saliente. 4. Confirma que tu negocio tenga la autorización necesaria. Si envías `consent.status: "GRANTED"`, incluye `capturedAt`: así registras tu declaración de consentimiento. En la operación de agentes, `contact.providerChannelId` debe pertenecer al agente elegido si lo envías. Es una preferencia: se puede seleccionar otra línea elegible de ese agente. En LeadScout se respeta la línea explícita. [Identificadores y sus fuentes](https://docs.bridge.new/es/guides/identifiers.md) explica qué valores usar. ## Envía una solicitud mínima de agente Reemplaza todos los valores de ejemplo. Este caso asume que la plantilla elegida no tiene variables obligatorias pendientes que solo puedas proporcionar tú. Define `forceSend` deliberadamente; el ejemplo mantiene explícito el comportamiento predeterminado. ```bash curl --fail-with-body --request POST \ "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/agents/$AGENT_ID/outbound" \ --header "x-api-key: $BRIDGE_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "contact": { "identifier": "f0000001-0000-4000-8000-000000000001", "identifierType": "ID", "messageProviderType": "WHATSAPP" }, "template": { "id": "f0000040-0000-4000-8000-000000000040" }, "forceSend": false }' ``` Una solicitud exitosa devuelve `201`. Conserva `conversation.id` e interpreta estos campos de respuesta: | Campo | Significado | | --- | --- | | `alreadyInitiated: true` | Se reutilizó una conversación activa existente. La solicitud exitosa igualmente agrega su nueva plantilla y sus mensajes de seguimiento. | | `recovered: true` | Se recuperó una conversación liberada y recuperable, conservando su ID. Se reemplazan su contexto saliente anterior y su `agentContext`. | | `additionalMessagesPersisted` | Cantidad de mensajes de seguimiento almacenados. No es una confirmación de entrega. | | `templateSent` | Resumen de la plantilla inicial almacenada para enviarla. El nombre del campo no demuestra que el destinatario la haya recibido. | En una creación nueva, ni reutilización ni recuperación se establecen en true. Puede haber recuperación con `forceSend: false`. Los mensajes adicionales se guardan en el orden de la solicitud: no asumas que esperan la respuesta del contacto. El flujo compartido almacena seguimientos de texto y no adjunta sus `mediaIds`. Usa la opción documentada `template.media` para medios en la plantilla inicial o el [flujo de adjuntos de mensajes](https://docs.bridge.new/es/guides/send-attachments.md) para un mensaje separado. ## Qué hace forceSend La disponibilidad se evalúa para **la conversación de este contacto en cada línea**. Que una línea esté ocupada en este contexto no significa que la línea corporativa de WhatsApp esté reservada globalmente para un solo contacto. Las reglas siguientes siguen sujetas a la disponibilidad del agente y a las validaciones de plantilla, consentimiento y sesión. En pantallas estrechas, desplázate horizontalmente para comparar las cuatro opciones. Si usas teclado, puedes enfocar esta comparación y recorrerla con las flechas. | Situación | LeadScout: false | LeadScout: true | Agentes: false | Agentes: true | | --- | --- | --- | --- | --- | | La línea elegida está libre | Crea | Crea | Crea | Crea | | La línea elegida contiene una conversación liberada marcada como recuperable | Recupera el mismo ID | Recupera el mismo ID | Recupera el mismo ID | Recupera el mismo ID | | La selección automática solo encuentra conversaciones activas ocupadas | `409 …0008` | Reutiliza la primera conversación ocupada elegible | `409 …0008` | Prefiere una controlada por el agente solicitado y aplica la comprobación de controlador indicada abajo | | La línea explícita está ocupada | `409 …0007` | Reutiliza esa conversación | Busca otras líneas libres o recuperables del agente; si no hay, `409 …0008` | Busca otras líneas libres o recuperables; si no hay, prefiere una ocupada que controle el agente | | La conversación ocupada elegida está controlada por una persona u otro agente | No reutiliza conversaciones activas | La ruta heredada permite reutilizarla, sujeto a otras comprobaciones; esto no promete por sí solo transferir su control | No reutiliza conversaciones activas | `409 BRIDGE_AI_AGENT_OUTBOUND_0006`; este rechazo no escribe nada | | Solo hay conversaciones bloqueadas o liberadas no recuperables | `409 …0008` | `409 …0008` | `409 …0008` | `409 …0008` | En la tabla, `…0007` es `BRIDGE_AI_LEADSCOUT_0007` y `…0008` es `BRIDGE_AI_LEADSCOUT_0008`. Una conversación liberada solo se puede recuperar si lo permite su indicador de recuperación almacenado; `forceSend` no la convierte en recuperable. En ambas rutas, una sesión de LeadScout abierta y sin vencer bloquea una nueva solicitud de conversación saliente con `409 BRIDGE_AI_LEADSCOUT_0017`. Si no se puede finalizar una sesión vencida, se devuelve `409 BRIDGE_AI_LEADSCOUT_0018`. Un Service Agent puede continuar su sesión de servicio abierta y vigente; una sesión vencida se cierra antes de abrir otra. **Advertencia** `forceSend` no es una clave de idempotencia. Repetir una solicitud exitosa puede agregar otra plantilla y más mensajes. No omite conversaciones bloqueadas, comprobaciones de sesión, reglas de aprobación ni validaciones. Si se agota el tiempo de espera, el resultado queda incierto: inspecciona la conversación antes de decidir si vuelves a enviar la solicitud. ## Maneja conflictos y efectos parciales | Resultado | Qué hacer | | --- | --- | | `BRIDGE_AI_LEADSCOUT_0007` / `0008` | Revisa la conversación existente del contacto y sus líneas elegibles. Decide si corresponde reutilizarla antes de habilitar `forceSend`. | | `BRIDGE_AI_AGENT_OUTBOUND_0006` | Revisa `extra.conversationId` y quién controla esa conversación. Coordina su control antes de liberarla deliberadamente. No interrumpas automáticamente una conversación humana. | | `BRIDGE_AI_LEADSCOUT_0017` / `0018` | Resuelve la sesión existente o contacta a soporte. Cambiar `forceSend` a true no corrige el problema de sesión. | | `BRIDGE_AI_LEADSCOUT_0019` / `0020` / `0021` | Usa la consulta de variables para corregir valores faltantes, superpuestos o claves desconocidas. | | `400 BRIDGE_AI_LEADSCOUT_0016` por un `mediaId` de plantilla desconocido en la operación de agentes | La conversación puede haberse creado o recuperado antes del error. Revísala antes de reintentar. | [Liberar una conversación](https://docs.bridge.new/es/api-reference/conversations-api/liberar-conversaci%C3%B3n.md) es una operación independiente con efectos de negocio. Un `204` no tiene cuerpo de respuesta. Libera una conversación solo cuando realmente quieras terminarla. ## Solicita una transferencia de LeadScout a una persona Para una conversación de LeadScout, obtén el [ID o correo del usuario humano de Bridge](https://docs.bridge.new/es/guides/identifiers.md) y llama al [endpoint de transferencia manual](https://docs.bridge.new/es/api-reference/leadscout-api/solicitar-transferencia-manual-de-leadscout-a-usuarios-internos.md). Esta operación es específica de LeadScout: no asumas que aplica a un Service Agent. ```bash curl --fail-with-body --request POST \ "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/leadscout/conversations/$CONVERSATION_ID/handoff" \ --header "x-api-key: $BRIDGE_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "assignees": [ {"identifier": "f0000002-0000-4000-8000-000000000002", "identifierType": "ID"} ] }' ``` Un `202` confirma la aceptación de la solicitud. Conserva `trackingId` y `conversationId`; la aceptación no demuestra que haya terminado la asignación ni que una persona haya leído o respondido la conversación. La referencia no publica un endpoint de seguimiento de transferencias: no construyas uno a partir de `trackingId`. Continúa con el [manejo de errores](https://docs.bridge.new/es/error-codes.md) y la [recepción de webhooks](https://docs.bridge.new/es/webhooks/receive-events.md) para conectar este flujo a tu sistema. --- # Lee todas las páginas de resultados Source: https://docs.bridge.new/es/guides/pagination Recorre los cursores opacos de contactos, conversaciones, usuarios de Bridge y agentes sin detenerte en una página corta. Los endpoints de listado devuelven una colección y un `cursor` opcional. Envía ese cursor sin modificar para leer la siguiente página. Continúa hasta que sea null o no aparezca. ## Elige la colección Los cuatro endpoints siguientes aceptan un `limit` de **1 a 100**, con un valor predeterminado de **20**. | Recurso | Ruta después del espacio de trabajo | Campo de la colección | | --- | --- | --- | | Contactos | `/contacts` | `contacts` | | Conversaciones | `/conversations` | `conversations` | | Usuarios de Bridge | `/users` | `users` | | Agentes | `/agents` | `agents` | Usa la [consulta de contactos por identificador](https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador.md) o la [consulta de usuarios de Bridge por identificador](https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-un-identificador.md) cuando necesites encontrar a una persona conocida. Recorrer toda una lista es una tarea distinta. ## Ejemplo desde el servidor Este ejemplo lee contactos. Guárdalo como `list-contacts.mjs` y configura `BRIDGE_API_KEY` y `BRIDGE_WORKSPACE_ID` en tu servidor. La protección local `maxPages` evita una ejecución ilimitada por accidente; no es un límite de la API de Bridge. La protección contra cursores repetidos detiene el proceso e informa el problema, en lugar de devolver silenciosamente una lista incompleta. ```javascript const BASE = "https://api-connect-us.bridge.new"; const apiKey = process.env.BRIDGE_API_KEY; const workspaceId = process.env.BRIDGE_WORKSPACE_ID; if (!apiKey || !workspaceId) { throw new Error("Set BRIDGE_API_KEY and BRIDGE_WORKSPACE_ID."); } async function* pages(resource, collection, filters = {}) { let cursor; const seen = new Set(); const maxPages = 10000; for (let pageNumber = 0; pageNumber < maxPages; pageNumber += 1) { const url = new URL( `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}/${resource}`, BASE, ); for (const [key, value] of Object.entries(filters)) { url.searchParams.set(key, String(value)); } url.searchParams.set("limit", "100"); if (cursor !== undefined) url.searchParams.set("cursor", cursor); const response = await fetch(url, { headers: { "x-api-key": apiKey } }); const body = await response.json().catch(() => null); if (response.status !== 200) { const code = body?.code ? ` (${body.code})` : ""; throw new Error(`List ${resource}: HTTP ${response.status}${code}`); } if (!Array.isArray(body?.[collection])) { throw new Error(`Expected the ${collection} collection.`); } yield body[collection]; if (body.cursor === null || body.cursor === undefined) return; if (typeof body.cursor !== "string" || seen.has(body.cursor)) { throw new Error("Invalid or repeated cursor; stopped without claiming completion."); } seen.add(body.cursor); cursor = body.cursor; } throw new Error("Local page guard reached; the sweep is incomplete."); } let count = 0; for await (const contacts of pages("contacts", "contacts")) { // Process or store this page before continuing. Avoid logging personal data. count += contacts.length; } console.log({ contactsRead: count }); ``` ```bash node list-contacts.mjs ``` Usa `pages("conversations", "conversations", { status: "ACTIVE" })`, `pages("users", "users")` o `pages("agents", "agents")` con el contrato correspondiente. Conserva los mismos filtros durante todo un recorrido. ## No te detengas en una página corta Una página con menos registros que `limit` puede tener una página siguiente. El endpoint de agentes documenta expresamente este comportamiento. El cursor devuelto indica si debes continuar; la cantidad de elementos de la colección no lo indica. Trata el cursor como un valor opaco. No lo decodifiques, no lo incrementes ni construyas uno por tu cuenta. En el ejemplo, `URL.searchParams` conserva su valor mediante la codificación de URL. ## Filtros y límites de solicitudes - Los filtros `ownerEmail` y `search` del listado de contactos están obsoletos. Para buscar un correo o teléfono conocido, usa la consulta por identificador. Para filtrar un inventario por `ownerId`, lee ese campo en las filas devueltas y filtra en tu código. - Los filtros `email` y `status` del listado de usuarios de Bridge están obsoletos. Usa la consulta por identificador para un correo conocido o revisa el `status` de cada usuario devuelto. - Cada solicitud de página consume el presupuesto compartido del espacio de trabajo. Sigue [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md), incluido `Retry-After` ante un `429`. Este ejemplo mínimo se detiene si recibe una respuesta distinta de 200, en lugar de reintentar automáticamente. Los contratos publicados no prometen una instantánea transaccional del listado mientras cambian los registros. No presentes este recorrido como una exportación cuya consistencia esté garantizada ni deduzcas una vigencia del cursor que no esté documentada. ## Referencias - [Lista de contactos](https://docs.bridge.new/es/api-reference/contacts-api/listar-contactos.md) - [Lista de conversaciones](https://docs.bridge.new/es/api-reference/conversations-api/consultar-conversaciones-con-filtros-flexibles.md) - [Lista de usuarios de Bridge](https://docs.bridge.new/es/api-reference/internal-users-api/listar-usuarios-internos.md) - [Lista de agentes](https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace.md) - [Respuestas y errores](https://docs.bridge.new/es/guides/responses.md) --- # Respuestas, errores y reintentos Source: https://docs.bridge.new/es/guides/responses Interpreta creación, aceptación, respuestas vacías, validación y señales de reintento sin confundir los contratos REST y de Custom Connections. ## Interpreta el resultado de la operación que llamaste El estado HTTP y el cuerpo de respuesta describen la operación solicitada. No todos significan que una persona recibió un mensaje. | Operación | Éxito publicado | Cómo interpretarlo | | --- | --- | --- | | Crear un mensaje | `201`, con `messageId` | Conserva el ID del mensaje. La respuesta publicada no incluye una confirmación de entrega del proveedor; no lo marques como entregado basándote solo en ella. | | Liberar una conversación | `204`, sin cuerpo de respuesta | Trátalo como éxito y no intentes interpretar el cuerpo vacío como JSON. | | Solicitar una transferencia de LeadScout | `202`, con `trackingId`, `conversationId`, `status` y `assignees` | Conserva el ID de correlación. La asignación es asíncrona: los destinatarios reflejan la solicitud y no demuestran que haya terminado su resolución o asignación posterior. | | Enviar un lead de Custom Connections | `202`, con `requestId` | Conserva el ID de solicitud. Muestra que el lead fue aceptado; otro servicio envía el mensaje inicial de WhatsApp después. | La referencia de cada operación sigue siendo la autoridad: [mensajes](https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje.md), [liberación](https://docs.bridge.new/es/api-reference/conversations-api/liberar-conversaci%C3%B3n.md), [transferencia](https://docs.bridge.new/es/api-reference/leadscout-api/solicitar-transferencia-manual-de-leadscout-a-usuarios-internos.md) y [Custom Connections](https://docs.bridge.new/es/api-reference/campaign-leads/registrar-un-lead-de-campa%C3%B1a.md). **Nota** Un ID de correlación no es una URL de estado. El contrato publicado no define un endpoint de consulta periódica para `trackingId` ni `requestId`. Consérvalo para correlación y soporte; no construyas un endpoint nuevo a partir de él. ## Interpreta el formato de error publicado por el endpoint Las integraciones REST y Custom Connections tienen contratos de error separados. ### Integraciones REST Muchas respuestas usan `Problem`: `title` y `status` son obligatorios; `code`, `detail`, `errors`, `traceId`, `instance` y `extra` son opcionales. Cuando haya un `code`, úsalo para elegir un manejador de error documentado en lugar de comparar el `title` legible para personas. Conserva `traceId` para soporte cuando se incluya. Algunas respuestas de validación publicadas declaran `HTTPValidationError`, cuyo `detail` es un array de elementos con `loc`, `msg` y `type`. El manejador compartido de errores de la API revisado para esta documentación devuelve esos detalles en `Problem.errors[]`. Las definiciones de respuesta publicadas se conservan; aún está pendiente confirmar el comportamiento contra la API desplegada. Consulta la [nota de compatibilidad de validación](https://docs.bridge.new/es/error-codes.md#parse-validation-errors-defensively). Acepta errores JSON con `application/json` o `application/problem+json`. Revisa `code` cuando aparezca y después un array `errors` o `detail` para los errores de campos. Un `detail` de tipo cadena es una explicación, no un array. El estado `422` por sí solo no identifica un formato universal de cuerpo. Prevé un caso alternativo para errores sin `code` y usa la referencia del endpoint junto con los [códigos de error](https://docs.bridge.new/es/error-codes.md) para decidir qué hacer. ### Custom Connections Su cuerpo de error exige `type`, `title` y `status`, y puede incluir `detail`. Aquí **`type` es el identificador de error para el código que procesa la respuesta**. No es el campo REST `code`. La [referencia de errores de Custom Connections](https://docs.bridge.new/es/lead-capture/errors.md) detalla estas respuestas. Las respuestas de error no incluyen el `requestId` del envío; solo aparece en una respuesta `202` exitosa. Para pedir soporte por un error, conserva la URL de la página y la hora aproximada, como indica esa referencia. ## Decide si reintentar según la operación y la causa | Resultado | Qué hacer | | --- | --- | | REST `429` | Respeta `Retry-After` en segundos. La guía de límites indica que la solicitud rechazada no se procesó. El presupuesto del espacio de trabajo se comparte entre las claves de API. | | REST `401` o `403` | Corrige la clave, los permisos o el espacio de trabajo incorrecto. Un reintento programado no corrige esas causas. | | Error de validación o configuración | Corrige primero la causa documentada. No envíes repetidamente la misma solicitud inválida. | | Custom Connections `422` | La causa documentada es la indisponibilidad del proveedor de CAPTCHA. Su guía de errores indica que reintentar es seguro; genera un token nuevo para el siguiente intento. | | Rechazo de CAPTCHA en Custom Connections | Comprueba que el token exista, esté vigente y se haya generado para este intento. El mismo error también cubre una puntuación baja; por eso un intento nuevo no demuestra por sí solo la causa original. | | Tiempo de espera agotado, pérdida de conexión o `5xx` sin clasificar durante una modificación | No asumas que no ocurrió nada. Revisa los efectos documentados de la operación y los identificadores que ya obtuviste antes de decidir si repetirla. No asumas una garantía general de idempotencia. | Consulta [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md) para controlar el ritmo y [Errores de Custom Connections](https://docs.bridge.new/es/lead-capture/errors.md) para sus reglas de reintento específicas. ## Algunos fallos pueden ocurrir después de una escritura La [referencia de conversaciones salientes de agentes](https://docs.bridge.new/es/api-reference/agents-api/iniciar-conversaci%C3%B3n-saliente-con-un-contact-como-agent-espec%C3%ADfico.md) documenta que un `template.media.mediaId` desconocido puede producir `BRIDGE_AI_LEADSCOUT_0016` después de crear o recuperar la conversación. Por eso un reintento puede producir un resultado distinto. Un estado de error no garantiza de forma universal que se hayan revertido todos los efectos. Sigue las instrucciones de efectos y recuperación de la operación específica. Si no están claras o se contradicen, identifica la incertidumbre y contacta a [soporte de Bridge](mailto:support@sainapsis.com) antes de repetir una acción con efectos externos. --- # Parámetros de plantillas de WhatsApp Source: https://docs.bridge.new/es/templates-and-parameters Abre una conversación con tus plantillas de WhatsApp, completa sus variables y maneja todos los errores que puede devolver la solicitud. ## Descripción general Al crear una conversación, `onboardingTemplates` permite elegir las plantillas de WhatsApp que la abren y su orden. Una plantilla puede contener variables, como un número de pedido, una fecha de entrega o el nombre del contacto. Bridge completa algunas por su cuenta para cada contacto; otras solo las puedes proporcionar tú y las envías en los `parameters` de la entrada. El flujo tiene tres pasos: 1. Consulta las variables de la plantilla. 2. Decide qué valores enviar. 3. Envíalos con `POST .../conversations`. **Nota** Todas las comprobaciones de esta página se ejecutan antes de crear recursos. Si la solicitud se rechaza, **no se crea una conversación ni se envía un mensaje**, de modo que puedes corregirla y enviarla nuevamente. --- ## 1. Consulta las variables de la plantilla ```http GET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId} x-api-key: YOUR_API_KEY ``` `templateId` acepta el `id` o el `name` de la plantilla. La respuesta enumera sus variables: ```json { "id": "f0000040-0000-4000-8000-000000000040", "name": "order_shipped_promo", "language": "es", "driftWarning": { "hasDrift": false, "stale": [], "missingLabels": [] }, "variables": [ { "key": "first_name", "label": "Contact first name", "callerMustSupply": false, "isCustom": false, "default": null }, { "key": "order_number", "label": "Order number", "callerMustSupply": true, "isCustom": false, "default": null }, { "key": "delivery_date", "label": "Delivery date", "callerMustSupply": true, "isCustom": false, "default": null }, { "key": "tracking_code", "label": "Tracking code", "callerMustSupply": false, "isCustom": true, "default": "pending" } ] } ``` `driftWarning` es solo informativo: señala diferencias entre las variables declaradas y la instantánea de la plantilla de Meta y nunca bloquea un envío. La tabla siguiente describe cada elemento de `variables`. | Campo | Significado | | --- | --- | | `key` | Nombre que debes usar en `parameters` | | `label` | Descripción de la variable legible para personas | | `callerMustSupply` | `true` cuando debes proporcionar un valor que no esté en blanco porque Bridge no tiene una fuente para él; `false` en los demás casos | | `isCustom` | Indica si es una variable personalizada: un valor que solo tú conoces y que tiene un texto predeterminado | | `default` | Para una variable personalizada, texto enviado si no proporcionas un valor; `null` en los demás casos | Una plantilla que no está en tu espacio de trabajo devuelve `404` con `BRIDGE_TEMPLATE_0001`. --- ## 2. Decide qué valores enviar | Variable | Qué significa | Qué hacer | | --- | --- | --- | | `callerMustSupply: true` | Bridge no tiene una fuente para ese valor | **Obligatorio.** Envía un valor que no esté en blanco para su `key` | | `callerMustSupply: false`, `isCustom: false` | Bridge lo completa para cada contacto, por ejemplo con su nombre | **Opcional.** Omítelo para conservar el valor de Bridge | | `isCustom: true` | Un valor que solo tú conoces, con un `default` | **Opcional.** Envía tu valor, omítelo o envíalo en blanco para que se envíe su `default` | El valor que envíes para una variable `callerMustSupply: false` reemplaza el valor de Bridge y se usa **para todos los contactos** de la conversación. **Advertencia** Para conservar el valor de Bridge en una variable no personalizada, **omite la clave**. Un valor en blanco no significa «usar el predeterminado»: se envía tal como lo escribiste. Una variable obligatoria cuyo valor esté vacío o contenga solo espacios se rechaza como faltante. Solo las variables personalizadas (`isCustom: true`) tratan el valor en blanco como no enviado y recurren a su `default`. --- ## 3. Envía los parámetros Cada entrada de `onboardingTemplates` recibe el `id` de la plantilla devuelto en el paso 1 y sus `parameters`, usando la `key` de cada variable. La posición en la lista determina el orden de envío. ```http POST /bridge/api/v1/workspaces/{workspaceId}/conversations x-api-key: YOUR_API_KEY Content-Type: application/json ``` ```json { "participants": { "externals": [ { "identifier": "+13802098869", "identifierType": "PHONE", "messageProviderType": "WHATSAPP", "brandId": "YOUR_BRAND_ID" } ] }, "onboardingTemplates": [ { "templateId": "f0000040-0000-4000-8000-000000000040", "parameters": { "order_number": "A-10492", "delivery_date": "3 de octubre" } } ] } ``` En este ejemplo se omiten `first_name` y `tracking_code`, por lo que cada contacto recibe su propio nombre y `tracking_code` se envía con su valor predeterminado, `pending`. Límites por plantilla: como máximo **50** parámetros, claves de hasta **128** caracteres y valores de hasta **1024** caracteres. Las solicitudes que superan esos límites se rechazan por formato incorrecto; consulta [Errores](https://docs.bridge.new/es/templates-and-parameters.md#errors). Según la configuración del espacio de trabajo, tus plantillas reemplazan toda la secuencia de inicio o solo su primera plantilla. En el segundo caso, el resto de la secuencia configurada se envía después de las tuyas. --- ## Reglas de valores de WhatsApp WhatsApp rechaza algunos valores al enviar el mensaje. Bridge los comprueba de antemano para que la solicitud falle mientras aún puedes corregirla: | Regla | Límite | | --- | --- | | Saltos de línea y tabulaciones | No se permiten `\n`, `\r` ni `\t` | | Espacios consecutivos | Como máximo 4 seguidos | | Encabezado | El texto del encabezado con tu valor debe caber en **60** caracteres | | Botón de URL | El enlace del botón con tu valor debe caber en **2000** caracteres | | Cuerpo | El texto del cuerpo más todos sus valores debe caber en **1024** caracteres | **Advertencia** El límite del cuerpo incluye los valores que Bridge completa para cada contacto, como su nombre. Bridge solo puede comprobar los valores que conoce al recibir la solicitud: deja espacio para los demás. Bridge nunca recorta ni reescribe tus valores: lo que envías es lo que recibe el contacto. --- ## Errores Todos los errores usan el formato `application/problem+json` descrito en [Códigos de error](https://docs.bridge.new/es/error-codes.md). Decide qué hacer según `code`, nunca según `title`. | Código | Estado | Cuándo ocurre | `extra` | | --- | --- | --- | --- | | `BRIDGE_CONVERSATION_0601` | 404 | La plantilla no existe | `templateId`, `workspaceId` | | `BRIDGE_CONVERSATION_0602` | 400 | La plantilla pertenece a otro espacio de trabajo | `templateId`, `workspaceId` | | `BRIDGE_CONVERSATION_0603` | 400 | La plantilla no está aprobada para la línea usada para contactar a un participante | `templateId`, `workspaceId`, `userIds` —contactos para cuya línea no está aprobada, cuando se conocen— | | `BRIDGE_CONVERSATION_0604` | 422 | Falta una variable obligatoria o está en blanco | `templateId`, `missingVariables: [{key, label}]` | | `BRIDGE_CONVERSATION_0605` | 422 | Una clave de `parameters` no pertenece a las variables de la plantilla | `templateId`, `unknownKeys: [key]` | | `BRIDGE_CONVERSATION_0606` | 422 | Se enviaron `parameters` para una plantilla que no es de WhatsApp | `templateId` | | `BRIDGE_CONVERSATION_0607` | 422 | Un valor infringe una [regla de WhatsApp](https://docs.bridge.new/es/templates-and-parameters.md#whatsapp-value-rules) | `templateId`, `invalidVariables: [{key, label, reason}]` | | `BRIDGE_CONVERSATION_0608` | 422 | Una plantilla que el espacio de trabajo envía después de las tuyas necesita valores que solo puede proporcionar quien llama a la API | `templateId`, `origin: "WORKSPACE_CONFIGURATION"` | ### Valores faltantes: `0604` ```json { "title": "A template named in the onboarding override is missing values only the caller can provide", "status": 422, "detail": "A template named in the onboarding override is missing values only the caller can provide", "code": "BRIDGE_CONVERSATION_0604", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "missingVariables": [ { "key": "delivery_date", "label": "Delivery date" } ] } } ``` ### Valores inválidos: `0607` ```json { "title": "Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent", "status": 422, "detail": "Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent", "code": "BRIDGE_CONVERSATION_0607", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "invalidVariables": [ { "key": "order_number", "label": "Order number", "reason": "NEWLINE" } ] } } ``` `reason` indica la primera regla que infringe el valor: | `reason` | Significado | | --- | --- | | `NEWLINE` | El valor contiene `\n` o `\r` | | `TAB` | El valor contiene `\t` | | `CONSECUTIVE_SPACES` | El valor tiene más de 4 espacios consecutivos | | `TOO_LONG` | El encabezado o botón de URL supera su límite al insertar el valor | | `BODY_TOO_LONG` | El cuerpo supera los 1024 caracteres; se enumeran todos los valores de cuerpo que enviaste | ### `0608` no se resuelve cambiando la solicitud `BRIDGE_CONVERSATION_0608` solo ocurre en espacios de trabajo donde tus plantillas reemplazan únicamente la primera de la secuencia de inicio. Significa que una plantilla enviada después de las tuyas necesita valores que solo puedes proporcionar tú y que la API no puede aportar. Pídele a un administrador que cambie la secuencia de inicio. ### Solicitudes mal formadas Una solicitud que no cumpla el esquema —más de 50 parámetros, una clave de más de 128 caracteres, un valor de más de 1024 o un campo desconocido— se rechaza con `422` **sin `code`**. En su lugar, incluye una lista `errors` que indica cada problema: ```json { "title": "Unprocessable content", "status": 422, "errors": [ { "loc": ["body", "onboardingTemplates", 0, "parameters", "order_number"], "msg": "String should have at most 1024 characters", "type": "string_too_long" } ] } ``` ### Orden de evaluación Las comprobaciones se ejecutan en este orden y **solo se devuelve el primer error**: 1. Límite de solicitudes: `429`. 2. Formato de la solicitud: `422` sin `code`. 3. Participantes, marca y línea: `400` / `409`, por ejemplo `BRIDGE_BRAND_0101` o `BRIDGE_PROVIDER_CHANNEL_0001`. 4. Cada plantilla, en el orden de la lista: `0601` / `0602` → `0603` → `0606` → `0605` → `0604` → `0607`. 5. `0608`, solo si tus plantillas reemplazan únicamente la primera de la secuencia del espacio de trabajo. Por eso corregir un error puede revelar el siguiente. Los valores de una plantilla posterior no se revisan hasta que pasen todas las anteriores. --- ## Temas relacionados - [Crear una conversación](https://docs.bridge.new/es/api-reference/conversations-api/crear-conversaci%C3%B3n-con-identificaci%C3%B3n-flexible-de-usuarios.md): referencia completa de solicitud y respuesta. - [Códigos de error](https://docs.bridge.new/es/error-codes.md): todos los códigos, incluidos los de marcas y líneas. - [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md): manejo de `429`. --- # Límites de solicitudes Source: https://docs.bridge.new/es/rate-limits Cuántas solicitudes acepta la API de Bridge, qué encabezados indican el presupuesto disponible y cómo manejar correctamente un 429. ## Descripción general La API de Bridge acepta **50 solicitudes cada 5 segundos**. El límite se aplica a todos los endpoints, está habilitado por defecto y no requiere configuración. **Nota** El presupuesto pertenece al **espacio de trabajo**, no a la clave de API. Si creas varias claves para el mismo espacio de trabajo —una por aplicación, como se recomienda— todas consumen las mismas 50 solicitudes. --- ## Comprueba el presupuesto disponible Toda respuesta a una solicitud autenticada incluye dos encabezados para que no tengas que adivinar cuánto presupuesto queda: ```http RateLimit-Policy: "default";q=50;w=5 RateLimit: "default";r=43;t=3 ``` | Campo | Significado | | --- | --- | | `q` | Solicitudes permitidas por ventana | | `w` | Duración de la ventana, en segundos | | `r` | Solicitudes **restantes** en la ventana actual | | `t` | Segundos hasta que la ventana se reinicie y `r` vuelva a `q` | Un cliente que observa `r` y hace una pausa cuando se acerca a cero evita los rechazos por este límite. **Nota** Una solicitud rechazada **antes** de la autenticación, porque falta la clave de API o es inválida, no incluye ninguno de esos encabezados. Consulta esas respuestas en [Autenticación](https://docs.bridge.new/es/credentials.md). --- ## Si superas el límite Las solicitudes que exceden el presupuesto reciben `429 Too Many Requests`. No se procesa nada, por lo que es seguro repetir la solicitud. ```http HTTP/1.1 429 Too Many Requests Content-Type: application/problem+json Retry-After: 3 RateLimit-Policy: "default";q=50;w=5 RateLimit: "default";r=0;t=3 ``` ```json { "title": "Too Many Requests", "status": 429, "detail": "The workspace has exhausted its request budget for the current window", "code": "BRIDGE_RATE_LIMIT_0001" } ``` `Retry-After` se expresa en **segundos a partir de ahora**, no como fecha. Espera ese tiempo antes de que se atienda la siguiente solicitud. **Advertencia** **Un `429` no es un problema de autenticación.** `401` y `403` indican que falta la clave, es inválida, venció o no está autorizada, y **reintentarlos de forma programada no resolverá el problema**: solo consume tu presupuesto. Solo se debe reintentar automáticamente un `429`, y únicamente después de la espera que indica. --- ## Qué consume presupuesto Cada solicitud HTTP cuenta como una, incluidas las que terminan en un error de validación o un `404`. Lo que importa es cuántas llamadas hace el cliente, no cuántos datos devuelve la API. La diferencia se ve al leer: - **Un recurso por ID**, con `GET .../contacts/{contactId}`, cuesta **una solicitud**, sin importar el tamaño de la respuesta. - **Un listado**, con `GET .../contacts`, cuesta **una solicitud por página**. Leerlo completo consume tantas solicitudes como páginas tenga. Por eso el tamaño de página determina el costo de recorrer todo el listado. Leer 500 contactos cuesta 5 solicitudes con páginas de 100 y 25 solicitudes con páginas de 20: los mismos datos consumen cinco veces más presupuesto. **Nota** Prefiere el mayor tamaño de página que admita el endpoint al leer una lista completa. Cuando ya sabes qué recurso necesitas, consúltalo directamente por ID. --- ## Controla la espera en la práctica Un cliente que regula su ritmo con `RateLimit` y respeta `Retry-After` cuando ocasionalmente supera el límite no necesita más lógica para este control: ```python import time import requests BASE = "https://api-connect-us.bridge.new" HEADERS = {"x-api-key": "YOUR_API_KEY"} def rate_limit_state(response): header = response.headers.get("RateLimit", "") fields = dict(part.split("=", 1) for part in header.split(";") if "=" in part) return int(fields.get("r", 1)), int(fields.get("t", 1)) def get(path): while True: response = requests.get(f"{BASE}{path}", headers=HEADERS) if response.status_code == 429: time.sleep(int(response.headers["Retry-After"])) continue remaining, reset_in = rate_limit_state(response) if remaining == 0: time.sleep(reset_in) return response ``` ```javascript const BASE = "https://api-connect-us.bridge.new"; const HEADERS = { "x-api-key": "YOUR_API_KEY" }; const sleep = (seconds) => new Promise((done) => setTimeout(done, seconds * 1000)); function rateLimitState(response) { const fields = Object.fromEntries( (response.headers.get("RateLimit") ?? "") .split(";") .filter((part) => part.includes("=")) .map((part) => part.split("=")) ); return { remaining: Number(fields.r ?? 1), resetIn: Number(fields.t ?? 1) }; } async function get(path) { while (true) { const response = await fetch(`${BASE}${path}`, { headers: HEADERS }); if (response.status === 429) { await sleep(Number(response.headers.get("Retry-After"))); continue; } const { remaining, resetIn } = rateLimitState(response); if (remaining === 0) await sleep(resetIn); return response; } } ``` **Advertencia** No reintentes un `429` de inmediato ni con un intervalo fijo elegido por tu cuenta. Si reintentas antes de que transcurra `Retry-After`, la solicitud vuelve a rechazarse. Un bucle de reintentos demasiado rápido mantiene en cero el presupuesto del espacio de trabajo para todas las demás aplicaciones que lo comparten. --- ## Estándares Estos campos no son exclusivos de Bridge: `RateLimit-Policy` y `RateLimit` siguen la especificación IETF de [campos de límites de solicitudes](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), `Retry-After` corresponde a [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#field.retry-after) y el cuerpo de `429` sigue [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457.html). Si ya manejas encabezados `X-RateLimit-*` de otra API, estos son sus equivalentes estandarizados. Si los valores difieren, **prevalece `Retry-After`**: es la señal que determina cuándo reintentar, mientras que `RateLimit` informa cómo regular el ritmo. --- ## Temas relacionados - [Autenticación](https://docs.bridge.new/es/credentials.md): claves de API y respuestas `401`/`403` que no deben reintentarse. - [Códigos de error](https://docs.bridge.new/es/error-codes.md): referencia completa, incluido `BRIDGE_RATE_LIMIT_0001`. - [Referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md): todos los endpoints documentan su respuesta `429`. --- # Códigos de error Source: https://docs.bridge.new/es/error-codes Interpreta los códigos de error REST, las respuestas de validación y los resultados de escritura inciertos para decidir qué hacer. ## Formato de respuesta Ejemplo de respuesta `Problem`. Consulta la referencia del endpoint para conocer su estado HTTP, tipo de contenido y esquema de respuesta: ```json { "title": "A template named in the onboarding override is missing values only the caller can provide", "status": 422, "detail": "A template named in the onboarding override is missing values only the caller can provide", "code": "BRIDGE_CONVERSATION_0604", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "missingVariables": [{ "key": "delivery_date", "label": "Delivery date" }] }, "instance": "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/{workspaceId}/conversations", "traceId": "Root=1-6702b8c4-3f1a2b4c5d6e7f8091a2b3c4" } ``` | Campo | Significado | | --- | --- | | `code` | Cuando aparece, código estable de error incluido en esta página. **Decide qué hacer según este campo, no según el título.** Los errores de validación y del servidor pueden omitirlo. | | `title` | Mensaje legible para personas. Puede ser más largo que el título de las tablas siguientes: nunca lo uses para identificar el error | | `status` | Código de estado HTTP | | `detail` | Más información sobre este caso, cuando está disponible | | `extra` | Contexto estructurado para procesar el error, como los IDs o claves involucrados, cuando está disponible | | `instance` | URL de la solicitud | | `traceId` | Inclúyelo cuando contactes a soporte | **Nota** Lee el esquema de respuesta de la operación que llamas. Cuando sea `HTTPValidationError`, los detalles están en un array `detail`; cada entrada contiene `loc` —dónde—, `msg` —qué— y `type`. Otras respuestas `422` documentadas usan `Problem` y pueden incluir `code` y `extra`. No asumas que todas las respuestas `422` tienen el mismo formato. ### Interpreta los errores de validación de forma defensiva Acepta cuerpos de error JSON con `application/json` o `application/problem+json`. Comprueba primero el estado HTTP y después revisa el cuerpo: 1. Si aparece `code`, usa la entrada correspondiente de esta página para decidir qué hacer. 2. Si `errors` es un array, lee sus entradas `loc`, `msg` y `type` como detalles de validación. 3. Si `detail` es un array, interprétalo como el formato `HTTPValidationError`. Un `detail` de tipo cadena es una explicación, no una lista de errores de campos. 4. Conserva `traceId`, el estado y la URL de solicitud para soporte. No exijas la presencia de `code` o `extra` ni uses mensajes legibles como identificadores. Un campo inválido y una regla que relaciona varios campos no tienen por qué compartir el mismo estado. Las reglas del cuerpo saliente revisadas generan `400` con `BRIDGE_CORE_0103` cuando `consent.status` es `GRANTED` y no se incluye `capturedAt`, o cuando `template.media` proporciona ambos o ninguno de `mediaId` y `url`. Los tipos de campo o UUID inválidos pueden producir, en cambio, detalles de validación de solicitud con `422`. Interpreta juntos el estado y el cuerpo de error; no exijas un array `errors` para toda solicitud inválida. ### Códigos heredados con sufijo Algunos manejadores de errores heredados añaden un nombre simbólico a `code`, por ejemplo, `BRIDGE_PRELOAD_FILE_0002 | PRELOAD_FILE_IS_PENDING`. Conserva el valor recibido completo para registros y soporte. Para consultar el catálogo, acepta un código simple conocido o su forma heredada reconocida explícitamente; no compares `title` o `detail`, no inventes un código desconocido ni reescribas el cuerpo de la respuesta. Esta revisión del código fuente no ha confirmado de forma independiente qué versión del manejador está desplegada. **Advertencia** **Compatibilidad de validación:** algunas respuestas OpenAPI publicadas declaran `HTTPValidationError.detail[]` y `application/json`, mientras que el manejador compartido de errores de la API revisado para esta documentación devuelve detalles de validación en `Problem.errors[]` con `application/problem+json`. Esta actualización editorial conserva las definiciones de respuesta publicadas. Maneja ambos formatos; sigue pendiente la confirmación contra la API desplegada antes de admitir solo uno en un cliente generado estricto. ### Decide si debes reintentar | Resultado | Acción | | --- | --- | | `400` o `422` | Corrige la solicitud según el código y los errores de campos. Repetir la misma entrada no corrige la validación. | | `401` o `403` | Revisa las credenciales, el espacio de trabajo y los permisos del tipo de integración correcto. Guarda las claves REST en el servidor. | | `404` | Confirma el identificador y el espacio de trabajo. Una consulta sin contacto coincidente es distinta de una entrada mal formada. | | `409` | Lee el código de la operación: una conversación existente, un agente no disponible o una sesión pendiente requieren soluciones distintas. No habilites `forceSend` automáticamente. | | `429` | Sigue la [guía de encabezados y espera por límite de solicitudes](https://docs.bridge.new/es/rate-limits.md). | | Tiempo de espera agotado, respuesta desconectada o `5xx` después de una escritura | Trata el resultado como incierto. Revisa el recurso afectado antes de reenviar: un error no demuestra que no se haya guardado ningún cambio. | Esta guía general de reintentos no agrega idempotencia a un endpoint. Para reutilización, recuperación y escrituras parciales, consulta [Conversaciones salientes y transferencias de agentes](https://docs.bridge.new/es/guides/agent-outbound.md). Custom Connections tiene su propia [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md) y no usa una clave de la API REST. ## Errores al responder a un mensaje Para `POST .../messages`, las comprobaciones revisadas del mensaje al que respondes definen estas formas heredadas adicionales: - `BRIDGE_MESSAGE_0001 | MESSAGE_NOT_FOUND` (`404`): no se encontró el Message indicado en `replyToMessageId`. - `BRIDGE_MESSAGE_0002 | MESSAGE_IS_NOT_ON_CONVERSATION` (`403`): el mensaje al que respondes pertenece a otra Conversation. Usa uno de la Conversation en la que vas a enviar el mensaje. Conserva `code` completo, incluido su sufijo simbólico. Estas comprobaciones se refieren al mensaje al que respondes, no al `mediaId` del archivo adjunto. ## Errores de carga de archivos El flujo de carga revisado define estos códigos heredados. El sufijo forma parte del `code` recibido, no es un campo de la solicitud. Consulta el contrato de respuesta de la operación y conserva la interpretación compatible anterior. La operación determina qué errores de archivo corresponden: `POST .../files` comprueba los metadatos y puede devolver los códigos `0003` o `0004` de abajo. `POST .../messages` puede devolver `0001` o `0002` cuando el `mediaId` de un adjunto no existe o sigue pendiente. Los archivos de las plantillas salientes tienen su propio manejo de errores; no sustituyas `BRIDGE_AI_LEADSCOUT_0016` por estos códigos. | `code` heredado | Estado | Acción | | --- | --- | --- | | `BRIDGE_PRELOAD_FILE_0001 \| PRELOAD_FILE_NOT_FOUND` | 404 | Comprueba el `mediaId` devuelto y la carga a la que hace referencia. | | `BRIDGE_PRELOAD_FILE_0002 \| PRELOAD_FILE_IS_PENDING` | 400 | El archivo sigue pendiente. Confirma que el PUT terminó y permite que se procese la carga; no deduzcas que una solicitud de Message fallida no guardó ningún cambio. | | `BRIDGE_PRELOAD_FILE_0003 \| PRELOAD_FILE_INVALID_MIME_TYPE` | 400 | Corrige la combinación del tipo MIME y el `fileType` lógico. | | `BRIDGE_PRELOAD_FILE_0004 \| PRELOAD_FILE_INVALID_NAME` | 400 | Proporciona un nombre con una extensión admitida para ese `fileType` lógico. | ## Códigos de error de agentes Errores de las operaciones de agentes. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_AI_AGENT_OUTBOUND_0001` | Agent Not Found | No se encontró el agente en el espacio de trabajo | | `BRIDGE_AI_AGENT_OUTBOUND_0002` | Agent Not Available | El agente no está disponible para conversaciones salientes | | `BRIDGE_AI_AGENT_OUTBOUND_0003` | Agent Type Not Supported | El tipo de agente no admite conversaciones salientes | | `BRIDGE_AI_AGENT_OUTBOUND_0004` | No Channels For Agent | El agente no tiene una línea activa de mensajería vinculada | | `BRIDGE_AI_AGENT_OUTBOUND_0005` | Agent Not Assigned To Channel | El agente no está asignado al canal solicitado | | `BRIDGE_AI_AGENT_OUTBOUND_0006` | Conversation Controlled By Other Agent | Otro agente controla la conversación activa | | `BRIDGE_AI_AGENT_OUTBOUND_0007` | Invalid Cursor | El cursor de paginación está mal formado o pertenece a otro espacio de trabajo | `POST .../agents/{agentId}/outbound` devuelve `0001` y `0004` como `404`, `0002` y `0006` como `409`, y `0003` y `0005` como `422`. - `0002`: el agente está en borrador o no tiene una línea. `extra.reason` indica la causa; esa misma causa aparece en `unavailableReason` en `GET .../agents`. - `0006`: la conversación del contacto en la línea seleccionada por la solicitud está controlada por otro agente o por un usuario de Bridge. No se envió nada. Libérala con `POST .../conversations/{conversationId}/release`, usando `extra.conversationId`, y vuelve a intentar. `extra` también incluye `channelId` y, solo si la controla un agente, `controllingAgentId`, que identifica a ese agente. Cuando la controla un usuario de Bridge, la clave no aparece; no se devuelve `null`. `GET .../agents` devuelve `0007` como `400` cuando el `cursor` está mal formado o se emitió para otro espacio de trabajo. Empieza otra vez sin cursor. Conserva el mismo filtro `type` durante la paginación: un cursor emitido con un filtro `type` se rechaza si la solicitud usa otro `type`. ### Otros códigos de `POST .../agents/{agentId}/outbound` | Código | Estado | Significado | | --- | --- | --- | | `BRIDGE_CORE_0103` | 400 | La solicitud es inválida: `consent.status` es `GRANTED` sin `capturedAt`, `template` no incluye `id` ni `name`, o `template.media` no incluye exactamente uno de `mediaId` o `url` | | `BRIDGE_CORE_0301` | 403 | El espacio de trabajo de la ruta no coincide con el de la clave de API | | `BRIDGE_AI_LEADSCOUT_0001` | 404 | El contacto no existe en el espacio de trabajo | | `BRIDGE_AI_LEADSCOUT_0002` | 404 | El usuario de Bridge de `handoffOverride` no existe en el espacio de trabajo | | `BRIDGE_AI_LEADSCOUT_0003` | 409 | Se eliminó al usuario de Bridge de `handoffOverride` | | `BRIDGE_AI_LEADSCOUT_0004` | 404 | Ninguna plantilla del espacio de trabajo coincide con `template.id`, o con `template.name` cuando no se envía un ID | | `BRIDGE_AI_LEADSCOUT_0005` | 409 | La plantilla no está aprobada | | `BRIDGE_AI_LEADSCOUT_0006` | 400 | No coinciden los parámetros ordenados de la plantilla | | `BRIDGE_AI_LEADSCOUT_0007` | 409 | Ya existe una conversación activa: otra solicitud obtuvo primero la conversación liberada. Reintenta | | `BRIDGE_AI_LEADSCOUT_0008` | 409 | Ninguna línea del agente está libre o es recuperable para este contacto; consulta `forceSend` | | `BRIDGE_AI_LEADSCOUT_0009` | 404 | No hay una línea configurada para el `brandId` solicitado | | `BRIDGE_AI_LEADSCOUT_0016` | 400 | Error de validación de conversación saliente | | `BRIDGE_AI_LEADSCOUT_0017` | 409 | La sesión más reciente no está finalizada | | `BRIDGE_AI_LEADSCOUT_0018` | 409 | No se pudo finalizar la sesión vencida antes de iniciar otra | | `BRIDGE_AI_LEADSCOUT_0019` | 422 | Faltan una o más variables obligatorias de la plantilla | | `BRIDGE_AI_LEADSCOUT_0020` | 422 | Hay fuentes de parámetros de plantilla superpuestas para la misma posición | | `BRIDGE_AI_LEADSCOUT_0021` | 422 | Clave de parámetro de plantilla desconocida | En `POST .../agents/{agentId}/outbound`, los errores `5xx` no incluyen `code` ni `extra`. ## Códigos de error de LeadScout Códigos adicionales documentados para [iniciar una conversación saliente de LeadScout](https://docs.bridge.new/es/api-reference/leadscout-api/iniciar-conversaci%C3%B3n-saliente-de-leadscout-con-un-lead-conocido.md) mediante `POST .../leadscout/outbound`: | Código | Estado | Referencia en inglés | Significado | | --- | --- | --- | --- | | `BRIDGE_AI_LEADSCOUT_0010` | 404 | Channel Not In Workspace | El canal de proveedor no pertenece al espacio de trabajo | | `BRIDGE_AI_LEADSCOUT_0011` | 404 | No Provider Channels | El espacio de trabajo no tiene canales de proveedor | | `BRIDGE_AI_LEADSCOUT_0012` | 404 | No Agent For Channel | No hay un agente de prospección para el canal | | `BRIDGE_AI_LEADSCOUT_0013` | 409 | Multiple Agents For Brand | Hay varios agentes de prospección para la marca | | `BRIDGE_AI_LEADSCOUT_0014` | 409 | Multiple Agents For Channel | Hay varios agentes de prospección para el canal | | `BRIDGE_AI_LEADSCOUT_0015` | 500 | Conversation Operation Failed | Falló la operación de conversación | ## Códigos de error de marcas Errores de comprobación de marcas al crear una conversación. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_BRAND_0101` | Brand Required | El espacio de trabajo tiene marcas habilitadas; cada participante externo debe corresponder a una marca o línea | Se devuelve como `400`. Envía `brandId` o `providerChannelId` para cada participante externo; `extra.resources` enumera los participantes que no tenían ninguno de los dos. ## Códigos de error de conversaciones Errores de las operaciones de conversaciones. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_CONVERSATION_0001` | Conversation Not Found | No se encontró la conversación solicitada | | `BRIDGE_CONVERSATION_0002` | Conversation Not In Workspace | La conversación no pertenece al espacio de trabajo especificado | | `BRIDGE_CONVERSATION_0003` | Conversation With Same Participants Already Exists | Ya existe una conversación activa con los mismos participantes | | `BRIDGE_CONVERSATION_0004` | Conversation Not Active | La conversación está inactiva y no se pueden hacer operaciones sobre ella | | `BRIDGE_CONVERSATION_0005` | Conversation Operation Failed | Ocurrió un error al operar sobre la conversación | | `BRIDGE_CONVERSATION_0006` | Conversation With Inconsistent State | La conversación tiene un estado inconsistente; contacta a soporte para resolverlo | | `BRIDGE_CONVERSATION_0007` | Conversation Is Released | La conversación está liberada: `409` en `POST .../messages` | | `BRIDGE_CONVERSATION_0101` | Internal User Already In Conversation | El usuario interno ya participa en la conversación | | `BRIDGE_CONVERSATION_0102` | Internal User Not In Conversation | El usuario interno no participa en la conversación | | `BRIDGE_CONVERSATION_0103` | External User Already In Conversation | El usuario externo ya participa en la conversación | | `BRIDGE_CONVERSATION_0104` | External User Not In Conversation | El usuario externo no participa en la conversación | | `BRIDGE_CONVERSATION_0105` | External User Already Use This Channel | El usuario externo ya usa este canal de mensajería en otra conversación | | `BRIDGE_CONVERSATION_0201` | External Participants Required | Se requiere al menos un participante externo para operar en una conversación | | `BRIDGE_CONVERSATION_0202` | Internal Participants Required | Se requiere al menos un participante interno para operar en una conversación | | `BRIDGE_CONVERSATION_0203` | User Is Not Admin | El usuario no es administrador de esta conversación | | `BRIDGE_CONVERSATION_0204` | Last Admin Removal Forbidden | La conversación debe tener al menos un administrador | | `BRIDGE_CONVERSATION_0205` | Min Internal Users Required | La conversación debe tener una cantidad mínima de participantes internos | | `BRIDGE_CONVERSATION_0206` | Max Internal Participants Exceeded | Se superó el máximo de participantes internos de la conversación | | `BRIDGE_CONVERSATION_0207` | Min External Participants Required | La conversación debe tener una cantidad mínima de participantes externos | | `BRIDGE_CONVERSATION_0208` | Max External Participants Exceeded | Se superó el máximo de participantes externos de la conversación | | `BRIDGE_CONVERSATION_0210` | Min Participants Required | La conversación debe tener una cantidad mínima de participantes | | `BRIDGE_CONVERSATION_0211` | Max Participants Exceeded | La conversación debe respetar una cantidad máxima de participantes | | `BRIDGE_CONVERSATION_0212` | Max Initial Messages Exceeded | Se superó el máximo de mensajes iniciales | | `BRIDGE_CONVERSATION_0213` | Messages Not In Conversation | Los mensajes deben pertenecer a la misma conversación | | `BRIDGE_CONVERSATION_0601` | Onboarding Template Not Found | No existe una plantilla indicada en el reemplazo de plantillas de inicio | | `BRIDGE_CONVERSATION_0602` | Onboarding Template Not In Workspace | Una plantilla indicada en el reemplazo de inicio pertenece a otro espacio de trabajo | | `BRIDGE_CONVERSATION_0603` | Onboarding Template Not Approved | Una plantilla indicada en el reemplazo de inicio no está aprobada para la línea usada para contactar a un participante | | `BRIDGE_CONVERSATION_0604` | Onboarding Template Missing Parameters | Faltan en una plantilla de inicio valores que solo puede proporcionar quien hace la solicitud | | `BRIDGE_CONVERSATION_0605` | Onboarding Template Unknown Parameters | El reemplazo de inicio nombra parámetros que la plantilla no declara | | `BRIDGE_CONVERSATION_0606` | Onboarding Template Parameters Not Supported | Se enviaron parámetros para una plantilla de inicio que no es una plantilla de proveedor de WhatsApp | | `BRIDGE_CONVERSATION_0607` | Onboarding Template Invalid Parameter Values | Los valores de parámetros de una plantilla de inicio infringen una regla de WhatsApp y se rechazarían al enviarse | | `BRIDGE_CONVERSATION_0608` | Onboarding Configured Template Requires Caller Input | Una plantilla de la secuencia de inicio del espacio de trabajo necesita valores que solo puede proporcionar quien hace la solicitud; un administrador debe cambiar la secuencia | Al crear una conversación, `BRIDGE_CONVERSATION_0105` devuelve `409` con `extra.reason` igual a `PARTICIPANTS_MISMATCH`: una conversación liberada ocupa la línea del contacto con otros contactos o líneas. Solicita los mismos contactos y líneas o usa otra línea. `BRIDGE_CONVERSATION_0601` devuelve `404`, `0602` y `0603` devuelven `400`, y `0604` a `0608` devuelven `422`. Consulta [Parámetros de plantillas de inicio](https://docs.bridge.new/es/templates-and-parameters.md) para saber qué incluye cada uno en `extra` y cómo corregirlo. ## Códigos de error de usuarios externos Errores de las operaciones de usuarios externos o contactos. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_EXTERNAL_0001` | External User Not Found | No se encontró el usuario externo solicitado | | `BRIDGE_EXTERNAL_0002` | External User Already Exists | Ya existe un usuario externo con los mismos datos de identificación | | `BRIDGE_EXTERNAL_0004` | External User Not In Workspace | Uno o más usuarios externos no pertenecen al espacio de trabajo especificado | | `BRIDGE_EXTERNAL_0005` | External User Without Configured Field | El usuario externo no tiene un campo configurado; revisa la configuración del espacio de trabajo o de información externa | | `BRIDGE_EXTERNAL_0007` | Cellphone Owned By Another Contact | El teléfono ya es una identidad activa de otro usuario externo | | `BRIDGE_EXTERNAL_0013` | Email Owned By Another Contact | El correo ya es una identidad activa de otro usuario externo | | `BRIDGE_EXTERNAL_0101` | External User Operation Failed | Ocurrió un error al operar sobre el usuario externo | ## Códigos de error de usuarios internos Errores de las operaciones de usuarios internos. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_INTERNAL_0001` | Internal User Not Found | No se encontró el usuario interno | | `BRIDGE_INTERNAL_0002` | Internal Users Not In Workspace | Los usuarios internos proporcionados no pertenecen al espacio de trabajo especificado | | `BRIDGE_INTERNAL_0003` | Inactive Internal User | Uno o más usuarios internos están inactivos en el espacio de trabajo; revisa su estado en la configuración | | `BRIDGE_INTERNAL_0004` | Internal User Without Configured Field | El usuario interno no tiene un campo configurado; revisa la configuración del espacio de trabajo o de información interna | | `BRIDGE_INTERNAL_0101` | Internal User Does Not Support Operation | El usuario interno no admite esta operación | ## Códigos de error de canales de proveedor Errores de las operaciones de canales de proveedor. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_PROVIDER_CHANNEL_0001` | Provider Channel Not Found | No se encontró el canal de proveedor; verifica que el espacio de trabajo tenga canales configurados | Al crear una conversación, este código se devuelve como `409` cuando no hay una línea de WhatsApp libre para un contacto ni una conversación liberada que recuperar, o cuando el `providerChannelId` indicado no está disponible para ese contacto. ## Códigos de error de límites de solicitudes Errores devueltos cuando un espacio de trabajo supera su presupuesto de solicitudes. Consulta el presupuesto, los encabezados y un cliente que regula su ritmo en [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md). | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_RATE_LIMIT_0001` | Too Many Requests | El espacio de trabajo agotó el presupuesto de solicitudes de la ventana actual | Este es el único código que debe reintentarse automáticamente, y solo después de la espera indicada por `Retry-After`. Los fallos de autenticación no son errores de límite de solicitudes y reintentarlos de forma programada no los resolverá. ## Códigos de error de solicitudes Errores devueltos antes de ejecutar una operación cuando la propia solicitud no se puede procesar. Consulta en el [Registro de cambios](https://docs.bridge.new/es/changelog.md) los parámetros que un endpoint dejará de aceptar. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_CORE_0101` | Invalid Field Format | El formato del campo es inválido; proporciona un valor válido | | `BRIDGE_CORE_0102` | Missing Required Field | Faltan campos obligatorios; revisa la operación | | `BRIDGE_CORE_0103` | Bad Request | La solicitud es inválida; revisa el cuerpo y los parámetros | | `BRIDGE_CORE_0104` | Invalid Cursor | El cursor es inválido; usa uno obtenido de una respuesta anterior | No reintentes ninguno de estos casos sin hacer cambios. `detail` describe el problema y, cuando es posible, indica el campo o parámetro incorrecto; la misma solicitud fallará igual hasta que la modifiques. ## Códigos de error de plantillas Errores de las operaciones de plantillas. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_TEMPLATE_0001` | Provider Template Not Found | No se encontró una plantilla de proveedor para el espacio de trabajo y nombre indicados | `GET .../templates/{templateId}` lo devuelve como `404` cuando el ID o nombre no coincide con una plantilla de WhatsApp de tu espacio de trabajo. ## Códigos de error de espacios de trabajo Errores de las operaciones de espacios de trabajo. | Código | Referencia en inglés | Mensaje | | --- | --- | --- | | `BRIDGE_WORKSPACE_0001` | Workspace Not Found | No se encontró el espacio de trabajo solicitado | | `BRIDGE_WORKSPACE_0002` | Workspace Not In Organization | El espacio de trabajo no pertenece a la organización especificada | | `BRIDGE_WORKSPACE_0003` | Workspace Without Available Provider Channels | El espacio de trabajo no tiene canales de proveedor disponibles | | `BRIDGE_WORKSPACE_0004` | Workspace Without Configured Field | El espacio de trabajo no tiene un campo configurado: `409` en `POST .../conversations/{conversationId}/release` | --- # Registro de cambios Source: https://docs.bridge.new/es/changelog Cambios de la API de Bridge que afectan tu integración, del más reciente al más antiguo. ## Descripción general Aquí se muestran los cambios que afectan las llamadas que ya haces, del más reciente al más antiguo. Los cambios aditivos —un endpoint nuevo o un campo opcional nuevo— no se incluyen salvo que reemplacen algo que se retirará; aparecen en la [referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md) cuando se publican. **Nota** Las entradas anteriores de abajo no registraron fechas de entrada en vigor. No se han verificado sus fechas de despliegue y su orden no establece una fecha de lanzamiento. **Aún no se ha anunciado** la fecha de retirada de los filtros de listado obsoletos. Sigue usando el contrato actual documentado hasta que se publique un cambio efectivo y usa los endpoints de consulta por identificador disponibles para integraciones nuevas. ## Mejoras de documentación Esta revisión aclara el contrato existente de la API e incorpora guías de integración por tarea. Renombra la función de landing pages como **Custom Connections**, explica la reutilización y recuperación de conversaciones salientes y mejora las guías de errores y webhooks. Se conservan las firmas actuales de la API y las URLs de documentación `/lead-capture`. La fecha de una revisión documental no es una fecha de despliegue de la API ni de retirada de funciones. --- ## Crear una conversación puede recuperar una liberada `POST /conversations` antes devolvía `409 BRIDGE_PROVIDER_CHANNEL_0001` cuando no había una línea libre. Ahora, si los contactos solicitados tienen una conversación liberada con recuperación habilitada, se recupera y se devuelve con `201` y su `id` existente. Por eso puedes recibir un `id` que ya tenías guardado. Si esa conversación incluye otros contactos o líneas, la solicitud devuelve `409 BRIDGE_CONVERSATION_0105`. Consulta los detalles en la [referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md). --- ## Buscar un contacto o usuario por identificador **Advertencia** **Se retirarán parámetros de consulta que existen hoy.** Todavía funcionan y están marcados como obsoletos en la [referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md). Antes de que dejen de aceptarse publicaremos aquí la fecha. Los endpoints de consulta por identificador que los reemplazan ya están disponibles. ### Qué cambia **Disponibles ahora:** `GET /contacts/lookup` y `GET /users/lookup` devuelven un contacto o un usuario de Bridge —usuario interno en la referencia de la API— a partir de un identificador. **Obsoletos, pendientes de retirada:** los endpoints de listado dejarán de filtrar. `GET /contacts` y `GET /users` conservarán únicamente `limit` y `cursor`. | Obsoleto | Reemplazo | | --- | --- | | `GET /contacts?search=`: teléfono | `GET /contacts/lookup?type=PHONE&value=…` | | `GET /contacts?search=`: correo | `GET /contacts/lookup?type=EMAIL&value=…` | | `GET /contacts?search=`: nombre | **Ninguno** | | `GET /contacts?ownerEmail=` | **Ninguno** | | `GET /users?email=` | `GET /users/lookup?type=EMAIL&value=…` | | `GET /users?status=` | **Ninguno**: cada fila ya incluye `status` | Después de retirarse, el parámetro se **rechazará**, no se ignorará. Enviarlo devolverá `400` con `BRIDGE_CORE_0103` y la respuesta nombrará el parámetro. Es deliberado: si se ignorara el filtro silenciosamente, la llamada entregaría la primera página de todo el espacio de trabajo y podrías tratarla como una coincidencia. ### Qué debes hacer **Si buscas por teléfono o correo**, migra al endpoint de consulta correspondiente. Devuelve el mismo objeto que el listado entrega en cada fila, o `404` cuando no hay coincidencia. `type` acepta los tipos de identificador que la API usa en otros lugares: los mismos valores de `identifierType` de un participante de conversación. Los contactos admiten `ID`, `EMAIL` y `PHONE`; los usuarios de Bridge admiten `ID` y `EMAIL`, porque su teléfono no funciona como identificador de consulta en Bridge. Se admite `ID` por la misma razón: el código que ya maneja un par `{identifierType, identifier}` no debería tener que separar uno de sus valores para construir una URL distinta. Devuelve exactamente lo mismo que `GET /contacts/{contactId}`, que sigue siendo la URL canónica de un contacto: prefiérela cuando ya tengas el ID. ```bash # Before curl "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts?search=%2B14084029292" \ -H "x-api-key: $BRIDGE_API_KEY" # After curl "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts/lookup?type=PHONE&value=%2B14084029292" \ -H "x-api-key: $BRIDGE_API_KEY" ``` Un `PHONE` se interpreta igual que el teléfono que envías al crear un contacto: si no incluye código de país, se interpreta según el país predeterminado del espacio de trabajo, y se ignoran espacios y separadores. En un `EMAIL`, el dominio se convierte a minúsculas, pero la parte local debe coincidir exactamente con lo enviado. **Nota** Un teléfono en formato internacional comienza con `+`, que debe codificarse como `%2B` en la cadena de consulta. La mayoría de los clientes HTTP lo hacen automáticamente si proporcionas los parámetros como un mapa en lugar de construir la URL a mano. Un `value` que no corresponda a su `type` —correo, teléfono o UUID con formato incorrecto— se rechaza con `422` y `BRIDGE_CORE_0101` antes de hacer la búsqueda. Si pasas entradas del usuario directamente, maneja ese caso por separado de `404`: uno indica *enviaste algo que no es un identificador* y el otro, *nadie en este espacio de trabajo tiene ese identificador*. **Si filtras usuarios de Bridge por estado**, lee el `status` de cada fila. Es un valor calculado, no almacenado, y ya aparece en todas las respuestas. Hoy el listado devuelve solo usuarios activos si no envías `status`; cuando se retire ese parámetro, devolverá tanto activos como deshabilitados. Lo mismo aplica a `GET /users/lookup`: devuelve al usuario de Bridge esté activo o deshabilitado y prefiere el activo cuando el correo coincide con ambos. Hoy `GET /users?email=` no devuelve un usuario deshabilitado; por eso debes revisar el `status` de la respuesta si solo quieres actuar sobre usuarios activos. **Si buscas contactos por nombre**, no habrá reemplazo. Conviene entender qué se pierde: el parámetro solo coincide con el **nombre completo exacto**, formado por nombre, un espacio y apellido. Nunca coincide con un prefijo, una parte del nombre o solo el apellido. Si hoy te funciona, ya estás enviando el nombre completo. **Si filtras contactos por propietario**, no habrá reemplazo. Obtén la página y filtra por `ownerId` en tu código. `ownerId` es el ID del usuario de Bridge propietario, no su correo: consúltalo una vez con `GET /users/lookup?type=EMAIL&value=…` y compáralo con su `id`. ### Por qué cambia Filtrar con esos parámetros hace que el costo de la llamada dependa del tamaño del espacio de trabajo en lugar del tamaño de la respuesta. Buscar un contacto por teléfono en un espacio de trabajo grande lee decenas de miles de registros para devolver uno; pedir una página mayor lo hace más lento, no más rápido. Los endpoints de consulta solo leen los registros que tienen ese identificador. Por eso se retiran esos filtros en lugar de ajustarlos: cuando existe un reemplazo, es mejor; y la búsqueda por nombre, que no tiene reemplazo, nunca encontró algo distinto del nombre completo exacto. --- ## Temas relacionados - [Códigos de error](https://docs.bridge.new/es/error-codes.md): referencia completa, incluidos `BRIDGE_CORE_0103` y `BRIDGE_CORE_0101`. - [Referencia de la API REST](https://docs.bridge.new/es/api-reference/health/comprobar-estado.md): endpoints de consulta, sus parámetros y sus respuestas. - [Límites de solicitudes](https://docs.bridge.new/es/rate-limits.md): qué acepta la API por espacio de trabajo y cómo esperar correctamente antes de reintentar. --- # Recibe webhooks de Bridge Source: https://docs.bridge.new/es/webhooks Conecta un receptor HTTPS a los eventos de Bridge y entiende la autenticación, la confirmación de recepción y el procesamiento asíncrono. Los webhooks envían eventos **desde Bridge hacia tu sistema**. Configura una URL de recepción HTTPS y suscríbete a las familias de eventos que necesita tu integración. Bridge envía JSON mediante `POST`; tu receptor autentica y almacena el evento antes de devolver `2xx`. Usa la [API REST de integraciones](https://docs.bridge.new/es/credentials.md) cuando tu sistema necesite leer o modificar un recurso de Bridge. Una suscripción de webhook no crea por sí sola una integración bidireccional completa con un CRM: tu receptor debe relacionar los identificadores, procesar el evento e implementar las escrituras de vuelta que necesites mediante la operación REST documentada. ## Construye el receptor ### Elige los eventos Lee la [referencia de eventos](https://docs.bridge.new/es/webhooks/events.md) y elige la familia y la versión de suscripción adecuadas para tu flujo. ### Verifica y almacena cada solicitud Sigue [Verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md) para la serialización HMAC exacta y [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md) para un ejemplo de almacenamiento duradero. ### Configura y prueba la recepción Introduce la URL, la clave de API del webhook y el secreto de cliente en la [consola de administración de Bridge](https://docs.bridge.new/es/webhooks/configuration.md). Comprueba el webhook de prueba antes de habilitar el flujo de negocio. ```mermaid sequenceDiagram participant B as Bridge participant R as Tu receptor participant I as Bandeja de entrada duradera participant W as Tu proceso de trabajo B->>R: POST de un evento JSON y encabezados de autenticación R->>R: Verifica la clave de API, el HMAC y la política de vigencia R->>I: Guarda el evento verificado o confirma el duplicado exacto I-->>R: Aceptación duradera R-->>B: Confirmación 2xx W->>I: Lee los eventos pendientes W->>W: Aplica la acción de negocio de forma idempotente ``` ## Mantén separadas las credenciales | Encabezado | Finalidad | | --- | --- | | `X-Bridge-API-Key` | Clave de API del webhook configurada para esta URL de recepción. Compárala con el valor esperado. | | `X-Bridge-Signature` | `sha256=` seguido del HMAC-SHA256 de la representación canónica del evento de Bridge, calculado con tu secreto de cliente del webhook. | | `X-Bridge-Timestamp` | Segundos Unix para comprobar la vigencia en el receptor. El HMAC **no** incluye este encabezado. | Estas credenciales de webhook son distintas de la `x-api-key` de la API REST y de la `captureKey` de Custom Connections usada en el navegador. Guarda el secreto de cliente del webhook en tu servidor. ## Qué significa la confirmación de recepción Una respuesta `2xx` significa que tu receptor aceptó el evento. No demuestra que haya terminado la actualización del CRM u otra acción de negocio. Guarda primero el evento y procésalo fuera de la solicitud para que un servicio lento posterior no retrase la confirmación. El emisor HTTP actual hace tres intentos por operación de entrega, con esperas de uno y dos segundos y un tiempo de espera de socket predeterminado de diez segundos. Esto no promete un total de tres intentos para toda la cadena de procesamiento del evento. Lee el [comportamiento de reintentos, duplicados y orden](https://docs.bridge.new/es/webhooks/receive-events.md) antes de elegir tu política de recuperación. No asumas entrega exactamente una vez, un orden global de eventos ni un endpoint público de reenvío. La [referencia de eventos](https://docs.bridge.new/es/webhooks/events.md) describe los cuerpos de los eventos; la [guía del receptor](https://docs.bridge.new/es/webhooks/receive-events.md) explica cómo manejarlos de forma confiable. --- # Verifica las solicitudes de webhook Source: https://docs.bridge.new/es/webhooks/verifying-signatures Verifica la clave de API del webhook y la representación HMAC exacta que usa Bridge; luego deduplica los eventos aceptados. Verifica cada solicitud antes de aceptarla en tu sistema. Usa la clave de API del **webhook** y el secreto de cliente configurados para esta URL de recepción: son distintos de la clave de la API REST de integraciones. ## Encabezados de autenticación | Encabezado | Comprobación | | --- | --- | | `X-Bridge-API-Key` | Comparación en tiempo constante con la clave de API del webhook que configuraste | | `X-Bridge-Signature` | `sha256=` seguido del resumen hexadecimal HMAC-SHA256 en minúsculas | | `X-Bridge-Timestamp` | Segundos Unix dentro de la ventana de vigencia aceptada; el ejemplo admite cinco minutos en ambas direcciones | Los nombres de los encabezados no distinguen mayúsculas y minúsculas. ## Qué se firma exactamente Bridge construye la entrada del HMAC a partir del evento JSON con esta expresión de Python y luego codifica la cadena en UTF-8: ```python json.dumps(event, sort_keys=True).encode("utf-8") ``` Esto ordena recursivamente las claves de los objetos, conserva el orden de los arrays, escapa los caracteres no ASCII y usa los espacios predeterminados de Python después de comas y dos puntos. No agrega un salto de línea final. La clave es el secreto de cliente codificado en UTF-8. Es una convención de serialización JSON de Python, no RFC 8785 / JCS. No la reemplaces por un resumen de los bytes crudos arbitrarios de la solicitud, JSON compacto, un `JSON.stringify` genérico de JavaScript ni una cadena con una marca de tiempo como prefijo. Los espacios, los escapes Unicode y el formato de números pueden cambiar la entrada HMAC aunque el objeto interpretado parezca equivalente. Usa el verificador de Python de abajo o prueba otra implementación contra el vector antes de conectarla. **Advertencia** La entrada HMAC actual contiene únicamente el JSON del evento. **`X-Bridge-Timestamp` no está incluido en la firma.** Comprueba la vigencia, pero no consideres que la marca de tiempo por sí sola ofrece protección criptográfica contra reenvíos: un cuerpo y una firma válidos anteriores pueden presentarse con otra marca de tiempo. Autentica la clave de API del webhook y usa una bandeja de entrada duradera y procesamiento idempotente, como explica [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md). ## Verificador de Python Guárdalo como `bridge_webhooks.py`. Devuelve el objeto interpretado y verificado para que el código posterior use la misma interpretación que se autenticó. Obtén los secretos de variables de entorno del servidor o de tu almacén de secretos. ```python import hashlib import hmac import json import re import sqlite3 import time class VerificationError(ValueError): pass def canonical_payload(event): # Match Bridge's Python json.dumps defaults: sort recursively, ASCII escapes, # a space after commas and colons, then UTF-8. This is not RFC 8785 / JCS. return json.dumps(event, sort_keys=True).encode("utf-8") def _unique_object(pairs): result = {} for key, value in pairs: if key in result: raise VerificationError("Duplicate JSON object key") result[key] = value return result def verify_webhook(raw_body, headers, webhook_api_key, client_secret, *, now=None, tolerance=300): headers = {key.lower(): value for key, value in headers.items()} received_key = headers.get("x-bridge-api-key", "") if not received_key or not webhook_api_key or not client_secret: raise VerificationError("Missing webhook credentials") if not hmac.compare_digest(received_key.encode("utf-8"), webhook_api_key.encode("utf-8")): raise VerificationError("Invalid webhook API key") received_signature = headers.get("x-bridge-signature", "") if not re.fullmatch(r"sha256=[0-9a-f]{64}", received_signature): raise VerificationError("Invalid signature format") timestamp = headers.get("x-bridge-timestamp", "") if not re.fullmatch(r"[0-9]+", timestamp): raise VerificationError("Invalid timestamp") current_time = time.time() if now is None else now if abs(current_time - int(timestamp)) > tolerance: raise VerificationError("Timestamp outside the permitted window") try: event = json.loads(raw_body.decode("utf-8"), object_pairs_hook=_unique_object) except (UnicodeDecodeError, json.JSONDecodeError) as exc: raise VerificationError("Invalid JSON body") from exc if not isinstance(event, dict): raise VerificationError("Expected a JSON object") expected = "sha256=" + hmac.new( client_secret.encode("utf-8"), canonical_payload(event), hashlib.sha256 ).hexdigest() if not hmac.compare_digest(expected, received_signature): raise VerificationError("Invalid webhook signature") return event ``` La ventana de cinco minutos es una política del receptor; mantén sincronizado el reloj de tu servidor. El verificador también rechaza claves JSON duplicadas y ambiguas. No desactives la autenticación para depurar una discrepancia: revisa las credenciales configuradas y compara la entrada canónica con los datos de prueba siguientes. ## Vector de firma reproducible Estos valores son datos sintéticos de prueba, no credenciales reales ni un evento para enviar a Bridge. Al probar las comprobaciones de vigencia, fija el argumento `now` del verificador en `1800000000`. | Valor | Dato de prueba | | --- | --- | | Secreto de cliente | `bridge-docs-test-secret` | | Clave de API del webhook | `bridge-docs-test-key` | | Encabezado de marca de tiempo | `1800000000` | | Firma esperada | `sha256=5536c29fd98baab6ffe46dd9517adb185b32202864cbb5a76146172fc0b39423` | Objeto de evento: ```json { "eventId": "evt_docs_001", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_docs", "timestamp": "2026-01-01T00:00:00Z", "payload": { "name": "José", "tags": [ "café", "one" ], "active": true, "count": 2 } } ``` Cadena JSON exacta que se firma: las secuencias `\u` siguientes contienen barras invertidas ASCII literales, no caracteres decodificados. ```text {"entity": "contact", "eventId": "evt_docs_001", "eventType": "contact.updated", "payload": {"active": true, "count": 2, "name": "Jos\u00e9", "tags": ["caf\u00e9", "one"]}, "timestamp": "2026-01-01T00:00:00Z", "workspaceId": "ws_docs"} ``` Cambiar un campo debe hacer fallar la verificación. Cambiar solo el orden de las claves de entrada o enviar Unicode literal en lugar de escapes Unicode JSON debe seguir verificando después de interpretar el JSON y reconstruir la misma representación canónica. ## Después de verificar Guarda el evento de forma duradera antes de confirmar su recepción. Un HMAC válido confirma la representación autenticada del evento; no demuestra que se haya ejecutado tu acción de negocio, que el evento sea nuevo ni que represente el estado más reciente del recurso. Continúa con [entrega, duplicados y orden](https://docs.bridge.new/es/webhooks/receive-events.md). --- # Recibe eventos de forma confiable Source: https://docs.bridge.new/es/webhooks/receive-events Verifica, guarda y confirma los webhooks; después procesa de forma segura los duplicados y los eventos fuera de orden. Un receptor de webhooks tiene dos tareas: aceptar rápidamente un evento autenticado y procesarlo de forma confiable después. Ejecuta las llamadas lentas al CRM, el enriquecimiento y otras tareas de negocio fuera de la solicitud HTTP. ## Recibe → verifica → guarda → confirma 1. Lee el cuerpo y los encabezados de la solicitud. 2. Verifica la clave de API del webhook, el HMAC canónico y la política de marcas de tiempo con [el verificador](https://docs.bridge.new/es/webhooks/verifying-signatures.md). 3. Guarda atómicamente el evento verificado en una bandeja de entrada duradera o confirma que ese evento exacto ya esté almacenado. 4. Devuelve una respuesta `2xx` rápidamente. Procesa los eventos almacenados en un proceso de trabajo y haz que cada acción de negocio sea idempotente. Devuelve éxito solo después de la aceptación duradera. Si el almacenamiento no está disponible, devuelve una respuesta distinta de `2xx` para no confirmar el intento de entrega. Un duplicado que ya está guardado debe recibir `2xx` nuevamente. ## Comportamiento de reintentos El emisor actual hace hasta **tres intentos HTTP** para una operación de entrega. Espera **un segundo** y luego **dos segundos** antes de los intentos restantes. Cualquier respuesta `2xx` detiene esos intentos. Una respuesta distinta de `2xx`, un fallo de conexión o una excepción de solicitud pueden activar el siguiente intento. El tiempo de espera de socket predeterminado es de **10 segundos** por intento: confirma la recepción en pocos segundos en lugar de depender de un margen de 30 segundos. El cuerpo y los encabezados de firma y marca de tiempo se reutilizan dentro de esa operación de entrega. Esos tres intentos limitan una operación de envío, **no el total de entregas de un evento de extremo a extremo**. Si un evento vuelve a entregarse en una etapa anterior, puede invocar de nuevo al emisor. Aquí no se promete un número total de reintentos ni un plazo máximo de reenvío. No dependas de un encabezado de respuesta `Retry-After` para establecer los tiempos de reintento de Bridge. Si fallan todos los intentos, la entrega se considera fallida. No asumas reintentos automáticos indefinidos ni un endpoint público de reenvío. Para investigar, conserva el espacio de trabajo, el tipo, el ID y la hora aproximada del evento, y contacta a soporte de Bridge. No incluyas las credenciales del webhook en mensajes a soporte ni en registros de la aplicación. ## Duplicados e identidad del evento Tu servicio puede haber guardado un evento aunque Bridge no haya recibido tu respuesta `2xx`. Reintentarlo no debe crear una segunda actualización del CRM, factura, mensaje u otro efecto de negocio. Delimita cada registro de la bandeja mediante `workspaceId`, `eventType` y `eventId`. Guarda también un resumen del evento verificado. No asumas que `eventId` es globalmente único en todas las familias de notificaciones: algunas usan un ID derivado de la entidad. Conserva los cuerpos distintos que compartan un ID y aplica después idempotencia de negocio a la operación que ejecuta tu proceso de trabajo. El ejemplo siguiente deduplica eventos repetidos exactos usando los tres identificadores y la huella SHA-256 del evento canónico. Es una clave de bandeja para este ejemplo, no un campo nuevo de solicitud de Bridge. No hagas vencer un registro de deduplicación solo porque transcurrió la ventana de cinco minutos de la marca de tiempo. Ese encabezado no está firmado, por lo que la ventana no establece un vencimiento seguro de protección contra reenvíos. Elige la retención según las necesidades de conciliación de tu negocio y mantén idempotentes las acciones del sistema de destino. El ejemplo no elimina automáticamente los registros de la bandeja. ## Receptor duradero mínimo Agrega estas definiciones al módulo `bridge_webhooks.py` de [Verificar solicitudes de webhook](https://docs.bridge.new/es/webhooks/verifying-signatures.md). El módulo del verificador ya incluye las importaciones usadas aquí. ```python class SQLiteInbox: """Single-service example inbox. Use a shared durable store for multiple replicas.""" def __init__(self, path): self.path = str(path) with sqlite3.connect(self.path) as db: db.execute("""CREATE TABLE IF NOT EXISTS webhook_inbox ( workspace_id TEXT NOT NULL, event_type TEXT NOT NULL, event_id TEXT NOT NULL, fingerprint TEXT NOT NULL, body TEXT NOT NULL, received_at REAL NOT NULL, processed INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(workspace_id, event_type, event_id, fingerprint) )""") def accept(self, event): identifiers = [event.get(key) for key in ("workspaceId", "eventType", "eventId")] if not all(isinstance(value, str) and value for value in identifiers): raise VerificationError("Missing event envelope identifiers") body = canonical_payload(event) fingerprint = hashlib.sha256(body).hexdigest() with sqlite3.connect(self.path, timeout=3) as db: cursor = db.execute( """INSERT OR IGNORE INTO webhook_inbox (workspace_id, event_type, event_id, fingerprint, body, received_at) VALUES (?, ?, ?, ?, ?, ?)""", (*identifiers, fingerprint, body.decode("utf-8"), time.time()), ) inserted = cursor.rowcount == 1 # Context manager commits before the request can be acknowledged. return inserted def make_wsgi_app(inbox, webhook_api_key, client_secret): """Verify, commit an inbox record, then acknowledge; workers process it later.""" def app(environ, start_response): if environ.get("REQUEST_METHOD") != "POST": start_response("405 Method Not Allowed", [("Allow", "POST")]) return [b""] try: length = int(environ.get("CONTENT_LENGTH") or "0") if length < 1: raise VerificationError("Missing JSON body") raw_body = environ["wsgi.input"].read(length) headers = { "x-bridge-api-key": environ.get("HTTP_X_BRIDGE_API_KEY", ""), "x-bridge-signature": environ.get("HTTP_X_BRIDGE_SIGNATURE", ""), "x-bridge-timestamp": environ.get("HTTP_X_BRIDGE_TIMESTAMP", ""), } event = verify_webhook(raw_body, headers, webhook_api_key, client_secret) inbox.accept(event) # A duplicate exact event is also acknowledged. except (VerificationError, ValueError): status, body = "400 Bad Request", b'{"accepted":false}' except sqlite3.Error: status, body = "503 Service Unavailable", b'{"accepted":false}' else: status, body = "200 OK", b'{"accepted":true}' start_response(status, [("Content-Type", "application/json"), ("Content-Length", str(len(body)))]) return [body] return app ``` Crea la aplicación WSGI en la configuración de tu servidor: ```python import os from bridge_webhooks import SQLiteInbox, make_wsgi_app application = make_wsgi_app( SQLiteInbox(os.environ["WEBHOOK_INBOX_PATH"]), os.environ["BRIDGE_WEBHOOK_API_KEY"], os.environ["BRIDGE_WEBHOOK_CLIENT_SECRET"], ) ``` Usa una ruta de base de datos duradera para este ejemplo de un solo servicio. Si ejecutas varias réplicas del receptor, usa almacenamiento compartido con una restricción equivalente de unicidad atómica. Aplica los límites de tamaño de solicitud y las políticas de red de tu servicio en el servidor HTTP, y termina allí la conexión HTTPS. Este ejemplo llega hasta la aceptación duradera. Un proceso de trabajo debe leer las filas con `processed=0`, ejecutar la acción de negocio de manera idempotente y marcarlas como procesadas solo después del éxito. Una confirmación local no demuestra que la acción de negocio haya terminado. ## Orden y conciliación No dependas de un orden global de entrega. Distintas familias de recursos e intentos independientes de entrega pueden intercalarse. Dirige cada evento según el `eventType` publicado y usa el esquema de esa suscripción. Cuando un cuerpo incluya `sequence`, trátalo como una indicación de orden del recurso o flujo, no como un contador global compartido por todos los espacios de trabajo o familias de eventos. No lo inventes para eventos cuyo esquema no tenga secuencia. Conserva las marcas de tiempo y los identificadores de origen, y evita reemplazar un estado nuevo por una notificación anterior. Si la API REST permite leer el recurso, consulta su estado actual cuando el evento deje el resultado incierto; de lo contrario, sigue la guía de la familia de eventos o contacta a soporte. No exijas un campo `version` universal en todos los sobres de evento. Para las familias admitidas por este servicio de webhooks, la versión de suscripción configurada selecciona el transformador registrado y el esquema de esa familia. Sigue el esquema documentado de esa familia y suscripción; no deduzcas una propiedad de versión que el sobre no publica. ## Comprueba el receptor antes de pasar a producción Prueba el vector de firma proporcionado, un cuerpo modificado, una clave de API incorrecta, marcas de tiempo vencidas y futuras, una entrega duplicada después de reiniciar el proceso, un fallo de almacenamiento y dos cuerpos distintos con el mismo ID. Reenviar un cuerpo firmado anteriormente con una nueva marca de tiempo demuestra por qué necesitas una bandeja duradera además de la comprobación de vigencia. Usa el webhook de prueba de la consola de Bridge para validar la conexión y las credenciales configuradas después de desplegar el receptor. Una prueba exitosa demuestra que funciona la ruta de recepción; no establece garantías de entrega u orden para todos los eventos de negocio. --- # Configura los webhooks Source: https://docs.bridge.new/es/webhooks/configuration Configura una URL de recepción, las credenciales del webhook y las suscripciones de eventos en la consola de administración de Bridge. Puedes administrar toda la configuración de webhooks desde la [consola de administración de Bridge](https://admin.bridge.new). Esto incluye el endpoint receptor, las claves de autenticación y los tipos de eventos a los que quieres suscribirte. --- ## Configura los webhooks Sigue estos pasos en la consola de administración de Bridge: 1. **Inicia sesión** en la consola de administración de Bridge. 2. Ve a **Developers → Webhooks**. 3. Proporciona estos datos: - **Webhook URL:** URL HTTPS completa de tu endpoint. - **API Key:** clave que identifica tu espacio de trabajo. - **Client Secret:** secreto usado para generar y verificar firmas HMAC-SHA256 de los webhooks. 4. Selecciona en **Select Event Types** los eventos a los que quieres suscribirte. --- ## Conectores nativos de CRM y webhooks personalizados Un conector nativo de CRM y un webhook personalizado son vías de entrega separadas. Si tienes un CRM conectado, comprueba la configuración activa del conector y las funciones que muestra la consola. Esta página no establece que se sincronicen todos los eventos, que no se requiera configuración ni que las actualizaciones tengan un plazo fijo en tiempo real. Configura un webhook personalizado cuando tu servicio necesite recibir un evento y procesarlo por su cuenta. Puedes suscribirte a una familia de eventos que también use un conector nativo. Si tu receptor escribe en el mismo CRM, coordina las dos vías para no aplicar dos veces la misma acción de negocio. La confirmación de un webhook personalizado solo indica que tu receptor lo aceptó. Usa [aceptación duradera y procesamiento idempotente](https://docs.bridge.new/es/webhooks/receive-events.md); no asumas que dos vías de entrega garantizan actualizaciones del CRM exactamente una vez. --- ## Opciones de suscripción de eventos Bridge admite actualmente las siguientes categorías: ### Notificaciones de resúmenes de conversación v1 Recibe una notificación diaria por conversación cuando Bridge AI genera el resumen del día. - `conversation_summary.created` ### Notificaciones de tareas v1 Recibe notificaciones cuando se crean tareas o cambia su estado. - `task.created` - `task.status_changed` - `task.assigned` - `task.unassigned` - `task.remove_reminder` - `task.field_updated` ### Actualizaciones de contactos v1 Recibe notificaciones cuando se crean, actualizan o eliminan contactos. - `contact.created` - `contact.updated` - `contact.deleted` ### Notificaciones de llamadas v1 Recibe un webhook por cada fase del ciclo de vida de una llamada —creada, sonando, iniciada y finalizada— y la transcripción de IA cuando esté lista. Las llamadas no se eliminan. - `call.created` - `call.updated` - `call.transcription.created` ### Notificaciones de reuniones v1 Recibe una notificación cuando una reunión alcanza el estado CREATED. Las reuniones no se eliminan, por lo que solo se emite `meeting.updated`. - `meeting.updated` ### Notificaciones de correo electrónico v1 Recibe una notificación cuando se ha procesado un correo y está disponible su resumen de IA. Los correos no se eliminan, por lo que solo se emite `email.updated`. - `email.updated` --- ## Verifica la configuración Al guardar la configuración, Bridge envía automáticamente un **webhook de prueba** a tu endpoint para comprobar que sea accesible y responda correctamente. Tu endpoint debe responder con: - **Código de estado HTTP:** `200–299`. - **Content-Type:** `application/json` (opcional). - **Tiempo de respuesta:** confirma rápidamente después de guardar el evento de forma duradera. El emisor usa un tiempo de espera de socket predeterminado de 10 segundos por intento HTTP; no dependas de un margen de 30 segundos. Consulta el [comportamiento de reintentos](https://docs.bridge.new/es/webhooks/receive-events.md#retry-behavior). --- ## Administra los webhooks Puedes administrar su configuración en cualquier momento desde la consola: | Acción | Descripción | | --- | --- | | **Edit** | Actualiza la URL, la clave de API o los eventos suscritos | | **Disable Events** | Pausa temporalmente tipos específicos de eventos sin eliminar el webhook | | **Delete** | Elimina permanentemente una configuración de webhook | --- ## Temas relacionados - [Descripción general](https://docs.bridge.new/es/webhooks.md) - [Verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md) - [Tipos de eventos](https://docs.bridge.new/es/webhooks/events.md) --- # Eventos de webhook Source: https://docs.bridge.new/es/webhooks/events Familias de eventos, ejemplos de cuerpos y versiones de suscripción de los webhooks de Bridge. Los webhooks de Bridge entregan cuerpos de eventos estructurados en JSON cuando ocurren acciones específicas en tu espacio de trabajo. Cada evento sigue un esquema consistente para facilitar su interpretación y validación. --- ## Estructura común de los eventos El ejemplo siguiente ilustra el sobre común: `"string"` representa un tipo, no un valor de evento para enviar. Lee los ejemplos de cada familia más abajo. No asumas que `eventId` sea globalmente único entre familias de notificaciones. ```json { "eventId": "string", "eventType": "string", "entity": "string", "workspaceId": "string", "timestamp": "string", "payload": {} } ``` --- ## Notificaciones de resúmenes de conversación v1 Se activan una vez al día por conversación cuando Bridge AI genera el resumen diario. El resumen recoge los puntos principales del intercambio y los participantes internos y externos involucrados. ### Tipos de eventos | Tipo de evento | Descripción | | --- | --- | | `conversation_summary.created` | Se generó el resumen diario de una conversación | ### Ejemplo de cuerpo ```json { "eventId": "evt_summary_001", "eventType": "conversation_summary.created", "entity": "conversation_summary", "workspaceId": "ws_123", "timestamp": "2026-05-19T05:03:15.910Z", "payload": { "conversationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "summaryDate": "2026-05-19", "summary": "- Advisor asked the customer about their preferred schedule and offered to book a product demo.\n- Customer replied they are unavailable on Monday morning.\n- Advisor offered alternative slots later in the week and is waiting for confirmation.", "externalUsers": [ { "id": "c1d2e3f4-a5b6-7890-cdef-012345678901", "first_name": "Ana", "last_name": "Garcia", "cellphone": "+57300000000" } ], "internalUsers": [ { "id": "d4e5f6a7-b8c9-0123-defa-234567890123", "first_name": "Bob", "last_name": "Smith", "cellphone": "+57301000000", "email": "bob.smith@example.com" } ], "initMessageId": "f1e2d3c4-b5a6-7890-fedc-ba0987654321", "endMessageId": "a9b8c7d6-e5f4-3210-abcd-ef9876543210", "createdAt": "2026-05-19T05:03:15.910Z", "updatedAt": "2026-05-19T05:03:15.910Z" } } ``` --- ## Actualizaciones de tareas v1 Se activan cuando se crean tareas o cambian su estado, asignación o recordatorios. Los cuerpos varían según el tipo de evento. El campo `details` explica qué cambió en ese evento específico. ### Tipos de eventos | Tipo de evento | Descripción | | --- | --- | | `task.created` | Se creó una tarea | | `task.status_changed` | Cambió el estado de la tarea, por ejemplo, de OPEN a CLOSED | | `task.assigned` | Se asignó un usuario a la tarea | | `task.unassigned` | Se quitó la asignación de un usuario a la tarea | | `task.remove_reminder` | Se eliminó un recordatorio de la tarea | | `task.field_updated` | Se actualizó un campo de la tarea | ### Ejemplos de cuerpos ```json Created { "eventId": "evt_123456789", "eventType": "task.created", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:30:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example task description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:30:00.000Z" }, "assignees": [ { "assigneeId": "user_456", "assigneeType": "USER" } ], "conversations": [ { "id": "conv_123", "status": "ACTIVE", "createdAt": "2026-01-14T09:10:00.000Z", "updatedAt": "2026-01-14T09:10:00.000Z" } ] } } ``` ```json Assigned { "eventId": "evt_123456790", "eventType": "task.assigned", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:31:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "assignee": { "assigneeId": "user_456" } } } } ``` ```json Unassigned { "eventId": "evt_123456791", "eventType": "task.unassigned", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:32:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "assignee": { "assigneeId": "user_456" } } } } ``` ```json Status changed (open → closed) { "eventId": "evt_123456792", "eventType": "task.status_changed", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:33:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "statusChange": { "fromStatus": "OPEN", "toStatus": "CLOSED" } } } } ``` ```json Status changed (closed → open) { "eventId": "evt_123456793", "eventType": "task.status_changed", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:34:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example task description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:34:00.000Z" }, "conversations": [ { "id": "conv_123", "status": "ACTIVE", "createdAt": "2026-01-14T09:10:00.000Z", "updatedAt": "2026-01-14T09:10:00.000Z" } ], "details": { "statusChange": { "fromStatus": "CLOSED", "toStatus": "OPEN" } } } } ``` ```json Reminder removed { "eventId": "evt_123456794", "eventType": "task.remove_reminder", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:35:00.000Z", "payload": { "taskId": "task_456", "actorType": "USER", "actorId": "user_123", "details": { "reminder": { "reminderId": "rem_123" } } } } ``` ```json Field updated { "eventId": "evt_123456795", "eventType": "task.field_updated", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:36:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example updated description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:36:00.000Z" }, "details": { "fieldUpdate": { "changedFields": ["description"] } } } } ``` --- ## Actualizaciones de contactos v1 Se activan cuando se crean, actualizan o eliminan registros de contactos. ### Tipos de eventos | Tipo de evento | Descripción | | --- | --- | | `contact.created` | Se creó un contacto | | `contact.updated` | Se actualizó un registro de contacto | | `contact.deleted` | Se eliminó un contacto | ### Ejemplos de cuerpos Los campos de propiedad dependen de si el contacto está vinculado a un CRM externo: - Los **contactos sincronizados con un CRM** incluyen `crmContactId` y `crmLastSyncedAt`: la identidad del contacto la controla el CRM, no un usuario interno de Bridge. - Los **contactos nativos de Bridge**, sin vínculo a un CRM, incluyen en cambio `internalUserOwnerId`, que identifica al usuario de Bridge propietario del registro. Estos grupos son mutuamente excluyentes: un contacto sincronizado no incluye `internalUserOwnerId`, y uno no sincronizado no incluye `crmContactId` ni `crmLastSyncedAt`. Cada entrada de `openAttributes` y `closedAttributes` incluye un `name` legible junto a `customAttributeId`. Para atributos cerrados, `closedCustomAttributeIds` es un array de objetos `{ id, content }`, donde `content` es la etiqueta visible de la opción elegida. ```json CRM-synced { "eventId": "evt_contact_001", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:30:00.000Z", "payload": { "id": "contact_123", "firstName": "John", "lastName": "Doe", "email": "john@example.com", "cellphone": "+1234567890", "languageCode": "EN", "openAttributes": [ { "customAttributeId": "attr_open_1", "name": "Account Number", "content": "14" } ], "closedAttributes": [ { "customAttributeId": "attr_closed_1", "name": "Preferred Language", "closedCustomAttributeIds": [ { "id": "opt_1", "content": "ENGLISH" } ] }, { "customAttributeId": "attr_closed_2", "name": "Software Tools", "closedCustomAttributeIds": [ { "id": "opt_2", "content": "Go" }, { "id": "opt_3", "content": "Postgres" } ] } ], "crmContactId": "crm_456", "crmLastSyncedAt": "2026-01-10T09:00:00.000Z", "createdAt": "2026-01-01T00:00:00.000Z", "updatedAt": "2026-01-15T10:30:00.000Z" } } ``` ```json Bridge-native (no CRM) { "eventId": "evt_contact_002", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:32:00.000Z", "payload": { "id": "contact_456", "firstName": "Jane", "lastName": "Smith", "email": "jane@example.com", "cellphone": "+1987654321", "languageCode": "EN", "openAttributes": [ { "customAttributeId": "attr_open_2", "name": "Education level", "content": "Secondary" } ], "closedAttributes": [ { "customAttributeId": "attr_closed_1", "name": "Preferred Language", "closedCustomAttributeIds": [ { "id": "opt_1", "content": "ENGLISH" } ] }, { "customAttributeId": "attr_closed_3", "name": "Gender", "closedCustomAttributeIds": [ { "id": "opt_4", "content": "FEMALE" } ] } ], "internalUserOwnerId": "user_789", "createdAt": "2026-01-05T15:47:49.000Z", "updatedAt": "2026-01-15T10:32:00.000Z" } } ``` --- ## Notificaciones de llamadas v1 Se activan cuando una llamada avanza por su ciclo de vida. Bridge emite como máximo un webhook por fase y llamada. Tu integración recibe una secuencia clara de cuatro fases —creada, sonando, iniciada y finalizada— en lugar de cada transición intermedia que Bridge registra internamente. La fase actual se puede deducir del estado de la llamada y de los estados de sus participantes: | Fase | Cómo detectarla | | --- | --- | | created | El estado es CREATED y ningún participante se ha unido ni está sonando | | ringing | Un participante tiene estado RINGING y nadie se ha unido todavía | | started | El estado es STARTED y dos participantes están JOINED | | finished | El estado es FINISHED | Las llamadas perdidas, en las que nadie responde, omiten la fase started: la integración recibe únicamente created, ringing y finished. Cuando termina la llamada, Bridge procesa la grabación mediante un flujo asíncrono de transcripción con IA. Cuando está lista, la integración recibe un evento adicional `call.transcription.created` con la transcripción completa dividida en segmentos por hablante y con marcas de tiempo. Este evento llega **después** de `call.updated (finished)`, normalmente entre varios segundos y unos minutos más tarde según la duración de la llamada. La diarización —identificación de distintos hablantes— depende de la calidad del audio de origen: una grabación mono puede producir una sola etiqueta de hablante para toda la transcripción. ### Tipos de eventos | Tipo de evento | Descripción | | --- | --- | | `call.created` | Se aprovisionó una llamada | | `call.updated` | Cambió una fase del ciclo de vida de la llamada: sonando, iniciada o finalizada | | `call.transcription.created` | Está lista la transcripción de IA de una llamada finalizada | ### Ejemplos de cuerpos ```json Created { "eventId": "evt_call_001", "eventType": "call.created", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:05.815Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "CREATED", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:05.815Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "INITIALIZED" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "INITIALIZED" } ] } } } ``` ```json Ringing { "eventId": "evt_call_002", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:06.243Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "CREATED", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:06.243Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "INITIALIZED" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "RINGING" } ] } } } ``` ```json Started { "eventId": "evt_call_003", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:12.771Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "STARTED", "startedAt": "2026-05-04T00:48:12.125Z", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:12.771Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "JOINED", "joinedAt": "2026-05-04T00:48:12.125Z" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "JOINED", "joinedAt": "2026-05-04T00:48:12.124Z" } ] } } } ``` ```json Finished { "eventId": "evt_call_004", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:20.113Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "FINISHED", "startedAt": "2026-05-04T00:48:12.125Z", "finishedAt": "2026-05-04T00:48:19.389Z", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:20.113Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "LEFT", "joinedAt": "2026-05-04T00:48:12.125Z", "leftAt": "2026-05-04T00:48:19.388Z" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "LEFT", "joinedAt": "2026-05-04T00:48:12.124Z", "leftAt": "2026-05-04T00:48:19.387Z" } ] } } } ``` ```json Transcription created { "eventId": "evt_call_005", "eventType": "call.transcription.created", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:50:14.231Z", "payload": { "callId": "call_abc123", "transcriptionId": "txn_xyz789", "conversationId": "conv_xyz", "duration": "27", "startedAt": "2026-05-04T00:48:12.125Z", "finishedAt": "2026-05-04T00:48:19.389Z", "transcript": [ { "speaker": "0", "text": "Hi, how can I help you today?", "start": 1.44, "end": 5.2 }, { "speaker": "1", "text": "I have a question about your product.", "start": 5.5, "end": 12.3 } ] } } ``` Cada segmento de transcripción incluye la etiqueta de hablante `speaker`, normalmente `"0"`, `"1"`, etc., el `text` y los desplazamientos `start`/`end` en segundos desde el inicio de la llamada. --- ## Notificaciones de reuniones v1 Se activan cuando una reunión alcanza el estado CREATED. Las cancelaciones se comunican mediante la notificación de correo correspondiente. ### Tipos de eventos | Tipo de evento | Descripción | | --- | --- | | `meeting.updated` | Una reunión alcanzó el estado `CREATED` | ### Ejemplo de cuerpo ```json { "eventId": "evt_meeting_001", "eventType": "meeting.updated", "entity": "meeting", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:46:40.954Z", "payload": { "meetingId": "meeting_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "subject": "Meeting with John Smith", "providerType": "TEAMS", "status": "CREATED", "organizerInternalUserId": "user_internal_1", "internalParticipants": ["user_internal_1"], "externalParticipants": ["user_external_1"], "startDateTime": "2026-05-04T01:00:00.000Z", "endDateTime": "2026-05-04T01:15:00.000Z", "createdAt": "2026-05-04T00:46:29.944Z", "updatedAt": "2026-05-04T00:46:40.954Z", "provider": { "joinUrl": "https://teams.microsoft.com/l/meetup-join/...", "calendarEventId": "AAMkADhlMWVlMWJhLWUyZTMtNDllOC...", "chatId": "MWM1Zjg4MmUtZjk0Mi00YjJkLTgyNTItNmRiODNiZmM1NWEw", "providerMeetingId": "MSowODJkZmFjYy1iNDZmLTRiNDItOGYzOS0xMzI0NDcyMzUwMWUq..." } } } ``` --- ## Notificaciones de correo electrónico v1 Se activan cuando se ha procesado un correo y está disponible su resumen de IA. El campo `sentFromBridge` indica la dirección: true para correos salientes enviados desde el espacio de trabajo y false para correos entrantes recibidos. ### Tipos de eventos | Tipo de evento | Descripción | | --- | --- | | `email.updated` | Un correo alcanzó el estado con resumen disponible | ### Ejemplo de cuerpo ```json { "eventId": "evt_email_001", "eventType": "email.updated", "entity": "email", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:45:31.261Z", "payload": { "emailId": "email_abc123", "conversationId": "conv_xyz", "threadId": "AAQkADhlMWVlMWJhLWUyZTMtNDllOC05MDg2LWMzNjFkMTI5MjM4MA...", "providerType": "OUTLOOK", "status": "PROCESSED", "subject": "Project update", "sender": "jane@example.com", "recipients": [ { "recipientEmail": "john@example.com" } ], "summary": "Jane confirms the project is on track and shares next steps.", "importance": "NORMAL", "sentFromBridge": true, "hasAttachments": false, "sentAt": "2026-05-04T00:45:09.000Z", "createdAt": "2026-05-04T00:45:09.000Z", "updatedAt": "2026-05-04T00:45:31.261Z" } } ``` --- ## Notas - Bridge puede agregar nuevas categorías de eventos en el futuro. - Revisa siempre el campo de tipo de evento para determinar qué manejador ejecutar. - Configura y admite la versión seleccionada para cada suscripción. El sobre común no declara un campo `version` universal: no lo exijas ni lo inventes. Consulta [Recepción de eventos](https://docs.bridge.new/es/webhooks/receive-events.md) para los duplicados y el orden. --- ## Temas relacionados - [Descripción general](https://docs.bridge.new/es/webhooks.md) - [Verificar firmas](https://docs.bridge.new/es/webhooks/verifying-signatures.md) - [Configuración en la consola](https://docs.bridge.new/es/webhooks/configuration.md) --- # Custom Connections Source: https://docs.bridge.new/es/lead-capture/index Usa Custom Connections para registrar leads desde tu landing page y encolar un mensaje inicial de WhatsApp. ## Qué hace esta integración Tu landing page envía un lead a Bridge. Luego Bridge abre la conversación de WhatsApp por ti con una plantilla aprobada. Tú no envías ese mensaje: lo enviamos nosotros. **Advertencia** **Una respuesta `202` significa que el lead fue aceptado, no que se haya enviado un mensaje.** Otro servicio transmite el primer mensaje de WhatsApp después. El texto de confirmación de tu página debe decir algo como «te escribiremos pronto», nunca «ya te enviamos un mensaje». ## Qué necesitas y de dónde lo obtienes Cuatro valores: la URL del endpoint, tu `captureKey`, la clave de sitio de reCAPTCHA y el nombre de la acción de reCAPTCHA. No debes armarlos manualmente. En la consola de administración de Bridge, en **LeadScout → Capture snippet**, un administrador de tu espacio de trabajo genera un ejemplo de integración que ya contiene esos cuatro valores. Luego se lo entrega a quien construye la página; esa persona no necesita acceso a la consola. **Nota** El ejemplo es un punto de partida, no un script listo para usar sin ajustes. Tú defines el marcado del formulario y el texto del consentimiento; consulta los [requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md). ## Continúa con estas guías ### [Requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md) Qué debe decir la autorización y qué estás declarando al enviarla. ### [Requisitos de plantillas](https://docs.bridge.new/es/lead-capture/templates.md) Elige una plantilla Utility o Marketing admitida y conoce los requisitos de su categoría. ### [Guía de integración](https://docs.bridge.new/es/lead-capture/integration.md) Agrega la integración al formulario y maneja CAPTCHA, consentimiento, respuestas y errores. ### [Referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md) Todas las respuestas que puede devolver el endpoint y cuáles puedes corregir. --- # Requisitos de consentimiento Source: https://docs.bridge.new/es/lead-capture/consent Qué debe decir la autorización y qué declaras cuando envías consent.status GRANTED. ## Qué debe incluir tu formulario Tu landing page debe pedir una autorización explícita antes de enviar un lead. Tú redactas el texto, pero debe cumplir dos requisitos de Meta: - **Nombrar tu negocio.** No basta con «nosotros» o «nuestros aliados»: debe identificar al negocio que le escribirá a la persona. - **Indicar que la persona recibirá comunicaciones de ese negocio por WhatsApp.** No basta con «podemos contactarte»: debes nombrar el canal. Meta reconoce los formularios de sitios web como un medio válido para obtener esta autorización. Por eso, una casilla en tu landing page es suficiente, siempre que su texto incluya ambos puntos. **Advertencia** Una casilla marcada de antemano no es una autorización. Tampoco lo es una línea en letra pequeña debajo del botón de envío con la que la persona nunca interactúa. La persona debe realizar la acción. ## Qué estás declarando **Nota** Enviar `consent.status: "GRANTED"` es una declaración que haces **tú**. No verificamos ni podemos verificar que la persona haya marcado una casilla: registramos que nos dijiste que lo hizo y cuándo. Si alguna vez se restringen tus envíos de WhatsApp, ese registro se presenta en tu nombre. Por eso `capturedAt` importa más de lo que parece. Debe corresponder al momento en que la persona realmente dio su consentimiento, no al momento en que tu servidor terminó enviando la solicitud ni a una marca de tiempo generada en un proceso nocturno por lotes. Si alguna vez hay que justificar ambos momentos, la diferencia entre ellos será uno de los primeros aspectos que se revisen. Envíalo como una marca de tiempo ISO 8601: ```json { "consent": { "status": "GRANTED", "capturedAt": "2026-08-26T14:32:07.184Z" } } ``` Si no hubo consentimiento, no envíes el lead. Toda solicitud con un estado distinto de `GRANTED` se rechaza con `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED`. ## Un ejemplo para adaptar Este texto es ilustrativo, no una fórmula para copiar sin revisar. Solo tú sabes qué enviarás y con qué finalidad; la autorización debe reflejarlo. > ☐ Acepto recibir mensajes de WhatsApp de **Acme Motors** sobre la cotización que acabo de solicitar. El ejemplo funciona porque nombra al negocio, identifica el canal y explica de qué tratarán los mensajes. Dejaría de cumplir esas condiciones si quitaras el nombre del negocio, dijeras «mensajes» sin especificar WhatsApp o combinaras esta autorización con una casilla general de términos y condiciones que también abarque asuntos no relacionados. --- # Requisitos de plantillas Source: https://docs.bridge.new/es/lead-capture/templates Categorías de plantillas admitidas y recomendaciones para abrir conversaciones mediante Custom Connections. ## Categorías de plantillas admitidas La plantilla que abre la conversación puede ser de **utilidad** o de **marketing**: - **Plantillas Utility:** son estrictamente transaccionales y responden a lo que la persona acaba de enviar, por ejemplo, confirmando la recepción de una consulta. Acceden a tarifas de conversación de WhatsApp más bajas. - **Plantillas Marketing:** pueden incluir promociones, descuentos, ofertas especiales o mensajes de venta directos. Se facturan con las tarifas estándar de conversaciones de marketing de WhatsApp. **Nota** Las plantillas **Authentication** no se pueden usar con Custom Connections. Se rechaza cualquier plantilla configurada con la categoría `AUTHENTICATION`. Configuras y envías tus plantillas a aprobación directamente en Meta WhatsApp Manager. Deben estar aprobadas antes de pasar a producción. ## Clasificación de Meta y entrega **Advertencia** Meta clasifica las plantillas según su contenido, no solo según la categoría que elijas al enviarlas a aprobación. Si una plantilla enviada como UTILITY contiene texto promocional, Meta puede reclasificarla como MARKETING o rechazarla. Elegir la categoría correcta desde el inicio evita problemas de clasificación inesperados y permite anticipar la entrega y la facturación. ## Ejemplos por categoría **Utility (transaccional):** confirma una consulta sin incluir ofertas promocionales: ```text Hi {{1}}, thanks for your enquiry about the {{2}}. A member of our team will follow up here shortly. ``` **Marketing (promocional):** incluye texto promocional, descuentos u ofertas: ```text Hi {{1}}, thanks for your enquiry about the {{2}}. Book this week and get 15% off — reply YES to claim. ``` ## Recomendaciones prácticas - **Elige Utility** cuando tu objetivo principal sea confirmar rápidamente la solicitud de la persona con un mensaje transaccional. Limítalo a lo que acaba de enviar y evita recursos promocionales para mantener la categoría de utilidad y su menor tarifa. - **Elige Marketing** cuando quieras ofrecer de inmediato descuentos de bienvenida, incentivos promocionales u ofertas del catálogo tras la captura. - **Evita las plantillas Authentication:** están destinadas exclusivamente a contraseñas de un solo uso y códigos de verificación; se rechazan en los envíos a leads de campañas. - Cuando la persona responde, comienza una sesión de conversación normal y las restricciones de categoría de plantilla dejan de aplicarse a los mensajes entrantes o a las respuestas del agente. --- # Guía de integración Source: https://docs.bridge.new/es/lead-capture/integration Conecta un formulario de landing page con Bridge: ejemplo, CAPTCHA, consentimiento, respuestas y manejo de errores. ## El ejemplo La consola de administración de Bridge proporciona un ejemplo generado con la configuración de tu espacio de trabajo. El ejemplo ampliado de abajo agrega validación y mensajes sobre el estado del envío. Antes de ejecutarlo, reemplaza los valores de ejemplo con los de la configuración generada para ti. Reemplaza el marcado del formulario y el texto del consentimiento con los tuyos. **Acme Motors es un negocio ficticio usado en este ejemplo.** Sustitúyelo por el negocio que le escribirá a la persona y describe los mensajes de WhatsApp que acepta recibir. Consulta los [requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md). El script muestra validación, estado del envío y manejo de errores. Conserva los campos de solicitud y la acción de reCAPTCHA de tu configuración generada. ```html

``` ## Qué hace el ejemplo - Comprueba los campos obligatorios antes de obtener un token de CAPTCHA. - Registra `consent.capturedAt` cuando la persona marca la casilla. Si el navegador restaura una casilla marcada anteriormente, pide una nueva acción de consentimiento. - Permite un solo envío a la vez y mantiene el botón deshabilitado después de la aceptación para evitar otro envío desde esa instancia del formulario. - Presenta un `202` como aceptación y puesta en cola, y muestra el `requestId` devuelto como referencia para soporte. Nunca afirma que se haya entregado un mensaje de WhatsApp. - Muestra los fallos de CAPTCHA que permiten un nuevo intento y genera un token nuevo en cada intento manual. No reintenta automáticamente un POST. - Trata un fallo de red posterior al envío como un resultado incierto: no afirma que el lead se haya rechazado ni que sea seguro reenviarlo. Son mensajes del lado del cliente, no una garantía de deduplicación del backend. Adapta los mensajes visibles a tu página y conserva la [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md) para el diagnóstico. ## Tu clave de captura no es una clave de API **Nota** La guía de [autenticación](https://docs.bridge.new/es/credentials.md) indica que nunca debes colocar una clave en código frontend. Esa regla se refiere a la clave de la API de integraciones y sigue vigente. Tu `captureKey` es otro tipo de valor. A diferencia de la `x-api-key` de la API de integraciones, tu `captureKey` está diseñada para aparecer en el HTML de tu página, donde cualquiera puede leerla. No permite leer ningún dato: solo identifica a qué espacio de trabajo pertenece un envío. El abuso se limita mediante otras dos comprobaciones: el token de reCAPTCHA y la aceptación de envíos únicamente desde los dominios registrados para tu espacio de trabajo. Nunca uses aquí tu clave de la API de integraciones ni la coloques en una página. ## Incluye el ID del espacio de trabajo en la URL El ID del espacio de trabajo debe ir en el cuerpo de la solicitud **y** en la URL como `?workspaceId=...`. Debe estar en ambos lugares: antes de la solicitud real, el navegador envía una solicitud de comprobación CORS sin cuerpo. Sin el ID en la URL no podemos identificar el espacio de trabajo ni devolver el encabezado que autoriza tu dominio, por lo que el navegador bloquea la solicitud antes de enviarla. Este fallo puede confundir: verás un error de CORS en la consola del navegador, pero no habrá una solicitud en nuestros registros porque la solicitud real nunca salió de la página. Por eso conviene configurarlo bien desde el inicio. ## Genera el token de CAPTCHA al enviar el formulario Un token de reCAPTCHA v3 dura aproximadamente dos minutos. Si lo generas al cargar la página, puede haber vencido cuando la persona termina de completar el formulario. Se rechazará con un `403`, que puede parecer un problema de permisos en lugar de uno de vigencia. ## Genera un token nuevo para cada intento Un token se verifica exactamente una vez. Si falla el envío y reintentas con el mismo token, su reutilización no se puede distinguir de un ataque y devuelve el mismo error que recibiría un bot. Vuelve a llamar siempre a `grecaptcha.execute` antes de reintentar. ## Qué debes enviar La [referencia del endpoint](https://docs.bridge.new/es/api-reference/campaign-leads/registrar-un-lead-de-campa%C3%B1a.md) contiene el contrato completo. Estos son los campos cuyo significado no resulta evidente solo con el esquema: ### `brandId` (`string`) La marca que vende tu landing page, no el ID de una línea, canal o teléfono. Solo es obligatorio si tu espacio de trabajo tiene marcas habilitadas. **Nunca se exige el ID de una línea.** ### `landingUri` (`string`) El origen y la ruta de la página, sin la cadena de consulta. Los parámetros UTM se envían por separado en `utm`; una cadena de consulta sin filtrar puede contener identificadores de clic o tokens de sesión que no deben almacenarse. Envía `https://example.com/offer`, no `https://example.com/offer?gclid=...`. ### `consent` (`object`) Tu declaración de que la persona aceptó y de cuándo lo hizo. Consulta los [requisitos de consentimiento](https://docs.bridge.new/es/lead-capture/consent.md): el texto de autorización del formulario no es opcional. ### `utm` (`object`) Se recopilan de la cadena de consulta mediante una lista de permitidos: los parámetros `utm_*` y cualquier nombre adicional que configures en la consola. Se usa una lista de permitidos, no una lista de exclusiones, porque recopilar datos de más no es reversible. ## Después del envío Un `202` significa que el lead fue aceptado y puesto en cola. **No** significa que se haya enviado un mensaje: eso ocurre después, en otro servicio. Indícale a la persona que le escribirás pronto. Cualquier otra respuesta es un error. Consulta la [referencia de errores](https://docs.bridge.new/es/lead-capture/errors.md) para saber qué significa cada uno y si puedes corregirlo. --- # Referencia de errores Source: https://docs.bridge.new/es/lead-capture/errors Todas las respuestas que puede devolver el endpoint de Custom Connections y cuáles puedes corregir. Las respuestas de error usan el formato de detalles de problemas de [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457): `type`, `title`, `status` y, en algunos casos, `detail`. **Nota** **Las respuestas de error no incluyen un identificador de solicitud.** Solo lo incluye una respuesta `202` exitosa. Si necesitas ayuda de soporte, informa la URL de la página y la hora aproximada. ## Todas las respuestas | Estado | `type` | Qué ocurrió | ¿Puedes corregirlo? | | --- | --- | --- | --- | | `400` | `invalid_payload` | Falta un campo o su formato es incorrecto. | Sí | | `400` | `BRIDGE.CAMPAIGN_LEADS.INVALID_PHONE` | El teléfono no se pudo interpretar como un número válido. | Sí: valídalo antes de enviar | | `400` | `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED` | `consent.status` no era `GRANTED`. | Sí | | `400` | `BRIDGE.CAMPAIGN_LEADS.BRAND_OR_LINE_REQUIRED` | El espacio de trabajo tiene marcas habilitadas y no se envió `brandId`. | Sí | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_DISABLED` | Custom Connections no está habilitado para este espacio de trabajo. | No: contacta a Bridge | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_KEY_MISMATCH` | No se envió la clave de captura o es incorrecta. | Sí | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_REJECTED` | El token de CAPTCHA no se envió, venció, ya se usó o recibió una puntuación demasiado baja. | A veces: consulta la explicación siguiente | | `403` | `BRIDGE.CAMPAIGN_LEADS.ORIGIN_NOT_ALLOWED` | El dominio de la página no está registrado para este espacio de trabajo. | No: contacta a Bridge | | `422` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_PROVIDER_UNAVAILABLE` | No pudimos comunicarnos con el proveedor de CAPTCHA. | Es seguro reintentar | | `500` | `unexpected_error` | Ocurrió un fallo de nuestro lado. | No | Solo se informa el primer fallo. Las comprobaciones se ejecutan en este orden: espacio de trabajo y clave de captura, teléfono, consentimiento, marca, CAPTCHA y, por último, dominio. Corregir un error puede dejar al descubierto el siguiente. ## Sobre el rechazo de CAPTCHA `CAPTCHA_REJECTED` cubre cuatro situaciones distintas. Revisa cómo maneja los tokens tu integración antes de atribuir el rechazo a la puntuación: - **El token venció.** Se generó demasiado pronto. Un token de reCAPTCHA v3 dura alrededor de dos minutos: genéralo al enviar el formulario, no al cargar la página. - **El token ya se usó.** Un token se verifica una sola vez. Si reintentas una solicitud fallida sin generar un token nuevo, se rechaza su reutilización. - **No se envió ningún token.** Asegúrate de que el cliente obtenga un token y lo incluya en `recaptchaToken` en cada envío. - **La puntuación fue demasiado baja.** La comprobación contra bots rechazó este intento. No la omitas. Las cuatro situaciones devuelven el mismo código, por lo que la respuesta por sí sola no identifica la causa. Primero comprueba que se incluya un token, que se genere al enviar el formulario y que sea nuevo para cada intento. ## Sobre el 422 Es un fallo transitorio de nuestro lado: no pudimos comunicarnos con el proveedor de CAPTCHA y, por tanto, no pudimos determinar si el envío era legítimo. **Es seguro reintentar.** El lead se conserva cuando esto ocurre y el reintento no puede generar un mensaje duplicado. Genera un token de CAPTCHA nuevo para ese reintento, como en cualquier otro intento. ## Sobre el error de dominio El orden de estas comprobaciones puede resultar poco intuitivo, por eso conviene explicarlo. Comprobamos que el dominio de tu página esté registrado para tu espacio de trabajo, pero el dominio evaluado es el que **informa el proveedor de CAPTCHA**, no el que aparece en los encabezados de la solicitud. Esta comprobación ocurre *después* de verificar el token. En consecuencia, una página alojada en un dominio no registrado falla en la etapa de CAPTCHA con `ORIGIN_NOT_ALLOWED`, no con un error de CORS. Si esto ocurre y el resto de tu integración funciona, falta registrar el dominio en la configuración del espacio de trabajo: contacta a Bridge para agregarlo. --- # Comprobar estado Source: https://docs.bridge.new/es/api-reference/health/comprobar-estado **Referencia de la operación:** `get /bridge/api/health` **operationId:** `health_bridge_api_health_get` Endpoint de comprobación de estado para verificar que la API esté en funcionamiento. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Obtener conversación por id Source: https://docs.bridge.new/es/api-reference/conversations-api/obtener-conversaci%C3%B3n-por-id **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}` **operationId:** `get_conversation_by_id_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__get` Obtiene una conversación específica por su identificador único dentro del workspace. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Actualizar conversación Source: https://docs.bridge.new/es/api-reference/conversations-api/actualizar-conversaci%C3%B3n **Referencia de la operación:** `patch /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}` **operationId:** `update_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__patch` Actualiza los detalles de la conversación, incluidos los participantes, el estado y el nombre. Admite actualizaciones parciales: incluye solo los campos que quieras cambiar. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Consultar conversaciones con filtros flexibles Source: https://docs.bridge.new/es/api-reference/conversations-api/consultar-conversaciones-con-filtros-flexibles **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations` **operationId:** `get_conversations_bridge_api_v1_workspaces__workspaceId__conversations_get` Consulta conversaciones con opciones de filtrado flexibles. Permite buscar por identificadores de usuarios externos (ID, correo electrónico o teléfono) o por participantes internos, con paginación y filtrado por estado. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Crear conversación con identificación flexible de usuarios Source: https://docs.bridge.new/es/api-reference/conversations-api/crear-conversaci%C3%B3n-con-identificaci%C3%B3n-flexible-de-usuarios **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations` **operationId:** `create_conversation_bridge_api_v1_workspaces__workspaceId__conversations_post` Crea una conversación con identificación flexible de usuarios. Los usuarios externos pueden identificarse por ID, correo electrónico o teléfono. Los usuarios internos solo se asignan cuando se indican explícitamente; de lo contrario, las conversaciones se asignan por turnos mediante un equipo o quedan abiertas para cualquier usuario interno disponible. Cuando no hay una línea libre y los Contacts tienen una conversación liberada con exactamente los participantes solicitados, se recupera y devuelve esa conversación, conservando su `id` e historial. No se le aplican el `name` ni el `status` de la solicitud. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Liberar conversación Source: https://docs.bridge.new/es/api-reference/conversations-api/liberar-conversaci%C3%B3n **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}/release` **operationId:** `release_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__release_post` Libera una conversación: la marca como liberada, elimina los participantes externos y la mueve a la sección RELEASED. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Crear mensaje Source: https://docs.bridge.new/es/api-reference/messages-api/crear-mensaje **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/messages` **operationId:** `create_message_bridge_api_v1_workspaces__workspaceId__messages_post` Crea un mensaje en una conversación específica. Para un mensaje de texto o un adjunto cargado, incluye todos los campos obligatorios: `conversationId`, `messageBody` y `enableExternalBroadcast`. Adjunta los archivos cargados mediante los identificadores recibidos en `mediaIds`; consulta [Enviar un adjunto](https://docs.bridge.new/es/guides/send-attachments.md). Una respuesta satisfactoria devuelve `messageId`; no contiene un comprobante de entrega del proveedor. Consulta [Respuestas y reintentos](https://docs.bridge.new/es/guides/responses.md). [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Obtener contacto por un identificador Source: https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-un-identificador **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/lookup` **operationId:** `retrieve_contact_by_identifier_bridge_api_v1_workspaces__workspaceId__contacts_lookup_get` Obtiene un contacto específico por cualquiera de sus identificadores dentro del workspace. `type=ID` devuelve el mismo contacto que GET /contacts/{contactId}, la URL canónica de un contacto y la opción preferida cuando ya tienes su ID. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Obtener contacto por id Source: https://docs.bridge.new/es/api-reference/contacts-api/obtener-contacto-por-id **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}` **operationId:** `retrieve_contact_by_id_bridge_api_v1_workspaces__workspaceId__contacts__contactId__get` Obtiene un contacto específico por su identificador único dentro del workspace. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Actualizar contacto Source: https://docs.bridge.new/es/api-reference/contacts-api/actualizar-contacto **Referencia de la operación:** `patch /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}` **operationId:** `update_contact_bridge_api_v1_workspaces__workspaceId__contacts__contactId__patch` Actualiza un contacto en el workspace indicado. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Listar contactos Source: https://docs.bridge.new/es/api-reference/contacts-api/listar-contactos **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts` **operationId:** `get_contacts_bridge_api_v1_workspaces__workspaceId__contacts_get` Consulta una lista paginada de contactos del workspace. Se ordena por fecha de creación. Los filtros `ownerEmail` y `search` están obsoletos y se eliminarán; para encontrar un contacto por un identificador, usa /contacts/lookup. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Crear contacto Source: https://docs.bridge.new/es/api-reference/contacts-api/crear-contacto **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts` **operationId:** `create_contact_bridge_api_v1_workspaces__workspaceId__contacts_post` Crea un contacto en el workspace indicado. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Crear o actualizar contacto Source: https://docs.bridge.new/es/api-reference/contacts-api/crear-o-actualizar-contacto **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts/partial` **operationId:** `create_partial_contact_bridge_api_v1_workspaces__workspaceId__contacts_partial_post` Crea o actualiza un contacto usando solo el celular. Lo clasifica como NORMAL o PARTIAL. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Crear cargas prefirmadas de archivos Source: https://docs.bridge.new/es/api-reference/files-api/crear-cargas-prefirmadas-de-archivos **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/files` **operationId:** `create_preloaded_files_bridge_api_v1_workspaces__workspaceId__files_post` Carga un archivo adjunto, como un PDF, una imagen o un documento, antes de crear un mensaje. Esta operación devuelve los datos de un PUT prefirmado; los bytes del archivo se cargan por separado. Cuando la carga termine correctamente, utiliza el `mediaId` devuelto en la operación de envío. Sigue [Enviar un archivo adjunto](https://docs.bridge.new/es/guides/send-attachments.md) para los pasos de suma de comprobación, carga y mensaje. Genera URL prefirmadas para cargar archivos (Presigned PUT). Valida la extensión, contentType y los límites por tipo. La suma de comprobación es obligatoria: envía el resumen SHA-256 en checksumBase64 (Base64). La carga debe incluir la cabecera x-amz-checksum-sha256 con el mismo valor. --- Para cargar los archivos, DEBES utilizar la URL prefirmada devuelta con el método HTTP PUT. Carga el archivo exactamente en la URL indicada, sin modificaciones, tal como exige AWS S3 para un PUT con URL prefirmada. Consulta la documentación oficial de AWS S3: [Documentación de AWS S3 sobre Presigned PUT](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html). Incluye todas las cabeceras obligatorias indicadas en la respuesta, por ejemplo, 'x-amz-checksum-sha256' con el valor SHA-256 correcto. AWS rechazará la carga si no utilizas el método HTTP o las cabeceras correctos.
TipoExtensiónTipo de contenidoTamaño máximo
Imagen.jpegimage/jpeg16 MB
.jpgimage/jpeg
.pngimage/png
.webpimage/webp
GIF.gifimage/gif3 MB
.mp4video/mp4
Vídeo.avivideo/x-msvideo64 MB
.movvideo/quicktime
.mp4video/mp4
Audio.m4aaudio/mp416 MB
.mp3audio/mpeg
.oggaudio/ogg
.wavaudio/wav
Documento.docapplication/msword100 MB
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.pdfapplication/pdf
.pptapplication/vnd.ms-powerpoint
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.txttext/plain
.xlsapplication/vnd.ms-excel
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
[Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Consultar atributos personalizados por workspaceid Source: https://docs.bridge.new/es/api-reference/custom-attributes-api/consultar-atributos-personalizados-por-workspaceid **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/settings/attributes` **operationId:** `get_custom_attributes_by_workspace_bridge_api_v1_workspaces__workspaceId__settings_attributes_get` Devuelve los atributos personalizados del workspace indicado. De forma predeterminada, solo devuelve atributos **activos** (sin un `deletedAt` en el pasado). **Filtros:** - `category`: filtra por `OPEN` o `CLOSED`. Omítelo para devolver todas las categorías. - `includeArchived`: usa `true` para incluir atributos archivados (con `deletedAt` en el pasado). Predeterminado: `false`. - `isRequired`: usa `true` para devolver solo atributos obligatorios y `false` para devolver solo opcionales. Omítelo para devolver todos. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Obtener canales de proveedores por workspace Source: https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-de-proveedores-por-workspace **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels` **operationId:** `get_provider_channels_by_workspace_id_bridge_api_v1_workspaces__workspaceId__provider_channels_get` Obtiene los canales de proveedores por identificador de workspace. Esta respuesta expone `provider` e `identifier`, similar a un número telefónico, para cada canal; no devuelve `providerChannelId`. Para las líneas de un Agent, lee `agents[].lines[].providerChannelId` en la lista de Agents. No sustituyas un ID de canal por un número telefónico. Consulta [Conceptos e identificadores](https://docs.bridge.new/es/guides/identifiers.md). [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Obtener canales por workspace y tipo de proveedor Source: https://docs.bridge.new/es/api-reference/provider-channels-api/obtener-canales-por-workspace-y-tipo-de-proveedor **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels/{messageProviderType}` **operationId:** `get_provider_channels_by_workspace_id_and_provider_type_bridge_api_v1_workspaces__workspaceId__provider_channels__messageProviderType__get` Obtiene los canales de proveedores por identificador de workspace y tipo de proveedor. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Iniciar conversación saliente de leadscout con un lead conocido Source: https://docs.bridge.new/es/api-reference/leadscout-api/iniciar-conversaci%C3%B3n-saliente-de-leadscout-con-un-lead-conocido **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound` **operationId:** `initiate_leadscout_outbound_bridge_api_v1_workspaces__workspaceId__leadscout_outbound_post` Inicia una conversación saliente de LeadScout con un Contact conocido. El Contact debe existir previamente. Bridge selecciona un Agent de prospección para una línea de WhatsApp apta. La plantilla se referencia mediante template.id o template.name; id tiene prioridad si se proporcionan ambos. Debe existir y estar APPROVED, y cualquier Bridge User de handoffOverride debe ser válido. Se respeta un contact.providerChannelId explícito. Sin él, la selección automática prefiere una línea libre, después una conversación liberada recuperable con este Contact y, por último, una conversación activa ocupada solo cuando forceSend=true. La disponibilidad se evalúa por Contact en cada línea, no por la ocupación global de la línea. forceSend=true reutiliza una conversación activa apta; no la ignora ni crea una nueva. Una reutilización exitosa devuelve alreadyInitiated=true y persiste la nueva plantilla y los seguimientos. Una conversación liberada recuperable se puede recuperar con cualquiera de los dos valores, conserva su ID y devuelve recovered=true. Esta opción no habilita las conversaciones bloqueadas ni las liberadas no recuperables. La ruta heredada puede reutilizar una conversación controlada por un humano u otro Agent; a diferencia del envío saliente de Agents, no exige la comprobación de control por el Agent solicitado. Una sesión abierta de LeadScout que no haya vencido sigue bloqueando una nueva solicitud saliente con 409 BRIDGE_AI_LEADSCOUT_0017; si no se puede finalizar una sesión vencida, devuelve 409 BRIDGE_AI_LEADSCOUT_0018. Las demás validaciones siguen vigentes. Los mensajes adicionales se persisten; persistirlos no demuestra su entrega ni que se espere la respuesta del lead. Una solicitud fallida puede dejar trabajo parcial, por lo que no debes tratar forceSend como idempotencia ni reintentar a ciegas un resultado incierto. Consulta [la guía completa de envío saliente](https://docs.bridge.new/es/guides/agent-outbound.md) para la matriz false/true, los indicadores de respuesta, las diferencias con el envío saliente de Agents, los errores y la transferencia. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Solicitar transferencia manual de leadscout a usuarios internos Source: https://docs.bridge.new/es/api-reference/leadscout-api/solicitar-transferencia-manual-de-leadscout-a-usuarios-internos **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/conversations/{conversationId}/handoff` **operationId:** `request_leadscout_handoff_bridge_api_v1_workspaces__workspaceId__leadscout_conversations__conversationId__handoff_post` Solicita la transferencia manual de una conversación controlada por LeadScout a uno o más usuarios internos. La solicitud se confirma con `202 Accepted`; la asignación se procesa de forma asíncrona. La respuesta repite los destinatarios solicitados y un ID de seguimiento para correlación. La resolución de usuarios internos (por ID o EMAIL) ocurre después y no se refleja en esta respuesta. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Descubrir las variables agnósticas de una plantilla Source: https://docs.bridge.new/es/api-reference/templates-api/descubrir-las-variables-agn%C3%B3sticas-de-una-plantilla **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId}` **operationId:** `get_template_discovery_bridge_api_v1_workspaces__workspaceId__templates__templateId__get` Devuelve las variables de una plantilla: `key`/`label`/`callerMustSupply`/`isCustom`/`default`, independientes de la ubicación en Meta. Nunca devuelve la dirección o el índice de una posición de Meta. `templateId` acepta el `id` o el `name` de la plantilla. Las operaciones salientes aceptan `template.id` o `template.name`, con prioridad para un id no vacío. El inicio de conversaciones utiliza `onboardingTemplates[].templateId`. Utiliza el selector que exige la operación de envío. Consulta [la receta de plantillas](https://docs.bridge.new/es/guides/send-template.md). Una variable con `callerMustSupply: true` no tiene una fuente declarada: quien llama debe incluir su `key` en `parameters` al enviar; de lo contrario, el envío falla con un 422 que identifica ese mismo `key`. Una variable con `callerMustSupply: false` la resuelve Bridge por su cuenta, por ejemplo, el nombre del destinatario, o ya tiene un valor que quien llama puede sobrescribir opcionalmente. Una variable con `isCustom: true` es un valor que solo conoce quien llama y tiene un `default`: envíala en `parameters` para usar tu propio valor, u omítela o déjala en blanco para enviar `default`. Códigos de error: - BRIDGE_CORE_0301: el workspace de la ruta no coincide con el workspace de quien llama (403) - BRIDGE_TEMPLATE_0001: no se encontró una PROVIDER_TEMPLATE para este workspace e identificador. Incluye por igual un id/name desconocido, una plantilla de otro workspace y una plantilla que no es PROVIDER_TEMPLATE (404); este endpoint nunca confirma la existencia de una plantilla fuera del workspace de quien llama [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Obtener usuario interno por un identificador Source: https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-un-identificador **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/users/lookup` **operationId:** `retrieve_internal_user_by_identifier_bridge_api_v1_workspaces__workspaceId__users_lookup_get` Obtiene un Bridge User específico por cualquiera de sus identificadores dentro del workspace. `type=ID` devuelve el mismo usuario que GET /users/{userId}, la URL canónica de un usuario interno y la opción preferida cuando ya tienes su ID. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Obtener usuario interno por id Source: https://docs.bridge.new/es/api-reference/internal-users-api/obtener-usuario-interno-por-id **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/users/{userId}` **operationId:** `retrieve_internal_user_by_id_bridge_api_v1_workspaces__workspaceId__users__userId__get` Obtiene un usuario interno específico (agente humano) por su identificador único dentro del workspace. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Listar usuarios internos Source: https://docs.bridge.new/es/api-reference/internal-users-api/listar-usuarios-internos **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/users` **operationId:** `get_internal_users_bridge_api_v1_workspaces__workspaceId__users_get` Consulta una lista paginada de usuarios internos del workspace. Se ordena por fecha de creación. Los filtros `email` y `status` están obsoletos y se eliminarán; para encontrar un usuario interno por un identificador, usa /users/lookup. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Listar los agents de un workspace Source: https://docs.bridge.new/es/api-reference/agents-api/listar-los-agents-de-un-workspace **Referencia de la operación:** `get /bridge/api/v1/workspaces/{workspaceId}/agents` **operationId:** `list_agents_bridge_api_v1_workspaces__workspaceId__agents_get` Lista los Agents del workspace con su estado, disponibilidad y líneas. Incluye todos los Agents, cualquiera que sea su estado; `available` indica si pueden iniciar conversaciones. Una página puede contener menos elementos que `limit`; sigue paginando mientras `cursor` no sea null. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Iniciar conversación saliente con un contact como agent específico Source: https://docs.bridge.new/es/api-reference/agents-api/iniciar-conversaci%C3%B3n-saliente-con-un-contact-como-agent-espec%C3%ADfico **Referencia de la operación:** `post /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound` **operationId:** `start_agent_outbound_bridge_api_v1_workspaces__workspaceId__agents__agentId__outbound_post` Inicia una conversación saliente con un Contact conocido, atendida por el Agent indicado. Funciona con Agents LeadScout y Service. Primero se resuelve el Contact y después el Agent, que debe existir en el workspace y estar disponible (consulta `GET /agents`). La plantilla se referencia mediante `template.id` o `template.name` (id tiene prioridad si se envían ambos), debe existir y estar APPROVED, y cualquier Bridge User de `handoffOverride` debe ser válido. Si `template.media.mediaId` es desconocido, la solicitud falla con 400 `BRIDGE_AI_LEADSCOUT_0016` solo después de crear o recuperar la conversación, por lo que un reintento tras ese error puede responder de otra manera. Las reglas del cuerpo (`consent.status=GRANTED` sin `capturedAt`, o `template.media` sin exactamente uno de `mediaId` o `url`) fallan con 400 `BRIDGE_CORE_0103`. La conversación se abre en una de las líneas activas de WhatsApp del Agent, bajo su control, con la plantilla como primer mensaje. Se elige una línea en este orden: - Una línea libre. - En su defecto, una línea con una conversación liberada recuperable con este Contact. La recuperación devuelve `recovered=true` y reemplaza el contexto saliente anterior y `agentContext`. Esto ocurre incluso con `forceSend=false`. - Si ninguna línea está libre o es recuperable: `forceSend=false` (predeterminado) falla con 409 `BRIDGE_AI_LEADSCOUT_0008`; `forceSend=true` reutiliza una línea ocupada por una conversación activa con este Contact, dando preferencia a una que controle este Agent. Si la conversación elegida está controlada por otro Agent o un Bridge User, la llamada falla con 409 `BRIDGE_AI_AGENT_OUTBOUND_0006` y no se escribe nada. Libérala primero y reintenta después. Nunca se usan líneas cuya conversación esté bloqueada o se haya liberado sin recuperación, por lo que, si ninguna línea está ocupada por una conversación activa, la llamada falla con 409 `BRIDGE_AI_LEADSCOUT_0008` incluso con `forceSend=true`. `contact.providerChannelId` es una preferencia: la línea indicada se usa cuando está libre o es recuperable; de lo contrario, se aplica el mismo orden entre todas las líneas del Agent. Entre las líneas ocupadas, tiene prioridad una que controle este Agent; si no existe, se reutiliza la línea indicada (y puede fallar con 0006). La reutilización de una conversación depende del tipo de Agent: - LeadScout: si su sesión de LeadScout sigue abierta y no ha vencido, la llamada falla con 409 `BRIDGE_AI_LEADSCOUT_0017` (`extra` incluye `conversationId`, `sessionId` y `stage`). Si no se puede finalizar una sesión vencida, falla con 409 `BRIDGE_AI_LEADSCOUT_0018`. - Service Agent: se continúa una sesión de servicio abierta que no haya vencido; una sesión vencida se cierra como abandonada y se abre una nueva. Consulta [la guía completa de envío saliente](https://docs.bridge.new/es/guides/agent-outbound.md) para los requisitos, la tabla de decisión de forceSend, la recuperación, el trabajo parcial y las decisiones de reintento seguro. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Registrar un lead de campaña Source: https://docs.bridge.new/es/api-reference/campaign-leads/registrar-un-lead-de-campa%C3%B1a **Referencia de la operación:** `post /leadscout/campaign-leads` **operationId:** `create_campaign_lead_leadscout_campaign_leads_post` Registra un lead captado por la página de destino de un tenant y pone en cola el primer mensaje saliente de WhatsApp. Un 202 significa que el lead fue aceptado, no que se haya enviado un mensaje. [Contrato OpenAPI exacto](https://docs.bridge.new/es/api-reference/campaign-leads.openapi.yaml) Este corpus contiene guías y descripciones de operaciones. No incluye todos los esquemas de solicitud y respuesta. Lee el contrato OpenAPI enlazado antes de generar una solicitud. --- # Integre seus sistemas ao Bridge Source: https://docs.bridge.new/pt-br/index Conecte seu CRM, automações ou landing page ao Bridge com a API REST, webhooks e Custom Connections. Implemente com sua ferramenta de programação preferida ## Conecte seu assistente de programação com IA Conecte sua ferramenta à documentação atual do Bridge. Escolha abaixo para ver a configuração, um exemplo de prompt e o teste de conexão. [Codex →](https://docs.bridge.new/pt-br/connect-your-agent.md#codex) [Claude Code →](https://docs.bridge.new/pt-br/connect-your-agent.md#claude-code) [Cursor →](https://docs.bridge.new/pt-br/connect-your-agent.md#cursor) [GitHub Copilot →](https://docs.bridge.new/pt-br/connect-your-agent.md#github-copilot) O acesso à documentação não exige chave de API do Bridge. O acesso ao workspace é separado. ## Escolha sua integração ### [API REST](https://docs.bridge.new/pt-br/credentials.md) Crie contatos, conversas e mensagens a partir do seu servidor. **Acesso:** `x-api-key` no servidor. ### [Webhooks](https://docs.bridge.new/pt-br/webhooks.md) Receba eventos do Bridge no seu endpoint HTTPS. **Acesso:** verifique as credenciais do webhook e a validade temporal. ### [Custom Connections](https://docs.bridge.new/pt-br/lead-capture/index.md) Capture leads de uma landing page e coloque a mensagem inicial de WhatsApp na fila de envio. **Acesso:** `captureKey` e reCAPTCHA; sem chave da API REST. ## Faça sua primeira requisição à API REST ### Obtenha suas credenciais de API Siga o guia de [autenticação](https://docs.bridge.new/pt-br/credentials.md) para gerar uma chave de API no console administrativo do Bridge. Se necessário, peça acesso ao administrador do Bridge. Mantenha a chave no servidor. ### Verifique a conexão Use o cabeçalho `x-api-key` para chamar o [health check](https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade.md) autenticado em `https://api-connect-us.bridge.new/bridge/api/health`. Continue na aba **API REST**. Cada endpoint apresenta seus campos, respostas e exemplos. **Nota** Custom Connections usa um endpoint separado e uma `captureKey` pública. Siga o [guia de integração](https://docs.bridge.new/pt-br/lead-capture/integration.md). Uma resposta `202` confirma a aceitação, não a entrega no WhatsApp. ## Implemente com base no contrato publicado - [Crie um Contato e envie uma mensagem](https://docs.bridge.new/pt-br/guides/first-conversation.md) — siga o fluxo completo: Contato → conversa → mensagem. - [Envie um PDF ou anexo](https://docs.bridge.new/pt-br/guides/send-attachments.md) — checksum, URL de upload, envio do arquivo e mensagem. - [Envie um template de WhatsApp](https://docs.bridge.new/pt-br/guides/send-template.md) — descubra as variáveis e forneça os valores exigidos do integrador. - [Inicie uma conversa com um Agente e transfira o atendimento](https://docs.bridge.new/pt-br/guides/agent-outbound.md) — escolha o Agente e entenda `forceSend`, reutilização e recuperação. - [Consulte identificadores](https://docs.bridge.new/pt-br/guides/identifiers.md) e [percorra os resultados paginados](https://docs.bridge.new/pt-br/guides/pagination.md) — use os IDs e cursores corretos. - [Limites de requisições](https://docs.bridge.new/pt-br/rate-limits.md) — compartilhe a cota de requisições e trate respostas `429`. - [Códigos de erro](https://docs.bridge.new/pt-br/error-codes.md) — interprete os erros da API REST. Custom Connections tem uma [referência de erros](https://docs.bridge.new/pt-br/lead-capture/errors.md) separada. - [Parâmetros de templates de WhatsApp](https://docs.bridge.new/pt-br/templates-and-parameters.md) — abra conversas com templates de WhatsApp e forneça suas variáveis. - [Histórico de alterações](https://docs.bridge.new/pt-br/changelog.md) — consulte mudanças que afetam as integrações. Leia sem MCP pelo [índice trilíngue](https://docs.bridge.new/llms.txt), [índice em português](https://docs.bridge.new/llms-pt-br.json), [documentação reunida em português](https://docs.bridge.new/llms-full-pt-br.json) ou [guia para agentes de IA](https://docs.bridge.new/skill.md). Consulte os esquemas exatos no [OpenAPI da API REST de integrações](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) ou no [OpenAPI de Custom Connections](https://docs.bridge.new/pt-br/api-reference/campaign-leads.openapi.yaml). Para ajuda sobre o uso do aplicativo Bridge, visite a [Central de Ajuda](https://help.bridge.new). --- # Conecte seu assistente de programação com IA Source: https://docs.bridge.new/pt-br/connect-your-agent Conecte Codex, Claude Code, Cursor ou GitHub Copilot à documentação atual do Bridge e implemente com base no contrato exato da API. Dê ao seu assistente de programação acesso à documentação atual do Bridge antes de pedir que ele construa a integração. Escolha sua ferramenta abaixo, adicione o endpoint MCP público e faça a verificação de conexão. | Configuração | Valor | | --- | --- | | URL do servidor | `https://docs.bridge.new/mcp` | | Conexão | HTTP remoto / Streamable HTTP | | Nome local sugerido | `bridgeDocs` | | Credenciais do Bridge | Nenhuma para esse servidor de documentação | **Nota** Isso conecta seu assistente à **documentação do Bridge**. Não o conecta ao workspace nem concede permissão para criar Contatos ou enviar mensagens. Sua integração usa as [credenciais separadas da API REST](https://docs.bridge.new/pt-br/credentials.md) ou a configuração pública de [Custom Connections](https://docs.bridge.new/pt-br/lead-capture/index.md). O servidor de documentação também oferece uma ferramenta opcional de feedback, que envia comentários sobre a documentação ao Bridge. ## Escolha seu assistente de programação ### [Codex](https://docs.bridge.new/pt-br/connect-your-agent.md#codex) Configuração da CLI e da extensão local de IDE. ### [Claude Code](https://docs.bridge.new/pt-br/connect-your-agent.md#claude-code) Um comando e, em seguida, a verificação da conexão. ### [Cursor](https://docs.bridge.new/pt-br/connect-your-agent.md#cursor) Adicione o servidor ao arquivo MCP do projeto. ### [GitHub Copilot](https://docs.bridge.new/pt-br/connect-your-agent.md#github-copilot) Configuração guiada no VS Code ou configuração portátil do projeto. ## Codex **Antes de começar:** tenha a CLI do Codex ou a extensão Codex para IDE instalada. Para a CLI, adicione o servidor no terminal: ```bash codex mcp add bridgeDocs --url https://docs.bridge.new/mcp codex mcp list ``` A lista deve incluir `bridgeDocs` com a URL da documentação do Bridge. A presença na lista confirma a configuração; use a [verificação de conexão abaixo](https://docs.bridge.new/pt-br/connect-your-agent.md#check-the-connection) para confirmar que a ferramenta realmente consegue ler a documentação. Se preferir editar a configuração, adicione esta entrada a `~/.codex/config.toml`. Preserve as demais configurações e entradas de servidores: ```toml [mcp_servers.bridgeDocs] url = "https://docs.bridge.new/mcp" ``` Reinicie o cliente ou a extensão após alterar a configuração. Na interface de terminal do Codex, `/mcp` mostra os servidores ativos. Clientes locais do Codex podem compartilhar a configuração no mesmo host; ambientes remotos podem ter configuração e políticas separadas. **Exemplo de prompt:** > Use bridgeDocs para ler o contrato REST do Bridge e o guia da primeira conversa. Prepare uma integração Node.js que crie um Contato, inicie uma conversa e crie uma mensagem. Liste primeiro os identificadores e as configurações necessários. Mantenha todos os campos e tipos da API inalterados, cite as fontes e não faça requisições reais à API. [Guia oficial de MCP do Codex](https://learn.chatgpt.com/docs/extend/mcp?surface=cli). ## Claude Code **Antes de começar:** tenha o Claude Code instalado. Adicione o servidor à configuração pessoal para disponibilizá-lo em todos os projetos: ```bash claude mcp add --transport http bridgeDocs --scope user https://docs.bridge.new/mcp claude mcp list ``` Se preferir uma configuração compartilhada do projeto, use `--scope project` em vez de `--scope user`. Revise a configuração resultante antes de adicioná-la ao repositório. Inicie o Claude Code e use `/mcp` para inspecionar `bridgeDocs`. Depois, faça a [verificação de conexão abaixo](https://docs.bridge.new/pt-br/connect-your-agent.md#check-the-connection). O endpoint de documentação do Bridge não precisa de uma chave de API do Bridge nem de login OAuth. **Exemplo de prompt:** > Use bridgeDocs para ler os guias atuais de verificação e recebimento de webhooks do Bridge. Implemente um receptor Python com a representação HMAC documentada e aceitação persistente antes da confirmação. Adicione testes offline usando o vetor de assinatura publicado. Explique a limitação do timestamp e o tratamento de duplicatas e cite as páginas usadas. [Guia oficial de MCP do Claude Code](https://code.claude.com/docs/en/mcp). ## Cursor **Antes de começar:** abra seu projeto de integração no Cursor. Crie ou atualize `.cursor/mcp.json` nesse projeto. Mescle a entrada com os servidores já existentes: ```json { "mcpServers": { "bridgeDocs": { "url": "https://docs.bridge.new/mcp" } } } ``` Para uma configuração pessoal disponível em vários projetos, use `~/.cursor/mcp.json`. Na barra lateral **Customize** do Cursor, confira se o servidor está habilitado. Abra uma conversa com o Agent e faça a [verificação de conexão abaixo](https://docs.bridge.new/pt-br/connect-your-agent.md#check-the-connection); as ferramentas MCP disponíveis aparecem em **Available Tools**. Revise as solicitações de ferramentas quando o Cursor pedir. **Exemplo de prompt:** > Use bridgeDocs para encontrar o fluxo completo de anexos em PDF. Implemente um upload no servidor que calcule o SHA-256 em Base64 dos bytes exatos do arquivo, solicite um upload pré-assinado, execute o PUT exigido e crie uma mensagem com o mediaId retornado. Preserve os campos documentados e explique o tratamento de falhas de cada etapa. Não envie uma chave de API do Bridge à URL de upload. [Guia oficial de MCP do Cursor](https://cursor.com/docs/mcp). ## GitHub Copilot **Antes de começar:** habilite o GitHub Copilot no VS Code e abra a pasta do projeto. Selecione **Copilot** como destino da sessão. 1. Abra a paleta de comandos com `Command` + `Shift` + `P` no macOS ou `Ctrl` + `Shift` + `P` no Windows/Linux. 2. Execute **MCP: Add Server** e escolha **HTTP (HTTP or Server-Sent Events)**. 3. Informe `https://docs.bridge.new/mcp` e dê ao servidor o nome `bridgeDocs`. 4. Escolha **Global → Copilot Global** para a configuração pessoal, quando disponível. Revise o destino mostrado pela sua versão do VS Code e qualquer solicitação de confiança no servidor. 5. Abra uma conversa do Copilot, habilite as ferramentas de documentação do Bridge para a sessão e faça a [verificação de conexão abaixo](https://docs.bridge.new/pt-br/connect-your-agent.md#check-the-connection). Para um projeto compartilhado usando a configuração portátil atual do Copilot, crie ou mescle esta entrada no arquivo `.mcp.json` na raiz do workspace: ```json { "mcpServers": { "bridgeDocs": { "type": "http", "url": "https://docs.bridge.new/mcp", "tools": ["*"] } } } ``` O formato portátil do Copilot acima é diferente do `.vscode/mcp.json` gerenciado pelo editor, que usa um objeto `servers`. Use o arquivo correspondente à conexão selecionada; não misture os dois formatos. Se o destino portátil não estiver disponível na sua versão, use a configuração guiada e o arquivo escolhido por ela. **Exemplo de prompt:** > Use bridgeDocs para ler o guia de Custom Connections e seu contrato OpenAPI separado. Prepare um formulário de landing page que registre o consentimento, obtenha um novo token de CAPTCHA a cada tentativa e apresente uma resposta 202 como aceita com seu requestId. Mantenha captureKey, os campos da requisição e a ação de CAPTCHA configurada inalterados. Não use uma chave da API REST na página. [Configuração oficial do VS Code](https://code.visualstudio.com/docs/agent-customization/mcp-servers) · [Referência de configuração do Copilot](https://code.visualstudio.com/docs/agents/reference/mcp-configuration). ## Verifique a conexão Depois de configurar qualquer um dos quatro clientes, faça este pedido: > Use o servidor MCP de documentação do Bridge para pesquisar a criação de uma mensagem. Leia o esquema MessageRequest no OpenAPI REST publicado. Quais são os três campos obrigatórios? Uma resposta 201 bem-sucedida comprova a entrega pelo WhatsApp? Cite a fonte exata do Bridge que você leu. Não chame a API de negócio. Uma verificação bem-sucedida usa uma ferramenta de documentação e cita uma página ou esquema do Bridge. Ela deve identificar `conversationId`, `messageBody` e `enableExternalBroadcast` como obrigatórios e distinguir uma mensagem criada de um comprovante de entrega do provedor. Uma resposta plausível sem chamada de ferramenta ou fonte não é um teste de conexão. ## Leia a documentação com qualquer IA, sem MCP Não é necessário conectar o MCP para ler a documentação do Bridge. Forneça a um assistente que possa abrir URLs o [índice trilíngue da documentação](https://docs.bridge.new/llms.txt) e escolha as fontes para sua tarefa e idioma: | Idioma | Índice de páginas | Documentação reunida | | --- | --- | --- | | English | [English index](https://docs.bridge.new/llms-en.json) | [English collection](https://docs.bridge.new/llms-full-en.json) | | Español | [Índice en español](https://docs.bridge.new/llms-es.json) | [Documentación en español](https://docs.bridge.new/llms-full-es.json) | | Português do Brasil | [Índice em português](https://docs.bridge.new/llms-pt-br.json) | [Documentação em português](https://docs.bridge.new/llms-full-pt-br.json) | O índice aponta para páginas `.md` individuais e para os arquivos OpenAPI exatos. A [coleção completa](https://docs.bridge.new/llms-full.txt) inclui os três idiomas; a coleção de um único idioma é menor. As descrições de endpoints reunidas não substituem os esquemas completos do OpenAPI. Os arquivos por idioma usam JSON: o índice lista as URLs, e cada coleção contém o texto das páginas em Markdown no campo `contentMarkdown`. Os arquivos gerais `llms.txt` e `llms-full.txt` continuam em Markdown. **Exemplo de prompt:** > Leia https://docs.bridge.new/llms.txt e selecione as fontes em português para enviar um PDF. Leia o guia completo de anexos e o OpenAPI REST vinculado antes de escrever código. Explique a sequência de upload, os campos obrigatórios e as limitações de entrega. Preserve as assinaturas publicadas da API e cite as URLs que você leu. Prepare apenas o código; não faça requisições reais. Se pesquisar pelo MCP, especifique `language: "pt-BR"` para português, `language: "es"` para espanhol ou `language: "en"` para inglês. As páginas públicas usam `.md`; as leituras de páginas no filesystem MCP usam `.mdx`. Consulte também o [guia de capacidades e fontes do Bridge](https://docs.bridge.new/skill.md). ## Implemente com o contrato correto O servidor oferece pesquisa na documentação, leitura completa de páginas e esquemas em um sistema de arquivos virtual de documentação e feedback opcional sobre a documentação. A ferramenta de sistema de arquivos não executa comandos no seu computador. O feedback é separado da pesquisa e da leitura: use-o somente quando quiser enviar um comentário sobre a documentação. Informe ao assistente a tarefa e o fluxo correspondente: - [Primeira conversa](https://docs.bridge.new/pt-br/guides/first-conversation.md): Contato → conversa → mensagem. - [Anexos](https://docs.bridge.new/pt-br/guides/send-attachments.md): bytes do arquivo → checksum → PUT pré-assinado → mensagem. - [Templates](https://docs.bridge.new/pt-br/guides/send-template.md): descubra as variáveis antes de enviar. - [Outbound de Agente](https://docs.bridge.new/pt-br/guides/agent-outbound.md): selecione um Agente e entenda `forceSend`, reutilização e recuperação. - [Receptor de webhook](https://docs.bridge.new/pt-br/webhooks/receive-events.md): verifique, persista, confirme e processe. O [índice da documentação](https://docs.bridge.new/llms.txt) permite localizar páginas. A [documentação reunida](https://docs.bridge.new/llms-full.txt) contém guias e descrições de endpoints, mas não todos os esquemas. Antes de gerar código, leia o Markdown do endpoint ou o [OpenAPI REST](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) ou [OpenAPI de Custom Connections](https://docs.bridge.new/pt-br/api-reference/campaign-leads.openapi.yaml) correspondente. Peça ao assistente para preservar hosts, métodos, caminhos, autenticação, identificadores, nomes de campos, tipos, campos obrigatórios e anuláveis, enums, valores padrão, limites e códigos de resposta. Se fontes publicadas entrarem em conflito, identifique as passagens e confirme o comportamento atual antes de usá-las como base. ## Se o servidor não aparecer | Sintoma | O que verificar | | --- | --- | | Servidor ausente | Confirme o local do arquivo ou o escopo da configuração, o nome do servidor e o cliente ou ambiente usado. Preserve a configuração existente ao adicionar a entrada. | | Configurado, mas sem ferramentas | Reinicie ou recarregue o cliente, habilite o servidor e confira o status MCP ou os logs. Uma organização gerenciada pode restringir servidores personalizados. | | Solicitação de autenticação | O servidor público de documentação do Bridge não precisa de chave de API do Bridge. Confira a URL e a política do cliente ou da organização. Não cole credenciais do workspace no chat. | | Resposta sem citações | Peça explicitamente o uso de `bridgeDocs`, a pesquisa e a leitura do esquema do endpoint. Execute a verificação de conexão novamente. | | MCP temporariamente indisponível | Leia diretamente o [índice](https://docs.bridge.new/llms.txt), o Markdown do endpoint e o OpenAPI. O servidor de documentação não tem um compromisso de disponibilidade separado. | As interfaces dos clientes mudam com o tempo. As opções de configuração podem variar conforme a versão e a política da organização; use a documentação oficial vinculada se os menus forem diferentes. Instruções dos fornecedores verificadas pela última vez em **14 de novembro de 2026**. --- # Autenticação da API REST Source: https://docs.bridge.new/pt-br/credentials Gere e use uma chave de API no servidor para a API REST de integrações, sem confundi-la com as credenciais de webhooks e Custom Connections. ## Visão geral Toda requisição à **API REST de integrações** em `https://api-connect-us.bridge.new` usa uma **chave de API** no cabeçalho `x-api-key`. Essa chave identifica seu aplicativo e autoriza o acesso aos recursos do Bridge em nome da sua organização. | Tipo de integração | Uso das credenciais | | --- | --- | | API REST de integrações | `x-api-key` no servidor, enviada para `https://api-connect-us.bridge.new`. | | Webhooks | Seu receptor verifica a chave de API configurada para o webhook, a assinatura HMAC e a política de validade do timestamp. Siga o guia de [verificação de assinaturas](https://docs.bridge.new/pt-br/webhooks/verifying-signatures.md). | | Custom Connections | `captureKey` pública e reCAPTCHA no navegador; sem cabeçalho de autenticação. Siga o [guia de integração](https://docs.bridge.new/pt-br/lead-capture/integration.md). | **Nota** Você precisará de acesso ao console administrativo do Bridge em https://admin.bridge.new. Se ainda não tiver acesso, peça ao administrador do Bridge para criar seu usuário. --- ## Gere uma chave de API ### Abra o console administrativo Acesse o [painel do Bridge](https://admin.bridge.new) e entre com suas credenciais. ### Acesse as chaves de API No painel esquerdo, acesse **Developers → API Keys Management**. ### Crie uma nova chave Clique em **Generate New Key**. Você pode definir um nome descritivo e uma data de expiração. **Aviso** **Importante:**\ A chave de API será exibida apenas uma vez, no momento da criação. Copie-a imediatamente e guarde-a em um local seguro: você não poderá consultá-la depois. --- ## Use sua chave de API Inclua a chave da API REST no cabeçalho `x-api-key` em toda requisição ao host da API REST de integrações: ```bash curl -X GET "https://api-connect-us.bridge.new/bridge/api/health" \ -H "x-api-key: YOUR_API_KEY" ``` ```javascript const response = await fetch("https://api-connect-us.bridge.new/bridge/api/health", { method: "GET", headers: { "x-api-key": "YOUR_API_KEY", }, }); const data = await response.json(); console.log(data); ``` ```python import requests response = requests.get( "https://api-connect-us.bridge.new/bridge/api/health", headers={"x-api-key": "YOUR_API_KEY"} ) print(response.json()) ``` **Nota** Use o endpoint `GET /bridge/api/health` para verificar se a chave de API é válida e se a conexão está funcionando. --- ## Boas práticas de segurança - **Use variáveis de ambiente** — Armazene a chave de API em uma variável de ambiente, como `BRIDGE_API_KEY`, em vez de inseri-la diretamente no código-fonte. - **Nunca exponha chaves no código do cliente** — As chaves de API devem ser usadas somente em aplicações no servidor. Nunca as inclua no frontend, em aplicativos móveis ou em repositórios públicos. - **Defina uma data de expiração** — Sempre configure a expiração ao criar uma chave. Evite chaves sem prazo definido. - **Use uma chave por aplicação** — Crie uma chave de API separada para cada serviço ou aplicação que se conecta ao Bridge. Isso limita o impacto de uma chave comprometida. - **Faça a rotação das chaves periodicamente** — Crie uma nova chave e atualize as aplicações antes de desativar a antiga. Assim, a rotação não interrompe o serviço. --- ## Solução de problemas | Erro | Possível causa | Solução | | ----- | -------------- | -------- | | `401 Unauthorized` | Chave de API inválida, expirada ou ausente | Verifique se a chave está correta, ativa e incluída no cabeçalho `x-api-key` | | `403 Forbidden` | A chave de API não tem acesso ao recurso solicitado | Verifique se a chave tem as permissões necessárias para esse endpoint | | Não consigo consultar a chave de API | A chave é exibida apenas uma vez, no momento da criação | Gere uma nova chave de API no console administrativo | Para consultar a lista completa, veja a referência de [códigos de erro](https://docs.bridge.new/pt-br/error-codes.md). --- ## Tópicos relacionados - [Códigos de erro](https://docs.bridge.new/pt-br/error-codes.md) — Referência completa dos erros da API Bridge - [Referência da API REST](https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade.md) — Explore os endpoints disponíveis - [Webhooks](https://docs.bridge.new/pt-br/webhooks.md) — Configure notificações de eventos em tempo real --- # Glossário e identificadores Source: https://docs.bridge.new/pt-br/guides/identifiers Encontre os identificadores corretos de workspace, Contato, usuário do Bridge, Agente, conversa, template, linha e mídia, sem confundi-los. ## Comece pela integração correta A **API REST de integrações** lê ou altera recursos do workspace a partir do seu servidor usando `x-api-key`. **Webhooks** enviam eventos do Bridge ao seu receptor. **Custom Connections** registra leads de uma landing page por meio de um endpoint público separado, com `captureKey` e reCAPTCHA. A chave de API é um segredo do servidor. A `captureKey` de Custom Connections foi projetada para estar na landing page. Esses valores não são intercambiáveis. Veja [autenticação](https://docs.bridge.new/pt-br/credentials.md) e [Custom Connections](https://docs.bridge.new/pt-br/lead-capture/index.md). ## Pessoas, Agentes e linhas - Um **Contato** é a pessoa externa com quem sua empresa se comunica. Os endpoints de contatos e os participantes externos de conversas se referem a essa pessoa. - Um **usuário do Bridge** é um usuário humano interno. A consulta de usuários internos e os destinatários de uma transferência de atendimento se referem a esses usuários. - Um **Agente** é um agente automatizado exposto pela API de Agentes. Seu tipo é `LEADSCOUT` ou `SERVICE_AGENT`; ele tem identificador, disponibilidade e linhas próprios. - Um **provedor** é um tipo de canal, como `WHATSAPP`. Uma **linha** é um canal específico usado em uma conversa. O tipo de provedor, o telefone e o `providerChannelId` são valores diferentes. - Um **workspace** delimita o escopo da requisição. Uma **marca** tem outro identificador, usado onde a operação o exige ou aceita; ela não é um workspace nem uma linha. O `ownerId` de um Contato se refere a um usuário do Bridge, não a um Agente automatizado. Consulte esse usuário no [endpoint de leitura de usuários internos](https://docs.bridge.new/pt-br/api-reference/internal-users-api/obter-usu%C3%A1rio-interno-por-id.md). ## De onde vem cada identificador Use identificadores do workspace desejado. Não reutilize um identificador apenas porque o mesmo telefone, e-mail ou nome aparece em outro workspace. | Valor necessário | Onde obter ou verificar | O que enviar | | --- | --- | --- | | `workspaceId` | Use o identificador de workspace fornecido para sua integração. Se não o tiver, peça ao administrador do Bridge. O contrato REST publicado não oferece um endpoint global de listagem de workspaces. | O ID do workspace no caminho da operação. Custom Connections também o exige no corpo e, para requisições do navegador, na query string. | | ID do Contato | [Consulte um Contato](https://docs.bridge.new/pt-br/api-reference/contacts-api/obter-contato-por-um-identificador.md) por `PHONE`, `EMAIL` ou `ID`; respostas de listagem, criação e upsert também retornam o `id` do Contato. | O `id` retornado em `{contactId}` ou em um objeto identificador com `identifierType: "ID"`, onde a operação aceitar esse formato. | | ID do usuário do Bridge | [Consulte um usuário interno](https://docs.bridge.new/pt-br/api-reference/internal-users-api/obter-usu%C3%A1rio-interno-por-um-identificador.md) por `EMAIL` ou `ID`, ou use a lista de usuários internos. | O `id` retornado em `{userId}` ou em um objeto identificador interno. A consulta de usuários internos não aceita `PHONE`. | | ID do Agente | [Liste os Agentes](https://docs.bridge.new/pt-br/api-reference/agents-api/listar-os-agents-de-um-workspace.md). Leia `agents[].id`, `type` e `available`. | `agents[].id` em `{agentId}` na operação outbound de Agente. `available` indica se o Agente pode iniciar conversas. | | ID da linha do Agente | Na mesma resposta de Agentes, leia `lines[].providerChannelId` do Agente correspondente. | Um ID de linha pertencente ao Agente quando a operação aceitar `contact.providerChannelId`. Consulte as regras de seleção de linha na referência outbound. | | Canal de provedor em geral | [Liste os canais de provedor](https://docs.bridge.new/pt-br/api-reference/provider-channels-api/obter-canais-de-provedores-por-workspace.md). Essa resposta publica `provider` e `identifier`, não o UUID do canal. | Use esses campos somente para as finalidades documentadas pela operação que os recebe. Não substitua `providerChannelId` pelo `identifier`, que tem formato de telefone. | | `brandId` | Uma resposta de Agente pode expor seu `brandId`. Para outro fluxo, obtenha o ID da marca na configuração da integração ou com o administrador; o contrato publicado não oferece um endpoint geral de listagem de marcas. | O ID de marca aceito pela operação. Um ID de marca não é um ID de linha. | | `teamId` | Obtenha o ID da equipe interna desejada com o administrador do Bridge ou na configuração da integração. O contrato REST publicado não oferece um endpoint de listagem de equipes. | A opção documentada de atribuição de equipe na criação da conversa; não envie também `participants.internals`. | | ID da conversa | Crie ou consulte uma conversa e guarde o `id` retornado. As respostas outbound contêm `conversation.id`. | `{conversationId}` ou `conversationId`, exatamente onde a operação exigir. | | Template | [Descubra um template](https://docs.bridge.new/pt-br/api-reference/templates-api/descobrir-as-vari%C3%A1veis-agn%C3%B3sticas-de-um-modelo.md) por ID ou nome. A resposta retorna `id`, `name` e as chaves das variáveis. | Use o seletor esperado pela operação de envio; veja a próxima seção. | | `mediaId` | [Crie uploads pré-assinados](https://docs.bridge.new/pt-br/api-reference/files-api/criar-uploads-pr%C3%A9-assinados-de-arquivos.md). Cada item do array de resposta contém `mediaId` e `presignUrl`. Conclua o upload PUT obrigatório. | O `mediaId` retornado em `mediaIds` ou no campo de mídia aceito pela operação. Não envie a URL pré-assinada como ID de mídia. | **Nota** As listagens de Agentes expõem IDs de linha no contexto de cada Agente. Isso não é uma forma geral de descobrir todas as linhas do workspace. Se outro fluxo exigir um `providerChannelId` que você não consegue obter da resposta publicada, peça ao administrador do Bridge ou ao [suporte](mailto:support@sainapsis.com) o ID da linha desejada. Não gere um ID nem o derive de um telefone. ## Nomes semelhantes podem exigir campos diferentes A **consulta de contatos** recebe parâmetros de query chamados `type` e `value`. Um participante externo de conversa recebe `identifier` e `identifierType`, além dos demais campos exigidos pela operação. Não copie diretamente a query de consulta para o corpo de um participante. A **descoberta de templates** aceita ID ou nome no parâmetro de caminho `{templateId}`. Os **templates iniciais de conversa** usam `onboardingTemplates[].templateId`. A **seleção de template outbound** usa `id` ou `name` no objeto `template`; leia o esquema do endpoint em vez de renomear todos os seletores para `templateId`. Use a `key` retornada para cada variável em `parameters` do template. As chaves das variáveis não são índices de posições da Meta. O [guia de parâmetros de templates](https://docs.bridge.new/pt-br/templates-and-parameters.md) explica valores obrigatórios, padrões e a diferença entre omitir um valor e enviá-lo vazio. ## Não confunda os identificadores de resultado | Valor retornado | O que identifica | O que não comprova por si só | | --- | --- | --- | | `messageId` | Uma mensagem criada pelo endpoint de mensagens | Um comprovante de entrega do provedor | | `trackingId` | Uma solicitação aceita de transferência LeadScout | A conclusão da atribuição aos usuários solicitados | | `requestId` | Um envio aceito de Custom Connections | A entrega da mensagem inicial de WhatsApp | | `eventId` | Um identificador enviado com o evento de webhook; algumas famílias usam valores derivados da entidade | Uma chave de deduplicação globalmente única ou garantia de ordem de entrega | Siga o guia de [recebimento de eventos](https://docs.bridge.new/pt-br/webhooks/receive-events.md) para entender a identidade dos eventos e tratar duplicatas. Veja [respostas e erros](https://docs.bridge.new/pt-br/guides/responses.md) para interpretar códigos de status, resultados assíncronos e novas tentativas. Para um fluxo completo, siga o guia da [primeira conversa](https://docs.bridge.new/pt-br/guides/first-conversation.md) ou de [envio de anexos](https://docs.bridge.new/pt-br/guides/send-attachments.md). --- # Crie um contato e envie uma mensagem Source: https://docs.bridge.new/pt-br/guides/first-conversation Siga um fluxo completo no servidor, do Contato à conversa e à mensagem, preservando os identificadores retornados. Este guia cria um Contato, inicia uma conversa com um usuário interno do Bridge e cria uma mensagem. Execute o exemplo no seu servidor. **Aviso** Use um Contato de teste para o qual você tem autorização de envio. A criação da conversa pode executar os templates iniciais do workspace antes da requisição separada de mensagem. Revise essa configuração primeiro: definir como false o sinalizador de envio externo da mensagem posterior não desabilita os templates iniciais da conversa. ## Antes de começar - Obtenha uma chave de API para uso no servidor no guia de [autenticação](https://docs.bridge.new/pt-br/credentials.md). - Tenha o ID do workspace, o `providerChannelId` de uma linha ativa de WhatsApp e o e-mail de um usuário interno do Bridge. Veja [conceitos e identificadores](https://docs.bridge.new/pt-br/guides/identifiers.md). - Use um novo telefone de teste em formato internacional. Se o Contato já existir, use a [consulta de contatos](https://docs.bridge.new/pt-br/api-reference/contacts-api/obter-contato-por-um-identificador.md) em vez de criá-lo novamente. - Verifique os atributos personalizados obrigatórios e a sequência inicial configurada no workspace. Este exemplo mínimo não envia atributos personalizados nem substitui os templates. - Escolha `enableExternalBroadcast` explicitamente: `true` solicita o envio externo quando as regras da conversa e do destinatário permitem; `false` ainda cria a mensagem, mas não realiza o envio externo. Nenhum dos valores confirma a entrega pelo provedor. Esse sinalizador não ignora regras de visibilidade ou permissões. ## A sequência | Etapa | Requisição | Valor a guardar | | --- | --- | --- | | Verificar o acesso | `GET /bridge/api/health` | Resposta HTTP bem-sucedida | | Criar Contato | `POST /bridge/api/v1/workspaces/{workspaceId}/contacts` | `id` do Contato | | Iniciar conversa | `POST /bridge/api/v1/workspaces/{workspaceId}/conversations` | `id` da conversa | | Criar mensagem | `POST /bridge/api/v1/workspaces/{workspaceId}/messages` | `messageId` | O `id` do Contato passa a ser o `identifier` do participante externo, com `identifierType: "ID"`. O `id` da conversa passa a ser o `conversationId` da mensagem. ## Execute o exemplo Use Node.js com `fetch` nativo. Salve como `first-conversation.mjs`. Configure estas variáveis de ambiente no servidor, usando os recursos de segredos e configuração da sua aplicação: | Variável | Valor | | --- | --- | | `BRIDGE_API_KEY` | Sua chave de API secreta | | `BRIDGE_WORKSPACE_ID` | O ID do workspace desejado | | `BRIDGE_PROVIDER_CHANNEL_ID` | O ID da linha de WhatsApp autorizada, não seu telefone | | `BRIDGE_USER_EMAIL` | Um usuário interno do Bridge no mesmo workspace | | `TEST_CONTACT_PHONE` | O telefone de um novo Contato de teste autorizado | | `ENABLE_EXTERNAL_BROADCAST` | Exatamente `true` ou `false`; nenhum valor padrão é presumido | Os nomes e a mensagem abaixo são exemplos. Substitua-os pelo conteúdo de teste desejado antes de executar. ```javascript const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const providerChannelId = required("BRIDGE_PROVIDER_CHANNEL_ID"); const internalEmail = required("BRIDGE_USER_EMAIL"); const cellphone = required("TEST_CONTACT_PHONE"); const broadcast = required("ENABLE_EXTERNAL_BROADCAST"); if (!["true", "false"].includes(broadcast)) { throw new Error("ENABLE_EXTERNAL_BROADCAST must be true or false."); } const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; async function request(method, path, body, expectedStatus) { const response = await fetch(`${BASE}${path}`, { method, headers: { "x-api-key": apiKey, ...(body === undefined ? {} : { "Content-Type": "application/json" }), }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), }); const result = await response.json().catch(() => null); if (response.status !== expectedStatus) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`${method} ${path}: HTTP ${response.status}${code}`); } return result; } await request("GET", "/bridge/api/health", undefined, 200); const contact = await request("POST", `${workspacePath}/contacts`, { firstName: "Alex", lastName: "Example", languageCode: "EN", cellphone, }, 201); if (!contact?.id || contact.workspaceId !== workspaceId) { throw new Error("The Contact response does not identify the intended workspace."); } const conversation = await request("POST", `${workspacePath}/conversations`, { participants: { externals: [{ identifier: contact.id, identifierType: "ID", messageProviderType: "WHATSAPP", providerChannelId, }], internals: [{ identifier: internalEmail, identifierType: "EMAIL" }], }, name: "Integration test", status: "ACTIVE", }, 201); if (!conversation?.id || conversation.workspaceId !== workspaceId) { throw new Error("The Conversation response does not identify the intended workspace."); } const message = await request("POST", `${workspacePath}/messages`, { conversationId: conversation.id, messageBody: "Hello from our authorized Bridge integration test.", enableExternalBroadcast: broadcast === "true", }, 201); if (!message?.messageId) throw new Error("The Message response has no messageId."); console.log({ contactId: contact.id, conversationId: conversation.id, messageId: message.messageId, }); ``` ```bash node first-conversation.mjs ``` ## Entenda o resultado - Uma resposta `201` de Contato informa sua identidade e workspace. Leia `type` para verificar a classificação real: `NORMAL` ou `PARTIAL`. - Uma resposta `201` de conversa fornece o ID a usar na próxima etapa. Quando nenhuma linha está livre, o Bridge pode recuperar uma conversa liberada com exatamente os participantes solicitados. Nesse caso, o ID e o histórico são mantidos, e os valores solicitados de `name` e `status` não são aplicados. - Uma resposta `201` de mensagem fornece `messageId`. Isso, por si só, não comprova que o WhatsApp entregou a mensagem ao Contato. Este guia atribui explicitamente um usuário interno do Bridge. Para atribuir uma equipe, use a opção documentada `teamId` em vez de `participants.internals`: as duas opções são mutuamente exclusivas. ## Se uma etapa falhar O exemplo para na requisição que falhou e nunca repete uma operação de escrita automaticamente. Uma falha de rede pode deixar o resultado incerto. Consulte o recurso correspondente antes de repetir uma criação ou um envio. | Situação | Próxima ação | | --- | --- | | O Contato já existe | Use a consulta de contatos e o `id` retornado; não continue criando o mesmo Contato. | | Erro de marca ou linha | Confirme a linha ou marca autorizada com o administrador; o telefone de uma linha não é seu ID. | | Erro de template `0604`–`0608` | Consulte [parâmetros de templates de WhatsApp](https://docs.bridge.new/pt-br/templates-and-parameters.md), incluindo os erros de configuração do workspace. | | Mensagem rejeitada porque a conversa está liberada | Verifique o estado da conversa e a referência de erros da operação antes de realizar outra ação. | | `429` | Siga o guia de [limites de requisições](https://docs.bridge.new/pt-br/rate-limits.md), incluindo `Retry-After`. | Veja [respostas e erros](https://docs.bridge.new/pt-br/guides/responses.md) para conhecer os formatos de resposta e decidir como recuperar a operação. ## Próximos passos - [Faça upload e envie um anexo](https://docs.bridge.new/pt-br/guides/send-attachments.md). - [Escolha e preencha um template de WhatsApp](https://docs.bridge.new/pt-br/guides/send-template.md). - Consulte os contratos completos de requisição e resposta para [criar um Contato](https://docs.bridge.new/pt-br/api-reference/contacts-api/criar-contato.md), [criar uma conversa](https://docs.bridge.new/pt-br/api-reference/conversations-api/criar-conversa-com-identifica%C3%A7%C3%A3o-flex%C3%ADvel-de-usu%C3%A1rios.md) e [criar uma mensagem](https://docs.bridge.new/pt-br/api-reference/messages-api/criar-mensagem.md). --- # Enviar PDF e outros anexos Source: https://docs.bridge.new/pt-br/guides/send-attachments Envie um PDF ou outro arquivo compatível em uma conversa: calcule o checksum, faça upload na URL pré-assinada e anexe o ID de mídia à mensagem. Para enviar um PDF ou outro anexo compatível, solicite um upload ao Bridge, envie os bytes do arquivo à URL retornada e crie uma mensagem com o `mediaId` recebido. O exemplo completo no servidor abaixo envia um PDF. ## Antes de começar - Tenha uma conversa existente no workspace desejado. Veja [primeira conversa](https://docs.bridge.new/pt-br/guides/first-conversation.md). - Escolha um PDF que você tem autorização para compartilhar e confirme se ele atende aos limites da [API de arquivos](https://docs.bridge.new/pt-br/api-reference/files-api/criar-uploads-pr%C3%A9-assinados-de-arquivos.md). - Mantenha a chave de API do Bridge no servidor. Não a acrescente à requisição de upload pré-assinada. - Escolha explicitamente o sinalizador `enableExternalBroadcast` da mensagem. ## Valide o arquivo antes de solicitar um upload Verifique o arquivo real no seu servidor: a extensão, o tipo MIME e o tamanho em bytes devem cumprir as regras publicadas da [API de arquivos](https://docs.bridge.new/pt-br/api-reference/files-api/criar-uploads-pr%C3%A9-assinados-de-arquivos.md). A requisição de URL pré-assinada contém metadados e um checksum, não os bytes do arquivo nem um campo de tamanho. Uma resposta `201` prepara um upload; não comprova que os bytes reais foram inspecionados, que o tamanho enviado cumpre os limites publicados ou que um provedor de mensagens aceitará o arquivo. Se você omitir `contentType`, ainda assim copie `presignUrl.headers` para a requisição PUT: a Bridge pode deduzir `Content-Type` pelo nome do arquivo. Se o informar, use o tipo MIME do arquivo real e mantenha-o coerente com `fileType` e a extensão. Renomear um arquivo não converte seu conteúdo. Após um PUT bem-sucedido, o processamento do upload ainda pode estar pendente. Se uma requisição de Message retornar um [erro de upload de arquivos](https://docs.bridge.new/pt-br/error-codes.md#file-upload-errors), preserve o erro completo e confira a etapa que falhou antes de decidir se outra gravação é segura. ## Sequência de upload | Etapa | O que acontece | O que ela não confirma | | --- | --- | --- | | `POST .../files` | O Bridge retorna `mediaId` e os dados de `presignUrl`. | Os bytes ainda não foram enviados. | | `PUT` pré-assinado | Seu servidor envia exatamente os bytes do arquivo usando a URL de upload e os cabeçalhos retornados. | Essa etapa não cria uma mensagem. | | `POST .../messages` | Você anexa o `mediaId` do arquivo enviado por meio de `mediaIds`. | A resposta da API, sozinha, não comprova a entrega pelo provedor. | O checksum é o **digest SHA-256 de todos os bytes do arquivo, codificado em Base64**. Não é um digest hexadecimal nem o hash do nome do arquivo. ## Exemplo completo no servidor Use Node.js com `fetch` nativo. Salve como `send-attachment.mjs`. Defina `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_CONVERSATION_ID`, `ATTACHMENT_PATH` e `ENABLE_EXTERNAL_BROADCAST` (`true` ou `false`). ```javascript import { readFile } from "node:fs/promises"; import { basename } from "node:path"; import { createHash } from "node:crypto"; const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const conversationId = required("BRIDGE_CONVERSATION_ID"); const filePath = required("ATTACHMENT_PATH"); const broadcast = required("ENABLE_EXTERNAL_BROADCAST"); if (!["true", "false"].includes(broadcast)) { throw new Error("ENABLE_EXTERNAL_BROADCAST must be true or false."); } if (!filePath.toLowerCase().endsWith(".pdf")) { throw new Error("This example is configured for a PDF document."); } const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; const bytes = await readFile(filePath); const checksumBase64 = createHash("sha256").update(bytes).digest("base64"); async function bridgePost(path, body) { const response = await fetch(`${BASE}${workspacePath}${path}`, { method: "POST", headers: { "x-api-key": apiKey, "Content-Type": "application/json" }, body: JSON.stringify(body), }); const result = await response.json().catch(() => null); if (response.status !== 201) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`Bridge ${path}: HTTP ${response.status}${code}`); } return result; } const uploads = await bridgePost("/files", [{ name: basename(filePath), fileType: "DOCUMENT", contentType: "application/pdf", checksumBase64, }]); const upload = uploads?.[0]; if (!upload?.mediaId || !upload.presignUrl?.url) { throw new Error("The upload response is missing its mediaId or URL."); } const method = upload.presignUrl.method ?? "PUT"; if (method !== "PUT") throw new Error("Expected a presigned PUT upload."); const uploadHeaders = new Headers(upload.presignUrl.headers ?? {}); const returnedChecksum = uploadHeaders.get("x-amz-checksum-sha256"); if (returnedChecksum !== null && returnedChecksum !== checksumBase64) { throw new Error("The returned checksum differs from the file checksum."); } if (returnedChecksum === null) { uploadHeaders.set("x-amz-checksum-sha256", checksumBase64); } const uploaded = await fetch(upload.presignUrl.url, { method, headers: uploadHeaders, body: bytes, }); if (!uploaded.ok) { throw new Error(`File upload failed: HTTP ${uploaded.status}; no Message was created.`); } const message = await bridgePost("/messages", { conversationId, messageBody: "Here is the document you requested.", enableExternalBroadcast: broadcast === "true", mediaIds: [upload.mediaId], }); if (!message?.messageId) throw new Error("The Message response has no messageId."); console.log({ mediaId: upload.mediaId, messageId: message.messageId }); ``` ```bash node send-attachment.mjs ``` ## Preserve a requisição de upload Use `presignUrl.url` sem reconstruir o host, o caminho ou a query string. Use o método e os cabeçalhos obrigatórios retornados. O contrato define `PUT` como método padrão quando o campo é omitido, e a API de arquivos exige `x-amz-checksum-sha256` com o mesmo checksum enviado ao Bridge. O upload envia os mesmos `bytes` usados para calcular o checksum. Não converta o PDF em texto, não o encapsule em JSON e não envie uma cópia diferente após calcular o hash. Para vários arquivos, preserve a associação entre cada `mediaId` retornado, os dados pré-assinados e o arquivo correspondente. Conclua todos os uploads necessários antes de anexar os IDs a uma mensagem. Algumas mídias precisam de mais preparação após o upload, como copiar o arquivo, gerar uma prévia, converter ou enviar o arquivo ao provedor de mensagens. Essas etapas podem falhar de forma independente. Um PUT bem-sucedido ou uma resposta 201 ao criar a mensagem não comprovam que o processamento ou a entrega pelo provedor foram concluídos. Mantenha o arquivo original e os identificadores recebidos para correlacionar o resultado antes de repetir uma requisição de mensagem. ## Trate uma falha em cada etapa - **O Bridge rejeita a solicitação de arquivo:** confira extensão, `fileType`, tipo de conteúdo, tamanho e checksum na referência. - **O upload falha:** pare antes de criar a mensagem. Verifique URL, método, cabeçalhos, checksum e bytes exatos. Não presuma um prazo de validade ou uma política de novas tentativas que a resposta não informe. - **A requisição de mensagem falha ou expira:** um arquivo enviado não comprova a existência de uma mensagem. Verifique o resultado antes de repetir a requisição de mensagem. `STICKER` e `WEBSITE` aparecem no enum `FileType`, mas a tabela pública de upload não especifica suas regras de extensão, MIME e tamanho. Confirme essas regras antes de escolher qualquer um deles para uma integração. Veja a [API de arquivos](https://docs.bridge.new/pt-br/api-reference/files-api/criar-uploads-pr%C3%A9-assinados-de-arquivos.md), a [API de mensagens](https://docs.bridge.new/pt-br/api-reference/messages-api/criar-mensagem.md) e o guia de [respostas e erros](https://docs.bridge.new/pt-br/guides/responses.md). --- # Escolha e preencha um template de WhatsApp Source: https://docs.bridge.new/pt-br/guides/send-template Descubra um template por ID ou nome, forneça os valores por suas chaves de variável agnósticas e use o ID retornado em uma requisição de conversa. Use este guia quando quiser abrir uma conversa com um template específico de WhatsApp. A [referência detalhada de templates](https://docs.bridge.new/pt-br/templates-and-parameters.md) explica as regras de validação e todos os erros de template documentados. ## Antes de começar - Tenha o **ID ou nome** do template. Ambos são aceitos por `GET .../templates/{templateId}`. - Confirme que o template foi aprovado para a conta WhatsApp Business associada à linha desejada. - Tenha o ID de um Contato de teste existente, o `providerChannelId` da linha autorizada de WhatsApp e o e-mail de um usuário interno do Bridge. Veja [conceitos e identificadores](https://docs.bridge.new/pt-br/guides/identifiers.md). - Revise a sequência inicial do workspace: sua substituição pode trocar toda a sequência ou apenas o primeiro template, conforme a configuração. **Aviso** A requisição final inicia uma conversa e pode enviar os templates iniciais. Use um Contato de teste autorizado e o conteúdo pretendido. ## 1. Descubra as variáveis ```http GET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId} x-api-key: YOUR_API_KEY ``` Codifique o ID ou nome fornecido para uso na URL. Leia `id`, `name`, `variables` e `driftWarning` na resposta. | Variável | Ação | | --- | --- | | `callerMustSupply: true` | Forneça uma string não vazia na `key` dessa variável. | | `callerMustSupply: false`, não personalizada | Omita-a para manter o valor definido pelo Bridge para cada Contato. Um valor informado substitui esse valor para todos os Contatos. | | `isCustom: true` | Forneça seu valor ou omita-o ou envie-o vazio para usar o `default`. | Use a `key` agnóstica, nunca o `label` de exibição, uma posição da Meta ou um nome de variável inventado. `driftWarning` é diagnóstico e, por si só, não bloqueia o envio. ## 2. Prepare seus valores Crie um arquivo JSON no servidor contendo somente as chaves retornadas pela descoberta. Para um template que realmente declare `order_number` e `delivery_date`, ele poderia conter: ```json { "order_number": "A-10492", "delivery_date": "October 3" } ``` Esses dois nomes são exemplos, não campos universais do Bridge. Consulte seu próprio template antes de usá-los. Mantenha os valores dentro das [regras de valores do WhatsApp](https://docs.bridge.new/pt-br/templates-and-parameters.md#whatsapp-value-rules). Para valores não personalizados que você quer que o Bridge preencha, omita as chaves em vez de enviar strings vazias. ## 3. Descubra, valide e crie a conversa Use Node.js com `fetch` nativo. Salve como `send-template.mjs` e defina `BRIDGE_API_KEY`, `BRIDGE_WORKSPACE_ID`, `BRIDGE_TEMPLATE_ID_OR_NAME`, `TEMPLATE_VALUES_PATH`, `BRIDGE_CONTACT_ID`, `BRIDGE_PROVIDER_CHANNEL_ID` e `BRIDGE_USER_EMAIL`. ```javascript import { readFile } from "node:fs/promises"; const BASE = "https://api-connect-us.bridge.new"; function required(name) { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; } const apiKey = required("BRIDGE_API_KEY"); const workspaceId = required("BRIDGE_WORKSPACE_ID"); const templateRef = required("BRIDGE_TEMPLATE_ID_OR_NAME"); const contactId = required("BRIDGE_CONTACT_ID"); const providerChannelId = required("BRIDGE_PROVIDER_CHANNEL_ID"); const internalEmail = required("BRIDGE_USER_EMAIL"); const parameters = JSON.parse(await readFile(required("TEMPLATE_VALUES_PATH"), "utf8")); if (parameters === null || Array.isArray(parameters) || typeof parameters !== "object") { throw new Error("The template values file must contain a JSON object."); } if (Object.entries(parameters).some(([key, value]) => Array.from(key).length > 128 || typeof value !== "string" || Array.from(value).length > 1024 )) { throw new Error("Parameter keys and values must respect the published string limits."); } if (Object.keys(parameters).length > 50) throw new Error("At most 50 parameters are allowed."); const workspacePath = `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}`; async function request(method, path, body, expectedStatus) { const response = await fetch(`${BASE}${workspacePath}${path}`, { method, headers: { "x-api-key": apiKey, ...(body === undefined ? {} : { "Content-Type": "application/json" }), }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), }); const result = await response.json().catch(() => null); if (response.status !== expectedStatus) { const code = result?.code ? ` (${result.code})` : ""; throw new Error(`${method} ${path}: HTTP ${response.status}${code}`); } return result; } const template = await request( "GET", `/templates/${encodeURIComponent(templateRef)}`, undefined, 200, ); if (!template?.id) throw new Error("Template discovery returned no id."); const variables = template.variables ?? []; const known = new Set(variables.map((variable) => variable.key)); const unknown = Object.keys(parameters).filter((key) => !known.has(key)); const missing = variables.filter((variable) => variable.callerMustSupply && (typeof parameters[variable.key] !== "string" || !parameters[variable.key].trim()) ); if (unknown.length || missing.length) { throw new Error(`Check template keys: ${unknown.length} unknown, ${missing.length} missing.`); } const conversation = await request("POST", "/conversations", { participants: { externals: [{ identifier: contactId, identifierType: "ID", messageProviderType: "WHATSAPP", providerChannelId, }], internals: [{ identifier: internalEmail, identifierType: "EMAIL" }], }, onboardingTemplates: [{ templateId: template.id, parameters }], }, 201); if (!conversation?.id || conversation.workspaceId !== workspaceId) { throw new Error("The Conversation response does not identify the intended workspace."); } console.log({ templateId: template.id, conversationId: conversation.id }); ``` ```bash node send-template.mjs ``` O exemplo usa o ID retornado pela descoberta em `onboardingTemplates[].templateId`. As duas operações outbound também aceitam ID ou nome do template, com prioridade para o ID quando ambos são informados. Seus formatos de requisição são diferentes de `onboardingTemplates`; leia o contrato da operação antes de reutilizar esse corpo em outro contexto. As verificações locais detectam chaves desconhecidas ou obrigatórias ausentes. O Bridge ainda realiza sua própria validação, incluindo a aprovação para a linha selecionada e as regras finais de valores do WhatsApp. Não trate a validação local como aprovação ou garantia de entrega. ## Corrija uma requisição rejeitada | Erro | O que fazer | | --- | --- | | Descoberta `BRIDGE_TEMPLATE_0001` | Confira o ID ou nome e o workspace. Essa resposta não revela se o identificador pertence a outro workspace. | | `BRIDGE_CONVERSATION_0604` | Forneça valores não vazios para as variáveis de `extra.missingVariables`. | | `BRIDGE_CONVERSATION_0605` | Remova as chaves de `extra.unknownKeys`; use as chaves agnósticas da descoberta. | | `BRIDGE_CONVERSATION_0607` | Corrija os valores de `extra.invalidVariables` conforme o `reason` de cada um. | | `BRIDGE_CONVERSATION_0608` | Peça a um administrador do workspace para alterar a sequência inicial configurada. Mudar os valores do seu template não corrige esse erro de configuração. | Leia a [referência completa de erros de templates](https://docs.bridge.new/pt-br/templates-and-parameters.md#errors) para entender aprovação, titularidade, parâmetros não aceitos e requisições malformadas. Não repita automaticamente uma requisição de conversa que expirou: primeiro verifique o resultado. --- # Inicie uma conversa outbound com um Agente Source: https://docs.bridge.new/pt-br/guides/agent-outbound Escolha um Agente, envie um template inicial, entenda forceSend e a recuperação de conversas e solicite uma transferência LeadScout. Use outbound quando um Contato existente deve receber um template aprovado de WhatsApp e continuar a conversa com um Agente de IA. Para o fluxo geral de conversas, use [criar uma conversa](https://docs.bridge.new/pt-br/guides/first-conversation.md). ## Escolha a operação | Objetivo | Operação | Como o Agente é selecionado | | --- | --- | --- | | Iniciar com um LeadScout ou Service Agent específico | `POST /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound` | Você fornece o ID do Agente obtido em `GET /agents`. | | Iniciar com um LeadScout selecionado pelas linhas elegíveis do workspace | `POST /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound` | O Bridge identifica o Agente de prospecção da linha. | As duas operações usam o host REST `https://api-connect-us.bridge.new` e `x-api-key` no servidor. Seus esquemas de requisição são separados. Leia a [referência de outbound de Agentes](https://docs.bridge.new/pt-br/api-reference/agents-api/iniciar-conversa-de-sa%C3%ADda-com-um-contact-como-agent-espec%C3%ADfico.md) ou a [referência de outbound de LeadScout](https://docs.bridge.new/pt-br/api-reference/leadscout-api/iniciar-conversa-de-sa%C3%ADda-do-leadscout-com-um-lead-conhecido.md), conforme a operação escolhida. ## Antes de enviar 1. [Consulte o Contato](https://docs.bridge.new/pt-br/api-reference/contacts-api/obter-contato-por-um-identificador.md) ou [crie-o](https://docs.bridge.new/pt-br/api-reference/contacts-api/criar-contato.md), se não existir. Outbound exige um Contato já existente no workspace; você não precisa criar antes uma conversa ou mensagem separada. 2. [Liste os Agentes](https://docs.bridge.new/pt-br/api-reference/agents-api/listar-os-agents-de-um-workspace.md). Escolha um Agente disponível e leia seu `lines[].providerChannelId`. O ID de um Agente de IA é diferente do ID de um usuário humano do Bridge. 3. Escolha um template aprovado. [Descubra suas variáveis](https://docs.bridge.new/pt-br/guides/send-template.md#1-discover-the-variables), forneça os valores exigidos do integrador e confirme a aprovação para a linha de destino. Use apenas a etapa de descoberta como pré-requisito: a etapa separada de criação de conversa desse guia não é necessária para outbound. 4. Confirme que sua empresa tem o aceite necessário. Se enviar `consent.status: "GRANTED"`, inclua `capturedAt`; isso registra sua declaração de consentimento. No outbound de Agentes, `contact.providerChannelId`, quando informado, deve pertencer ao Agente escolhido. Ele expressa uma preferência: outra linha elegível do Agente pode ser selecionada. No outbound de LeadScout, a linha explícita é respeitada. O guia de [identificadores e suas fontes](https://docs.bridge.new/pt-br/guides/identifiers.md) explica quais valores usar. ## Envie uma requisição mínima de Agente Substitua todos os valores de exemplo. Este caso pressupõe que o template escolhido não tenha variáveis obrigatórias do integrador ainda sem valor. Defina `forceSend` conscientemente; o exemplo mantém explícito o comportamento padrão. ```bash curl --fail-with-body --request POST \ "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/agents/$AGENT_ID/outbound" \ --header "x-api-key: $BRIDGE_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "contact": { "identifier": "f0000001-0000-4000-8000-000000000001", "identifierType": "ID", "messageProviderType": "WHATSAPP" }, "template": { "id": "f0000040-0000-4000-8000-000000000040" }, "forceSend": false }' ``` Uma requisição bem-sucedida retorna `201`. Guarde `conversation.id` e interprete os campos de resposta: | Campo | Significado | | --- | --- | | `alreadyInitiated: true` | Uma conversa ativa existente foi reutilizada. A requisição bem-sucedida ainda acrescenta seu novo template e as mensagens de acompanhamento. | | `recovered: true` | Uma conversa liberada e recuperável foi recuperada, mantendo o ID. O contexto outbound anterior e `agentContext` são substituídos. | | `additionalMessagesPersisted` | Quantidade de mensagens de acompanhamento armazenadas. Não é um comprovante de entrega. | | `templateSent` | Resumo do template inicial armazenado para envio. Não interprete o nome do campo como prova de entrega ao destinatário. | Em uma criação nova, os indicadores de reutilização e recuperação não são true. A recuperação pode ocorrer com `forceSend: false`. As mensagens adicionais são persistidas na ordem da requisição; não conte com uma promessa de que aguardam a resposta do Contato. O fluxo outbound compartilhado persiste mensagens de acompanhamento em texto e não anexa seus `mediaIds`. Use a opção documentada `template.media` para mídia no template inicial ou o [fluxo de anexos de mensagem](https://docs.bridge.new/pt-br/guides/send-attachments.md) para uma mensagem separada. ## O que forceSend faz A disponibilidade é avaliada para **a conversa desse Contato em cada linha**. Uma linha ocupada, nesse contexto, não significa que a linha corporativa de WhatsApp esteja globalmente reservada a um único Contato. As regras abaixo continuam sujeitas à disponibilidade do Agente, à validação do template e do consentimento e às verificações de sessão. Em telas estreitas, role horizontalmente para comparar as quatro opções. Quem usa o teclado pode colocar o foco nessa comparação e usar as teclas de seta. | Situação | LeadScout: false | LeadScout: true | Agentes: false | Agentes: true | | --- | --- | --- | --- | --- | | A linha selecionada está livre | Cria | Cria | Cria | Cria | | A linha selecionada contém uma conversa liberada marcada como recuperável | Recupera o mesmo ID | Recupera o mesmo ID | Recupera o mesmo ID | Recupera o mesmo ID | | A seleção automática encontra apenas conversas ativas ocupadas | `409 …0008` | Reutiliza a primeira conversa ocupada elegível | `409 …0008` | Prioriza uma conversa controlada pelo Agente solicitado e aplica a verificação de controlador abaixo | | A linha explícita está ocupada | `409 …0007` | Reutiliza essa conversa | Tenta outras linhas livres ou recuperáveis do Agente; se não houver, `409 …0008` | Tenta outras linhas livres ou recuperáveis; se não houver, prioriza uma linha ocupada controlada pelo Agente | | A conversa ocupada selecionada é controlada por uma pessoa ou outro Agente | Não reutiliza a conversa ativa | A rota legada permite reutilização, sujeita às demais verificações; isso não promete, por si só, transferência de controle | Não reutiliza a conversa ativa | `409 BRIDGE_AI_AGENT_OUTBOUND_0006`; essa rejeição não grava nada | | Há apenas conversas bloqueadas ou liberadas não recuperáveis | `409 …0008` | `409 …0008` | `409 …0008` | `409 …0008` | Nesta tabela, `…0007` corresponde a `BRIDGE_AI_LEADSCOUT_0007`, e `…0008`, a `BRIDGE_AI_LEADSCOUT_0008`. Uma conversa liberada só é recuperável quando o sinalizador de recuperação armazenado permite; `forceSend` não a torna recuperável. Nas duas rotas, uma sessão LeadScout ainda aberta e não expirada bloqueia uma nova requisição outbound com `409 BRIDGE_AI_LEADSCOUT_0017`. A falha ao finalizar uma sessão expirada retorna `409 BRIDGE_AI_LEADSCOUT_0018`. Um Service Agent pode continuar sua sessão de serviço aberta e não expirada; uma sessão expirada é encerrada antes de iniciar outra. **Aviso** `forceSend` não é uma chave de idempotência. Repetir uma requisição bem-sucedida pode acrescentar outro template e mais mensagens. O sinalizador não ignora conversas bloqueadas, verificações de sessão, regras de aprovação ou validação. Um timeout deixa o resultado incerto: consulte a conversa antes de decidir reenviar. ## Trate conflitos e trabalho parcial | Resultado | Próxima etapa | | --- | --- | | `BRIDGE_AI_LEADSCOUT_0007` / `0008` | Confira a conversa existente do Contato e as linhas elegíveis. Decida se a reutilização é apropriada antes de habilitar `forceSend`. | | `BRIDGE_AI_AGENT_OUTBOUND_0006` | Examine `extra.conversationId` e seu controlador. Combine a responsabilidade pelo atendimento antes de liberar a conversa de propósito. Não interrompa automaticamente uma conversa humana. | | `BRIDGE_AI_LEADSCOUT_0017` / `0018` | Resolva a sessão existente ou contate o suporte. Mudar `forceSend` para true não corrige a sessão. | | `BRIDGE_AI_LEADSCOUT_0019` / `0020` / `0021` | Corrija variáveis obrigatórias ausentes, conflitantes ou desconhecidas usando a descoberta. | | `400 BRIDGE_AI_LEADSCOUT_0016` para `mediaId` de template desconhecido no outbound de Agentes | A conversa pode já ter sido criada ou recuperada antes desse erro. Consulte-a antes de tentar novamente. | [Liberar conversa](https://docs.bridge.new/pt-br/api-reference/conversations-api/liberar-conversa.md) é uma operação separada, com efeitos de negócio. Uma resposta `204` não tem corpo. Libere a conversa somente quando encerrá-la for a ação desejada. ## Solicite a transferência de LeadScout para uma pessoa Para uma conversa LeadScout, obtenha o [ID ou e-mail do usuário humano do Bridge](https://docs.bridge.new/pt-br/guides/identifiers.md) e chame o [endpoint de transferência manual](https://docs.bridge.new/pt-br/api-reference/leadscout-api/solicitar-transfer%C3%AAncia-manual-do-leadscout-para-usu%C3%A1rios-internos.md). Essa operação é específica de LeadScout; não presuma que também se aplica a um Service Agent. ```bash curl --fail-with-body --request POST \ "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE_ID/leadscout/conversations/$CONVERSATION_ID/handoff" \ --header "x-api-key: $BRIDGE_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "assignees": [ {"identifier": "f0000002-0000-4000-8000-000000000002", "identifierType": "ID"} ] }' ``` Uma resposta `202` confirma a aceitação da solicitação. Guarde `trackingId` e `conversationId`; a aceitação não comprova que a atribuição terminou nem que uma pessoa leu ou respondeu à conversa. A referência não publica um endpoint de acompanhamento da transferência, portanto não construa um a partir de `trackingId`. Continue com o [tratamento de erros](https://docs.bridge.new/pt-br/error-codes.md) e o [recebimento de webhooks](https://docs.bridge.new/pt-br/webhooks/receive-events.md) para conectar esse fluxo ao seu sistema. --- # Leia todas as páginas de resultados Source: https://docs.bridge.new/pt-br/guides/pagination Percorra os cursores opacos de Contatos, conversas, usuários do Bridge e Agentes, sem parar em uma página com poucos registros. Os endpoints de listagem retornam uma coleção e um `cursor` opcional. Envie esse cursor sem alterações para ler a próxima página. Continue seguindo os cursores até que o valor seja nulo ou esteja ausente. ## Escolha a coleção Os quatro endpoints abaixo aceitam `limit` de **1 a 100**, com valor padrão **20**. | Recurso | Caminho após o workspace | Campo da coleção | | --- | --- | --- | | Contatos | `/contacts` | `contacts` | | Conversas | `/conversations` | `conversations` | | Usuários do Bridge | `/users` | `users` | | Agentes | `/agents` | `agents` | Use a [consulta de contatos](https://docs.bridge.new/pt-br/api-reference/contacts-api/obter-contato-por-um-identificador.md) ou a [consulta de usuários do Bridge](https://docs.bridge.new/pt-br/api-reference/internal-users-api/obter-usu%C3%A1rio-interno-por-um-identificador.md) quando precisar encontrar uma pessoa conhecida. Percorrer a lista inteira é uma tarefa diferente. ## Exemplo no servidor Este exemplo lê Contatos. Salve como `list-contacts.mjs` e defina `BRIDGE_API_KEY` e `BRIDGE_WORKSPACE_ID` no servidor. A proteção local `maxPages` evita uma execução ilimitada por engano; ela não é um limite da API Bridge. A proteção contra cursores repetidos interrompe a execução e informa o problema, em vez de retornar silenciosamente uma lista incompleta. ```javascript const BASE = "https://api-connect-us.bridge.new"; const apiKey = process.env.BRIDGE_API_KEY; const workspaceId = process.env.BRIDGE_WORKSPACE_ID; if (!apiKey || !workspaceId) { throw new Error("Set BRIDGE_API_KEY and BRIDGE_WORKSPACE_ID."); } async function* pages(resource, collection, filters = {}) { let cursor; const seen = new Set(); const maxPages = 10000; for (let pageNumber = 0; pageNumber < maxPages; pageNumber += 1) { const url = new URL( `/bridge/api/v1/workspaces/${encodeURIComponent(workspaceId)}/${resource}`, BASE, ); for (const [key, value] of Object.entries(filters)) { url.searchParams.set(key, String(value)); } url.searchParams.set("limit", "100"); if (cursor !== undefined) url.searchParams.set("cursor", cursor); const response = await fetch(url, { headers: { "x-api-key": apiKey } }); const body = await response.json().catch(() => null); if (response.status !== 200) { const code = body?.code ? ` (${body.code})` : ""; throw new Error(`List ${resource}: HTTP ${response.status}${code}`); } if (!Array.isArray(body?.[collection])) { throw new Error(`Expected the ${collection} collection.`); } yield body[collection]; if (body.cursor === null || body.cursor === undefined) return; if (typeof body.cursor !== "string" || seen.has(body.cursor)) { throw new Error("Invalid or repeated cursor; stopped without claiming completion."); } seen.add(body.cursor); cursor = body.cursor; } throw new Error("Local page guard reached; the sweep is incomplete."); } let count = 0; for await (const contacts of pages("contacts", "contacts")) { // Process or store this page before continuing. Avoid logging personal data. count += contacts.length; } console.log({ contactsRead: count }); ``` ```bash node list-contacts.mjs ``` Use `pages("conversations", "conversations", { status: "ACTIVE" })`, `pages("users", "users")` ou `pages("agents", "agents")` com o contrato correspondente. Mantenha os mesmos filtros durante todo o percurso. ## Não pare em uma página com poucos registros Uma página com menos registros que `limit` ainda pode ter uma próxima página. O endpoint de Agentes documenta esse comportamento explicitamente. O sinal de continuação é o cursor retornado, não o tamanho da coleção. Trate o cursor como opaco. Não o decodifique, incremente ou crie por conta própria. O `URL.searchParams` do exemplo preserva seu valor por meio da codificação de URL. ## Filtros e limites de requisições - Os filtros `ownerEmail` e `search` da lista de Contatos estão obsoletos. Para um e-mail ou telefone conhecido, use a consulta de contatos. Para filtrar um conjunto por `ownerId`, leia esse campo nas linhas retornadas e faça a filtragem no seu código. - Os filtros `email` e `status` da lista de usuários do Bridge estão obsoletos. Use a consulta para um e-mail conhecido ou examine o `status` de cada usuário retornado. - Cada requisição de página consome a cota compartilhada do workspace. Siga o guia de [limites de requisições](https://docs.bridge.new/pt-br/rate-limits.md), incluindo `Retry-After` em respostas `429`. Este exemplo mínimo para em respostas diferentes de 200, sem tentar novamente automaticamente. Os contratos publicados não garantem uma visão transacionalmente consistente da lista enquanto os registros estão mudando. Não apresente esse percurso como uma exportação necessariamente consistente nem presuma um prazo de validade do cursor que não esteja documentado. ## Referências - [Listar Contatos](https://docs.bridge.new/pt-br/api-reference/contacts-api/listar-contatos.md) - [Listar conversas](https://docs.bridge.new/pt-br/api-reference/conversations-api/consultar-conversas-com-filtros-flex%C3%ADveis.md) - [Listar usuários do Bridge](https://docs.bridge.new/pt-br/api-reference/internal-users-api/listar-usu%C3%A1rios-internos.md) - [Listar Agentes](https://docs.bridge.new/pt-br/api-reference/agents-api/listar-os-agents-de-um-workspace.md) - [Respostas e erros](https://docs.bridge.new/pt-br/guides/responses.md) --- # Respostas, erros e novas tentativas Source: https://docs.bridge.new/pt-br/guides/responses Interprete criação, aceitação, respostas vazias, erros de validação e sinais de nova tentativa, sem confundir os contratos REST e de Custom Connections. ## Interprete o resultado da operação O status HTTP e o corpo da resposta descrevem a operação chamada. Eles nem sempre significam que uma pessoa recebeu uma mensagem. | Operação | Sucesso publicado | O que fazer com o resultado | | --- | --- | --- | | Criar uma mensagem | `201`, com `messageId` | Guarde o ID da mensagem. A resposta publicada não inclui um comprovante de entrega do provedor; não a apresente como entregue com base apenas nessa resposta. | | Liberar uma conversa | `204`, sem corpo de resposta | Trate como sucesso e não chame um parser de JSON para o corpo vazio. | | Solicitar transferência LeadScout | `202`, com `trackingId`, `conversationId`, `status` e `assignees` | Guarde o ID de correlação. A atribuição é assíncrona; os destinatários repetem o que foi solicitado e não comprovam que a resolução ou atribuição posterior terminou. | | Enviar um lead por Custom Connections | `202`, com `requestId` | Guarde o ID da requisição. Informe que o lead foi aceito; a mensagem inicial de WhatsApp é enviada depois por um serviço separado. | A referência de cada operação continua sendo a fonte do contrato: [mensagens](https://docs.bridge.new/pt-br/api-reference/messages-api/criar-mensagem.md), [liberação](https://docs.bridge.new/pt-br/api-reference/conversations-api/liberar-conversa.md), [transferência](https://docs.bridge.new/pt-br/api-reference/leadscout-api/solicitar-transfer%C3%AAncia-manual-do-leadscout-para-usu%C3%A1rios-internos.md) e [Custom Connections](https://docs.bridge.new/pt-br/api-reference/campaign-leads/registrar-um-lead-de-campanha.md). **Nota** Um ID de correlação não é uma URL de consulta de status. O contrato publicado não define um endpoint de consulta periódica para `trackingId` ou `requestId`. Guarde-o para correlação e suporte; não construa um novo endpoint a partir dele. ## Leia o formato de erro publicado pelo endpoint A API REST de integrações e Custom Connections têm contratos de erro separados. ### API REST de integrações Muitas respostas usam `Problem`: `title` e `status` são obrigatórios; `code`, `detail`, `errors`, `traceId`, `instance` e `extra` são opcionais. Quando `code` estiver presente, use-o para selecionar o tratamento de erro documentado, em vez de comparar o texto de `title`. Guarde `traceId`, quando fornecido, para pedir suporte. Algumas respostas de validação publicadas declaram `HTTPValidationError`, cujo `detail` é um array de entradas com `loc`, `msg` e `type`. Já o tratador compartilhado de erros da API revisado para esta documentação retorna os detalhes de validação em `Problem.errors[]`. As definições publicadas de resposta foram preservadas; a confirmação na API implantada ainda está pendente. Veja a [nota de compatibilidade de validação](https://docs.bridge.new/pt-br/error-codes.md#parse-validation-errors-defensively). Aceite erros JSON tanto com `application/json` quanto com `application/problem+json`. Examine `code`, quando presente, e depois um array `errors` ou `detail` para os erros de campo. Um `detail` do tipo string é uma explicação, não um array. O status `422` sozinho não define um formato universal de corpo. Mantenha um tratamento alternativo para erros sem `code` e use a referência do endpoint junto com [códigos de erro](https://docs.bridge.new/pt-br/error-codes.md) para escolher a ação. ### Custom Connections Seu corpo de erro contém `type`, `title` e `status` obrigatórios e pode incluir `detail`. Nesse contrato, **`type` é o identificador de erro legível por máquina**. Ele não é o campo REST `code`. A [referência de erros de Custom Connections](https://docs.bridge.new/pt-br/lead-capture/errors.md) lista essas respostas. As respostas de erro não contêm o `requestId` do envio; somente uma resposta bem-sucedida `202` contém esse valor. Para pedir suporte sobre um erro, guarde a URL da página e o horário aproximado, conforme a referência. ## Decida se deve tentar novamente por operação e causa | Resultado | Próxima ação | | --- | --- | | REST `429` | Siga `Retry-After` em segundos. O guia de limites informa que a requisição rejeitada não foi processada. A cota do workspace é compartilhada entre as chaves de API. | | REST `401` ou `403` | Corrija a chave de API, as permissões ou a divergência de workspace. Tentar novamente após um intervalo não corrige essas causas. | | Erro de validação ou configuração | Corrija primeiro a causa documentada. Não envie repetidamente a mesma requisição inválida. | | Custom Connections `422` | A causa documentada é a indisponibilidade do provedor de CAPTCHA. O guia de erros informa que é seguro tentar novamente; gere um novo token de CAPTCHA para a tentativa. | | Rejeição de CAPTCHA em Custom Connections | Confira se o token foi enviado, se é recente e se foi gerado para essa tentativa. O mesmo erro também abrange uma pontuação baixa; uma nova tentativa, sozinha, não comprova a causa original. | | Timeout, perda de conexão ou `5xx` não classificado durante uma alteração | Não presuma que nada aconteceu. Verifique os efeitos documentados da operação e os identificadores já obtidos antes de decidir repeti-la. Não presuma uma garantia geral de idempotência. | Veja [limites de requisições](https://docs.bridge.new/pt-br/rate-limits.md) para controlar o ritmo e [erros de Custom Connections](https://docs.bridge.new/pt-br/lead-capture/errors.md) para suas regras específicas de nova tentativa. ## Algumas falhas podem ocorrer depois de uma gravação A [referência de outbound de Agente](https://docs.bridge.new/pt-br/api-reference/agents-api/iniciar-conversa-de-sa%C3%ADda-com-um-contact-como-agent-espec%C3%ADfico.md) documenta que um `template.media.mediaId` desconhecido pode produzir `BRIDGE_AI_LEADSCOUT_0016` depois que a conversa já foi criada ou recuperada. Por isso, uma nova tentativa pode produzir um resultado diferente. Um status de falha, portanto, não é uma garantia universal de rollback. Siga os efeitos e as instruções de recuperação da operação específica. Se essas instruções forem pouco claras ou conflitantes, identifique a incerteza e entre em contato com o [suporte do Bridge](mailto:support@sainapsis.com) antes de repetir uma ação com efeitos externos. --- # Parâmetros de templates de WhatsApp Source: https://docs.bridge.new/pt-br/templates-and-parameters Abra uma conversa com seus próprios templates de WhatsApp, preencha as variáveis e trate os erros que a requisição pode retornar. ## Visão geral Ao criar uma conversa, `onboardingTemplates` permite escolher, em ordem, os templates de WhatsApp usados na abertura. Um template pode conter variáveis, como número de pedido, data de entrega ou nome do Contato. O Bridge preenche algumas delas para cada Contato; outras só você pode fornecer, enviando-as em `parameters` da entrada correspondente. O fluxo tem três etapas: 1. Consulte as variáveis do template. 2. Decida quais valores enviar. 3. Envie-os com `POST .../conversations`. **Nota** Todas as verificações descritas nesta página ocorrem antes de qualquer criação. Se a requisição for rejeitada, **nenhuma conversa é criada e nenhuma mensagem é enviada**. Você pode corrigi-la e enviá-la novamente. --- ## 1. Encontre as variáveis do template ```http GET /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId} x-api-key: YOUR_API_KEY ``` `templateId` aceita o `id` ou o `name` do template. A resposta lista suas variáveis: ```json { "id": "f0000040-0000-4000-8000-000000000040", "name": "order_shipped_promo", "language": "es", "driftWarning": { "hasDrift": false, "stale": [], "missingLabels": [] }, "variables": [ { "key": "first_name", "label": "Contact first name", "callerMustSupply": false, "isCustom": false, "default": null }, { "key": "order_number", "label": "Order number", "callerMustSupply": true, "isCustom": false, "default": null }, { "key": "delivery_date", "label": "Delivery date", "callerMustSupply": true, "isCustom": false, "default": null }, { "key": "tracking_code", "label": "Tracking code", "callerMustSupply": false, "isCustom": true, "default": "pending" } ] } ``` `driftWarning` é apenas diagnóstico: informa diferenças entre as variáveis declaradas e o snapshot do template na Meta e nunca bloqueia um envio. A tabela abaixo descreve cada item de `variables`. | Campo | Significado | | ----- | ------- | | `key` | O nome a usar em `parameters` | | `label` | Uma descrição da variável legível por pessoas | | `callerMustSupply` | `true` quando você precisa fornecer um valor não vazio porque o Bridge não tem uma fonte para ele; `false` nos demais casos | | `isCustom` | Indica se a variável é personalizada: um valor que só você conhece, com um texto padrão | | `default` | Para uma variável personalizada, o texto enviado quando você não fornece um valor; `null` nos demais casos | Um template que não pertence ao workspace retorna `404` com `BRIDGE_TEMPLATE_0001`. --- ## 2. Decida quais valores enviar | Variável | O que significa | O que fazer | | -------- | ------------- | ---------- | | `callerMustSupply: true` | O Bridge não tem uma fonte para esse valor | **Obrigatório.** Envie um valor não vazio para sua `key` | | `callerMustSupply: false`, `isCustom: false` | O Bridge preenche o valor para cada Contato, como o primeiro nome | **Opcional.** Omita-o para manter o valor do Bridge | | `isCustom: true` | Um valor que só você conhece, com um `default` | **Opcional.** Envie seu valor, omita-o ou envie-o vazio para usar o `default` | Um valor enviado para uma variável `callerMustSupply: false` substitui o valor do Bridge e é usado **para todos os Contatos** da conversa. **Aviso** Para uma variável não personalizada, mantenha o valor do Bridge **omitindo a chave**. Um valor vazio não significa "usar o padrão": ele é enviado como você o escreveu. Uma variável obrigatória vazia ou composta apenas de espaços é rejeitada como ausente. Somente variáveis personalizadas (`isCustom: true`) tratam um valor vazio como não enviado e usam seu `default`. --- ## 3. Envie os parâmetros Cada entrada de `onboardingTemplates` recebe o `id` do template retornado na etapa 1 e seus `parameters`, indexados pela `key` da variável. A posição na lista define a ordem de envio. ```http POST /bridge/api/v1/workspaces/{workspaceId}/conversations x-api-key: YOUR_API_KEY Content-Type: application/json ``` ```json { "participants": { "externals": [ { "identifier": "+13802098869", "identifierType": "PHONE", "messageProviderType": "WHATSAPP", "brandId": "YOUR_BRAND_ID" } ] }, "onboardingTemplates": [ { "templateId": "f0000040-0000-4000-8000-000000000040", "parameters": { "order_number": "A-10492", "delivery_date": "3 de octubre" } } ] } ``` Neste exemplo, `first_name` e `tracking_code` são omitidos. Assim, cada Contato recebe seu próprio primeiro nome, e `tracking_code` é enviado com seu valor padrão, `pending`. Limites por template: no máximo **50** parâmetros, chaves de até **128** caracteres e valores de até **1.024** caracteres. Requisições que ultrapassam esses limites são rejeitadas como malformadas; veja [erros](https://docs.bridge.new/pt-br/templates-and-parameters.md#errors). Conforme a configuração do workspace, seus templates substituem toda a sequência inicial ou apenas o primeiro template. No segundo caso, o restante da sequência configurada ainda é enviado depois dos seus. --- ## Regras de valores do WhatsApp O WhatsApp rejeita determinados valores no envio da mensagem. O Bridge os verifica antes para que a requisição falhe enquanto você ainda pode corrigi-los: | Regra | Limite | | ---- | ----- | | Quebras de linha e tabulações | Não permitidas: sem `\n`, `\r` ou `\t` | | Espaços consecutivos | No máximo quatro seguidos | | Cabeçalho | O texto do cabeçalho com o valor inserido deve caber em **60** caracteres | | Botão de URL | O link do botão com o valor inserido deve caber em **2.000** caracteres | | Corpo | O texto do corpo mais todos os valores deve caber em **1.024** caracteres | **Aviso** O limite do corpo inclui os valores que o Bridge preenche para cada Contato, como o primeiro nome. O Bridge só consegue verificar os valores disponíveis no momento da requisição; reserve espaço para os demais. O Bridge nunca remove espaços das extremidades nem reescreve seus valores: o que você envia é o que o Contato recebe. --- ## Erros Todos os erros usam o formato `application/problem+json` descrito em [códigos de erro](https://docs.bridge.new/pt-br/error-codes.md). Escolha o tratamento por `code`, nunca por `title`. | Código | Status | Quando ocorre | `extra` | | ---- | ------ | ---- | ------- | | `BRIDGE_CONVERSATION_0601` | 404 | O template não existe | `templateId`, `workspaceId` | | `BRIDGE_CONVERSATION_0602` | 400 | O template pertence a outro workspace | `templateId`, `workspaceId` | | `BRIDGE_CONVERSATION_0603` | 400 | O template não foi aprovado para a linha pela qual um participante será contatado | `templateId`, `workspaceId`, `userIds` (os Contatos cuja linha não tem aprovação, quando conhecidos) | | `BRIDGE_CONVERSATION_0604` | 422 | Uma variável obrigatória está ausente ou vazia | `templateId`, `missingVariables: [{key, label}]` | | `BRIDGE_CONVERSATION_0605` | 422 | Uma chave de `parameters` não está entre as variáveis do template | `templateId`, `unknownKeys: [key]` | | `BRIDGE_CONVERSATION_0606` | 422 | `parameters` foi enviado para um template que não é de WhatsApp | `templateId` | | `BRIDGE_CONVERSATION_0607` | 422 | Um valor viola uma [regra do WhatsApp](https://docs.bridge.new/pt-br/templates-and-parameters.md#whatsapp-value-rules) | `templateId`, `invalidVariables: [{key, label, reason}]` | | `BRIDGE_CONVERSATION_0608` | 422 | Um template enviado pelo workspace depois do seu exige valores que só o integrador pode fornecer | `templateId`, `origin: "WORKSPACE_CONFIGURATION"` | ### Valores ausentes — `0604` ```json { "title": "A template named in the onboarding override is missing values only the caller can provide", "status": 422, "detail": "A template named in the onboarding override is missing values only the caller can provide", "code": "BRIDGE_CONVERSATION_0604", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "missingVariables": [ { "key": "delivery_date", "label": "Delivery date" } ] } } ``` ### Valores inválidos — `0607` ```json { "title": "Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent", "status": 422, "detail": "Parameter values for an onboarding template break a WhatsApp rule and would be rejected when sent", "code": "BRIDGE_CONVERSATION_0607", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "invalidVariables": [ { "key": "order_number", "label": "Order number", "reason": "NEWLINE" } ] } } ``` `reason` informa a primeira regra violada pelo valor: | `reason` | Significado | | -------- | ------- | | `NEWLINE` | O valor contém `\n` ou `\r` | | `TAB` | O valor contém `\t` | | `CONSECUTIVE_SPACES` | O valor contém mais de quatro espaços seguidos | | `TOO_LONG` | O cabeçalho ou botão de URL ultrapassa o limite com o valor inserido | | `BODY_TOO_LONG` | O corpo ultrapassa 1.024 caracteres; todos os valores de corpo enviados são listados | ### O erro `0608` não se resolve alterando a requisição `BRIDGE_CONVERSATION_0608` ocorre somente em workspaces em que seus templates substituem apenas o primeiro template da sequência inicial. Isso significa que um template enviado pelo workspace depois do seu precisa de valores que só o integrador pode fornecer e que a API não consegue suprir. Peça a um administrador para alterar a sequência inicial. ### Requisições malformadas Uma requisição incompatível com o esquema — mais de 50 parâmetros, chave com mais de 128 caracteres, valor com mais de 1.024 caracteres ou campo desconhecido — é rejeitada com `422` **sem `code`**. Nesse caso, uma lista `errors` aponta cada problema: ```json { "title": "Unprocessable content", "status": 422, "errors": [ { "loc": ["body", "onboardingTemplates", 0, "parameters", "order_number"], "msg": "String should have at most 1024 characters", "type": "string_too_long" } ] } ``` ### Ordem de avaliação As verificações seguem esta ordem, e **o primeiro erro prevalece**: 1. Limite de requisições — `429` 2. Formato da requisição — `422` sem `code` 3. Participantes, marca e linha — `400` / `409`, por exemplo, `BRIDGE_BRAND_0101` ou `BRIDGE_PROVIDER_CHANNEL_0001` 4. Cada template, na ordem da lista: `0601` / `0602` → `0603` → `0606` → `0605` → `0604` → `0607` 5. `0608`, somente em workspaces onde seus templates substituem apenas o primeiro template Por isso, corrigir um erro pode revelar o próximo. Os valores de um template posterior só são verificados depois que todos os anteriores passam. --- ## Tópicos relacionados - [Criar uma conversa](https://docs.bridge.new/pt-br/api-reference/conversations-api/criar-conversa-com-identifica%C3%A7%C3%A3o-flex%C3%ADvel-de-usu%C3%A1rios.md) — Referência completa da requisição e resposta - [Códigos de erro](https://docs.bridge.new/pt-br/error-codes.md) — Todos os códigos, incluindo erros de marca e linha - [Limites de requisições](https://docs.bridge.new/pt-br/rate-limits.md) — Tratamento de `429` --- # Limites de requisições Source: https://docs.bridge.new/pt-br/rate-limits Quantas requisições a API Bridge aceita, quais cabeçalhos mostram a cota disponível e como tratar corretamente uma resposta 429. ## Visão geral A API Bridge aceita **50 requisições a cada 5 segundos**. O limite se aplica a todos os endpoints, está habilitado por padrão e não exige configuração. **Nota** A cota pertence ao **workspace**, não à chave de API. Se você emitir várias chaves para o mesmo workspace, uma por aplicação, como recomendado, todas compartilharão as mesmas 50 requisições. --- ## Consulte a cota disponível Toda resposta a uma requisição autenticada contém dois cabeçalhos, para que você saiba quanto ainda pode usar: ```http RateLimit-Policy: "default";q=50;w=5 RateLimit: "default";r=43;t=3 ``` | Campo | Significado | | ----- | ------- | | `q` | Requisições permitidas por janela | | `w` | Duração da janela em segundos | | `r` | Requisições **restantes** na janela atual | | `t` | Segundos até a janela reiniciar e `r` voltar a `q` | Um cliente que monitora `r` e pausa quando o valor se aproxima de zero evita rejeições por limite. **Nota** Uma requisição rejeitada **antes** da autenticação, por chave de API ausente ou inválida, não contém esses cabeçalhos. Veja essas respostas em [autenticação](https://docs.bridge.new/pt-br/credentials.md). --- ## Quando o limite é excedido As requisições acima da cota recebem `429 Too Many Requests`. Nada é processado, portanto é seguro repetir a requisição. ```http HTTP/1.1 429 Too Many Requests Content-Type: application/problem+json Retry-After: 3 RateLimit-Policy: "default";q=50;w=5 RateLimit: "default";r=0;t=3 ``` ```json { "title": "Too Many Requests", "status": 429, "detail": "The workspace has exhausted its request budget for the current window", "code": "BRIDGE_RATE_LIMIT_0001" } ``` `Retry-After` é expresso em **segundos a partir de agora**, não como uma data. Aguarde esse intervalo antes de fazer a próxima requisição. **Aviso** **Um `429` não é um problema de autenticação.** `401` e `403` significam que a chave de API está ausente, inválida, expirada ou sem autorização. **Repeti-los em intervalos não resolverá o problema** e apenas consumirá sua cota. Somente `429` deve ser repetido automaticamente, e apenas depois do intervalo informado. --- ## O que consome a cota Cada requisição HTTP conta como uma, inclusive as que terminam em erro de validação ou `404`. O que importa é quantas chamadas o cliente faz, não a quantidade de dados retornados. Essa diferença aparece nas leituras: - **Um único recurso por ID** — `GET .../contacts/{contactId}` — custa **uma requisição**, independentemente do tamanho da resposta. - **Uma lista** — `GET .../contacts` — custa **uma requisição por página**. Ler a lista inteira custa tantas requisições quantas forem suas páginas. Por isso, o tamanho da página determina o custo de uma leitura completa. Percorrer 500 contatos custa cinco requisições com 100 por página e 25 requisições com 20 por página: os mesmos dados, com cinco vezes mais consumo de cota. **Nota** Prefira o maior tamanho de página aceito pelo endpoint quando precisar ler a lista inteira. Se já souber qual recurso procura, leia-o diretamente pelo ID. --- ## Controle o ritmo na prática Um cliente que ajusta o ritmo com `RateLimit` e respeita `Retry-After` nas eventuais rejeições não precisa de outra lógica: ```python import time import requests BASE = "https://api-connect-us.bridge.new" HEADERS = {"x-api-key": "YOUR_API_KEY"} def rate_limit_state(response): header = response.headers.get("RateLimit", "") fields = dict(part.split("=", 1) for part in header.split(";") if "=" in part) return int(fields.get("r", 1)), int(fields.get("t", 1)) def get(path): while True: response = requests.get(f"{BASE}{path}", headers=HEADERS) if response.status_code == 429: time.sleep(int(response.headers["Retry-After"])) continue remaining, reset_in = rate_limit_state(response) if remaining == 0: time.sleep(reset_in) return response ``` ```javascript const BASE = "https://api-connect-us.bridge.new"; const HEADERS = { "x-api-key": "YOUR_API_KEY" }; const sleep = (seconds) => new Promise((done) => setTimeout(done, seconds * 1000)); function rateLimitState(response) { const fields = Object.fromEntries( (response.headers.get("RateLimit") ?? "") .split(";") .filter((part) => part.includes("=")) .map((part) => part.split("=")) ); return { remaining: Number(fields.r ?? 1), resetIn: Number(fields.t ?? 1) }; } async function get(path) { while (true) { const response = await fetch(`${BASE}${path}`, { headers: HEADERS }); if (response.status === 429) { await sleep(Number(response.headers.get("Retry-After"))); continue; } const { remaining, resetIn } = rateLimitState(response); if (remaining === 0) await sleep(resetIn); return response; } } ``` **Aviso** Não repita um `429` imediatamente nem use um intervalo fixo definido por conta própria. Repetir antes de `Retry-After` terminar causa nova rejeição, e um loop intenso de tentativas mantém a cota do workspace em zero para todas as outras aplicações que a compartilham. --- ## Padrões Esses campos não são exclusivos do Bridge: `RateLimit-Policy` e `RateLimit` seguem a especificação IETF de [campos de cabeçalho RateLimit](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/); `Retry-After` segue a [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html#field.retry-after); e o corpo do `429` segue a [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457.html). Se você já trata cabeçalhos `X-RateLimit-*` de outra API, esses são os equivalentes padronizados. Quando os dois divergirem, **`Retry-After` prevalece**: ele é o sinal que determina a nova tentativa, enquanto `RateLimit` orienta o ritmo das chamadas. --- ## Tópicos relacionados - [Autenticação](https://docs.bridge.new/pt-br/credentials.md) — Chaves de API e respostas `401` / `403` que não devem ser repetidas automaticamente - [Códigos de erro](https://docs.bridge.new/pt-br/error-codes.md) — Referência completa, incluindo `BRIDGE_RATE_LIMIT_0001` - [Referência da API REST](https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade.md) — Cada endpoint documenta sua resposta `429` --- # Códigos de erro Source: https://docs.bridge.new/pt-br/error-codes Interprete códigos de erro da API REST, respostas de validação e resultados incertos de gravações para escolher a próxima ação. ## Formato da resposta Exemplo de resposta `Problem`. Consulte na referência do endpoint o status HTTP, o tipo de mídia e o esquema da resposta: ```json { "title": "A template named in the onboarding override is missing values only the caller can provide", "status": 422, "detail": "A template named in the onboarding override is missing values only the caller can provide", "code": "BRIDGE_CONVERSATION_0604", "extra": { "templateId": "f0000040-0000-4000-8000-000000000040", "missingVariables": [{ "key": "delivery_date", "label": "Delivery date" }] }, "instance": "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/{workspaceId}/conversations", "traceId": "Root=1-6702b8c4-3f1a2b4c5d6e7f8091a2b3c4" } ``` | Campo | Significado | | ----- | ------- | | `code` | Quando presente, o código estável de erro listado nesta página. **Escolha o tratamento por esse campo, não pelo título.** Erros de validação e de servidor podem omiti-lo. | | `title` | Uma mensagem legível por pessoas. Ela pode ser mais longa que o título das tabelas abaixo; nunca use seu texto para identificar o erro | | `status` | O código de status HTTP | | `detail` | Mais detalhes sobre a ocorrência, quando disponíveis | | `extra` | Contexto do erro legível por máquina, como IDs ou chaves envolvidos, quando disponível | | `instance` | A URL da requisição | | `traceId` | Inclua-o ao entrar em contato com o suporte | **Nota** Leia o esquema de resposta da operação chamada. Quando ele for `HTTPValidationError`, os detalhes de validação estarão em um array `detail`; cada entrada contém `loc` (onde), `msg` (o quê) e `type`. Outras respostas `422` documentadas usam `Problem` e podem incluir `code` e `extra`. Não presuma que todas as respostas `422` tenham o mesmo formato. ### Interprete erros de validação de forma defensiva Aceite corpos de erro JSON tanto com `application/json` quanto com `application/problem+json`. Primeiro verifique o status HTTP; depois, examine o corpo: 1. Se `code` estiver presente, use a entrada correspondente desta página para escolher a ação. 2. Se `errors` for um array, leia suas entradas `loc`, `msg` e `type` como detalhes de validação. 3. Se `detail` for um array, interprete-o no formato `HTTPValidationError`. Um `detail` do tipo string é uma explicação, não uma lista de erros de campo. 4. Preserve `traceId`, o status e a URL da requisição para suporte. Não exija que `code` ou `extra` existam nem compare mensagens legíveis por pessoas como identificadores. Um campo inválido e uma regra que relaciona vários campos não precisam ter o mesmo status. As regras do corpo outbound revisadas geram `400` com `BRIDGE_CORE_0103` quando `consent.status` é `GRANTED` sem `capturedAt`, ou quando `template.media` fornece ambos ou nenhum de `mediaId` e `url`. Tipos de campo ou UUIDs inválidos podem gerar, por sua vez, detalhes de validação de requisição com `422`. Interprete o status e o corpo do erro juntos; não exija um array `errors` para toda requisição inválida. ### Códigos legados com sufixo Alguns tratadores de erro legados acrescentam um nome simbólico a `code`, por exemplo, `BRIDGE_PRELOAD_FILE_0002 | PRELOAD_FILE_IS_PENDING`. Preserve o valor recebido completo para logs e suporte. Para consultar o catálogo, aceite um código simples conhecido ou sua forma legada reconhecida explicitamente; não compare `title` ou `detail`, não invente um código desconhecido nem reescreva o corpo da resposta. Esta revisão do código-fonte não confirmou de forma independente qual versão do tratador está implantada. **Aviso** **Compatibilidade de validação:** algumas respostas OpenAPI publicadas declaram `HTTPValidationError.detail[]` e `application/json`, enquanto o tratador compartilhado de erros da API revisado para esta documentação retorna detalhes de validação como `Problem.errors[]` com `application/problem+json`. Esta atualização editorial preserva as definições de resposta publicadas. Trate os dois formatos; a confirmação na API implantada continua pendente antes de adotar um deles como único formato aceito por um cliente gerado estrito. ### Decida se deve tentar novamente | Resultado | Ação | | --- | --- | | `400` ou `422` | Corrija a requisição usando o código e os erros de campo. Repetir os mesmos dados não corrige a validação. | | `401` ou `403` | Confira credencial, workspace e permissões da integração correta. Mantenha as chaves da API REST no servidor. | | `404` | Confirme o identificador e o workspace. Uma consulta que não encontra um Contato é diferente de uma entrada malformada. | | `409` | Leia o código da operação: conversa existente, Agente indisponível e sessão não finalizada exigem soluções diferentes. Não habilite `forceSend` automaticamente. | | `429` | Siga os [cabeçalhos de limite e as orientações de espera](https://docs.bridge.new/pt-br/rate-limits.md). | | Timeout, desconexão da resposta ou `5xx` após uma gravação | Trate o resultado como incerto. Consulte o recurso afetado antes de reenviar: um erro não comprova que nenhum trabalho foi persistido. | As orientações gerais de nova tentativa não acrescentam idempotência a um endpoint. Para reutilização outbound, recuperação e gravações parciais, veja [outbound de Agente e transferência](https://docs.bridge.new/pt-br/guides/agent-outbound.md). Custom Connections tem sua própria [referência de erros](https://docs.bridge.new/pt-br/lead-capture/errors.md) e não usa chave da API REST. ## Erros ao responder a uma mensagem Para `POST .../messages`, as verificações revisadas da mensagem à qual você responde definem estas formas legadas adicionais: - `BRIDGE_MESSAGE_0001 | MESSAGE_NOT_FOUND` (`404`): o Message indicado em `replyToMessageId` não foi encontrado. - `BRIDGE_MESSAGE_0002 | MESSAGE_IS_NOT_ON_CONVERSATION` (`403`): a mensagem à qual você responde pertence a outra Conversation. Use uma da Conversation em que você enviará a mensagem. Preserve o `code` completo, incluindo seu sufixo simbólico. Essas verificações se referem à mensagem à qual você responde, não ao `mediaId` do anexo. ## Erros de upload de arquivos O fluxo de upload revisado define estes códigos legados. O sufixo faz parte do `code` recebido, não é um campo da requisição. Consulte o contrato de resposta da operação e mantenha a interpretação compatível acima. A operação determina quais erros de arquivo se aplicam: `POST .../files` verifica os metadados e pode retornar os códigos `0003` ou `0004` abaixo. `POST .../messages` pode retornar `0001` ou `0002` quando o `mediaId` de um anexo não existe ou ainda está pendente. Os arquivos de templates outbound têm seu próprio tratamento de erros; não substitua `BRIDGE_AI_LEADSCOUT_0016` por esses códigos. | `code` legado | Status | Ação | | --- | --- | --- | | `BRIDGE_PRELOAD_FILE_0001 \| PRELOAD_FILE_NOT_FOUND` | 404 | Confira o `mediaId` retornado e o upload referenciado. | | `BRIDGE_PRELOAD_FILE_0002 \| PRELOAD_FILE_IS_PENDING` | 400 | O arquivo ainda está pendente. Confirme que o PUT terminou e aguarde o processamento do upload; não conclua que uma requisição de Message com falha não persistiu nenhum trabalho. | | `BRIDGE_PRELOAD_FILE_0003 \| PRELOAD_FILE_INVALID_MIME_TYPE` | 400 | Corrija a combinação do tipo MIME e do `fileType` lógico. | | `BRIDGE_PRELOAD_FILE_0004 \| PRELOAD_FILE_INVALID_NAME` | 400 | Informe um nome com uma extensão aceita para esse `fileType` lógico. | ## Códigos de erro de Agentes Códigos de erro de operações de Agentes. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_AI_AGENT_OUTBOUND_0001` | Agente não encontrado | O Agente não foi encontrado no workspace | | `BRIDGE_AI_AGENT_OUTBOUND_0002` | Agente indisponível | O Agente não está disponível para outbound | | `BRIDGE_AI_AGENT_OUTBOUND_0003` | Tipo de Agente não aceito | O tipo de Agente não é aceito para outbound | | `BRIDGE_AI_AGENT_OUTBOUND_0004` | Agente sem canais | Nenhuma linha ativa de mensagens está vinculada ao Agente | | `BRIDGE_AI_AGENT_OUTBOUND_0005` | Agente não atribuído ao canal | O Agente não está atribuído ao canal solicitado | | `BRIDGE_AI_AGENT_OUTBOUND_0006` | Conversa controlada por outro Agente | A conversa ativa é controlada por outro Agente | | `BRIDGE_AI_AGENT_OUTBOUND_0007` | Cursor inválido | O cursor de paginação está malformado ou pertence a outro workspace | `POST .../agents/{agentId}/outbound` retorna `0001` e `0004` como `404`, `0002` e `0006` como `409`, e `0003` e `0005` como `422`. - `0002`: o Agente é um rascunho ou não tem linha. `extra.reason` informa qual é o caso; o mesmo motivo aparece como `unavailableReason` em `GET .../agents`. - `0006`: a conversa do Contato na linha selecionada pela requisição está sob o controle de outro Agente ou de um usuário do Bridge. Nada foi enviado. Libere-a com `POST .../conversations/{conversationId}/release`, usando `extra.conversationId`, e depois tente novamente. `extra` também contém `channelId` e, somente quando o controlador é um Agente, `controllingAgentId`. Quando o controlador é um usuário do Bridge, a chave está ausente, não é `null`. `GET .../agents` retorna `0007` como `400` quando o `cursor` está malformado ou foi emitido para outro workspace. Recomece sem cursor. Mantenha o mesmo filtro `type` durante a paginação: um cursor emitido com um filtro `type` é rejeitado se a requisição informar outro `type`. ### Outros códigos retornados por `POST .../agents/{agentId}/outbound` | Código | Status | Significado | | ---- | ------ | ------- | | `BRIDGE_CORE_0103` | 400 | A requisição é inválida: `consent.status` é `GRANTED` sem `capturedAt`, `template` não contém `id` nem `name`, ou `template.media` não contém exatamente um entre `mediaId` e `url` | | `BRIDGE_CORE_0301` | 403 | O workspace do caminho difere do workspace da chave de API | | `BRIDGE_AI_LEADSCOUT_0001` | 404 | O Contato não existe no workspace | | `BRIDGE_AI_LEADSCOUT_0002` | 404 | O usuário do Bridge de `handoffOverride` não existe no workspace | | `BRIDGE_AI_LEADSCOUT_0003` | 409 | O usuário do Bridge de `handoffOverride` foi excluído | | `BRIDGE_AI_LEADSCOUT_0004` | 404 | Nenhum template do workspace corresponde a `template.id` ou a `template.name`, quando nenhum ID é enviado | | `BRIDGE_AI_LEADSCOUT_0005` | 409 | Template não aprovado | | `BRIDGE_AI_LEADSCOUT_0006` | 400 | Os parâmetros ordenados do template não correspondem ao esperado | | `BRIDGE_AI_LEADSCOUT_0007` | 409 | Já existe uma conversa ativa: outra requisição assumiu primeiro a conversa liberada. Tente novamente | | `BRIDGE_AI_LEADSCOUT_0008` | 409 | Nenhuma linha do Agente está livre ou recuperável para esse Contato; veja `forceSend` | | `BRIDGE_AI_LEADSCOUT_0009` | 404 | Nenhuma linha configurada para o `brandId` solicitado | | `BRIDGE_AI_LEADSCOUT_0016` | 400 | Erro de validação outbound | | `BRIDGE_AI_LEADSCOUT_0017` | 409 | A sessão mais recente não foi finalizada | | `BRIDGE_AI_LEADSCOUT_0018` | 409 | Não foi possível finalizar a sessão expirada antes de iniciar uma nova | | `BRIDGE_AI_LEADSCOUT_0019` | 422 | Variáveis obrigatórias do template ausentes | | `BRIDGE_AI_LEADSCOUT_0020` | 422 | Fontes de parâmetros de template conflitantes para a mesma posição | | `BRIDGE_AI_LEADSCOUT_0021` | 422 | Chave de parâmetro de template desconhecida | Em `POST .../agents/{agentId}/outbound`, erros `5xx` não contêm `code` nem `extra`. ## Códigos de erro de LeadScout Códigos adicionais documentados para [iniciar uma conversa outbound de LeadScout](https://docs.bridge.new/pt-br/api-reference/leadscout-api/iniciar-conversa-de-sa%C3%ADda-do-leadscout-com-um-lead-conhecido.md) com `POST .../leadscout/outbound`: | Código | Status | Título | Significado | | --- | --- | --- | --- | | `BRIDGE_AI_LEADSCOUT_0010` | 404 | Canal fora do workspace | O canal de provedor não pertence ao workspace | | `BRIDGE_AI_LEADSCOUT_0011` | 404 | Nenhum canal de provedor | O workspace não tem canais de provedor | | `BRIDGE_AI_LEADSCOUT_0012` | 404 | Nenhum Agente para o canal | Não há Agente de prospecção para o canal | | `BRIDGE_AI_LEADSCOUT_0013` | 409 | Vários Agentes para a marca | Há vários Agentes de prospecção para a marca | | `BRIDGE_AI_LEADSCOUT_0014` | 409 | Vários Agentes para o canal | Há vários Agentes de prospecção para o canal | | `BRIDGE_AI_LEADSCOUT_0015` | 500 | Falha na operação de conversa | A operação de conversa falhou | ## Códigos de erro de marcas Códigos das verificações de marca na criação de uma conversa. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_BRAND_0101` | Marca obrigatória | O workspace tem marcas habilitadas; cada participante externo precisa ser associado a uma marca ou linha | Retornado como `400`. Envie `brandId` ou `providerChannelId` para cada participante externo; `extra.resources` lista os participantes que não tinham nenhum dos dois. ## Códigos de erro de conversas Códigos das operações de conversas. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_CONVERSATION_0001` | Conversa não encontrada | A conversa solicitada não foi encontrada | | `BRIDGE_CONVERSATION_0002` | Conversa fora do workspace | A conversa não pertence ao workspace informado | | `BRIDGE_CONVERSATION_0003` | Já existe conversa com os mesmos participantes | Já existe uma conversa ativa com os mesmos participantes | | `BRIDGE_CONVERSATION_0004` | Conversa inativa | A conversa está inativa; nenhuma operação pode ser realizada nela | | `BRIDGE_CONVERSATION_0005` | Falha na operação de conversa | Ocorreu um erro ao executar a operação na conversa | | `BRIDGE_CONVERSATION_0006` | Conversa em estado inconsistente | A conversa está em um estado inconsistente; contate o suporte para resolver | | `BRIDGE_CONVERSATION_0007` | Conversa liberada | A conversa está liberada; `409` de `POST .../messages` | | `BRIDGE_CONVERSATION_0101` | Usuário interno já está na conversa | O usuário interno já participa da conversa | | `BRIDGE_CONVERSATION_0102` | Usuário interno não está na conversa | O usuário interno não participa da conversa | | `BRIDGE_CONVERSATION_0103` | Usuário externo já está na conversa | O usuário externo já participa da conversa | | `BRIDGE_CONVERSATION_0104` | Usuário externo não está na conversa | O usuário externo não participa da conversa | | `BRIDGE_CONVERSATION_0105` | Usuário externo já usa o canal | O usuário externo já usa esse canal de mensagens em alguma conversa | | `BRIDGE_CONVERSATION_0201` | Participantes externos obrigatórios | É necessário pelo menos um participante externo para operar em uma conversa | | `BRIDGE_CONVERSATION_0202` | Participantes internos obrigatórios | É necessário pelo menos um participante interno para operar em uma conversa | | `BRIDGE_CONVERSATION_0203` | Usuário não é administrador | O usuário não é administrador desta conversa | | `BRIDGE_CONVERSATION_0204` | Remoção do último administrador não permitida | A conversa precisa ter pelo menos um administrador | | `BRIDGE_CONVERSATION_0205` | Mínimo de usuários internos | A conversa precisa ter uma quantidade mínima de participantes internos | | `BRIDGE_CONVERSATION_0206` | Máximo de participantes internos excedido | A conversa excedeu o máximo de participantes internos | | `BRIDGE_CONVERSATION_0207` | Mínimo de participantes externos | A conversa precisa ter uma quantidade mínima de participantes externos | | `BRIDGE_CONVERSATION_0208` | Máximo de participantes externos excedido | A conversa excedeu o máximo de participantes externos | | `BRIDGE_CONVERSATION_0210` | Quantidade mínima de participantes | A conversa precisa ter uma quantidade mínima de participantes | | `BRIDGE_CONVERSATION_0211` | Quantidade máxima de participantes | A conversa precisa respeitar uma quantidade máxima de participantes | | `BRIDGE_CONVERSATION_0212` | Máximo de mensagens iniciais excedido | A quantidade máxima de mensagens iniciais foi excedida | | `BRIDGE_CONVERSATION_0213` | Mensagens fora da conversa | As mensagens precisam pertencer à mesma conversa | | `BRIDGE_CONVERSATION_0601` | Template inicial não encontrado | Um template informado na substituição da sequência inicial não existe | | `BRIDGE_CONVERSATION_0602` | Template inicial fora do workspace | Um template informado na substituição da sequência inicial pertence a outro workspace | | `BRIDGE_CONVERSATION_0603` | Template inicial não aprovado | Um template informado na substituição da sequência inicial não foi aprovado para a linha de um participante | | `BRIDGE_CONVERSATION_0604` | Parâmetros ausentes no template inicial | Um template da sequência inicial exige valores que só o integrador pode fornecer | | `BRIDGE_CONVERSATION_0605` | Parâmetros desconhecidos no template inicial | A substituição da sequência inicial informa parâmetros não declarados pelo template | | `BRIDGE_CONVERSATION_0606` | Parâmetros não aceitos pelo template inicial | Foram enviados parâmetros para um template inicial que não é um template de provedor WhatsApp | | `BRIDGE_CONVERSATION_0607` | Valores inválidos no template inicial | Valores do template inicial violam uma regra do WhatsApp e seriam rejeitados no envio | | `BRIDGE_CONVERSATION_0608` | Template configurado exige valores do integrador | Um template da sequência inicial do workspace precisa de valores que só o integrador pode fornecer; um administrador deve alterar a sequência | Ao criar uma conversa, `BRIDGE_CONVERSATION_0105` retorna `409` com `extra.reason` igual a `PARTICIPANTS_MISMATCH`: uma conversa liberada ocupa a linha do Contato com outros Contatos ou linhas. Solicite os mesmos Contatos e linhas ou use outra linha. `BRIDGE_CONVERSATION_0601` retorna `404`, `0602` e `0603` retornam `400`, e de `0604` a `0608` retornam `422`. Veja em [parâmetros de templates iniciais](https://docs.bridge.new/pt-br/templates-and-parameters.md) o conteúdo de `extra` de cada erro e como corrigi-lo. ## Códigos de erro de usuários externos Códigos das operações de usuários externos, ou Contatos. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_EXTERNAL_0001` | Usuário externo não encontrado | O usuário externo solicitado não foi encontrado | | `BRIDGE_EXTERNAL_0002` | Usuário externo já existe | Já existe um usuário externo com os mesmos dados de identificação | | `BRIDGE_EXTERNAL_0004` | Usuário externo fora do workspace | Um ou mais usuários externos não pertencem ao workspace informado | | `BRIDGE_EXTERNAL_0005` | Campo não configurado no usuário externo | O usuário externo não tem um campo configurado; confira as configurações do workspace ou das informações externas | | `BRIDGE_EXTERNAL_0007` | Celular pertence a outro Contato | O telefone já é uma identidade ativa de outro usuário externo | | `BRIDGE_EXTERNAL_0013` | E-mail pertence a outro Contato | O e-mail já é uma identidade ativa de outro usuário externo | | `BRIDGE_EXTERNAL_0101` | Falha na operação de usuário externo | Ocorreu um erro ao executar a operação no usuário externo | ## Códigos de erro de usuários internos Códigos das operações de usuários internos. | Código | Título legível | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_INTERNAL_0001` | Usuário interno não encontrado | O usuário interno não foi encontrado | | `BRIDGE_INTERNAL_0002` | Usuários internos fora do workspace | Os usuários internos informados não pertencem ao workspace especificado | | `BRIDGE_INTERNAL_0003` | Usuário interno inativo | Um ou mais usuários internos estão inativos; confira o status do usuário nas configurações do workspace | | `BRIDGE_INTERNAL_0004` | Campo não configurado no usuário interno | O usuário interno não tem um campo configurado; confira as configurações do workspace ou das informações internas | | `BRIDGE_INTERNAL_0101` | Operação não aceita pelo usuário interno | O usuário interno não aceita essa operação | ## Códigos de erro de canais de provedor Códigos das operações de canais de provedor. | Código | Título legível | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_PROVIDER_CHANNEL_0001` | Canal de provedor não encontrado | O canal de provedor não foi encontrado; verifique se o workspace tem canais configurados | Ao criar uma conversa, esse código é retornado como `409` quando nenhuma linha de WhatsApp está livre para um Contato e não há uma conversa liberada para recuperar, ou quando o `providerChannelId` informado não está disponível para esse Contato. ## Códigos de limite de requisições Códigos retornados quando um workspace excede a cota de requisições. Veja em [limites de requisições](https://docs.bridge.new/pt-br/rate-limits.md) a cota, os cabeçalhos e um cliente que controla seu ritmo. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_RATE_LIMIT_0001` | Requisições em excesso | O workspace esgotou a cota de requisições da janela atual | Esse é o único código que deve ser repetido automaticamente, e apenas após o intervalo informado no cabeçalho `Retry-After`. Falhas de autenticação não são erros de limite, e repeti-las periodicamente não resolverá o problema. ## Códigos de erro de requisição Códigos retornados antes de executar a operação, quando a própria requisição não pode ser processada. Veja no [histórico de alterações](https://docs.bridge.new/pt-br/changelog.md) os parâmetros que um endpoint deixará de aceitar. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_CORE_0101` | Formato de campo inválido | O formato do campo é inválido; forneça um valor válido | | `BRIDGE_CORE_0102` | Campo obrigatório ausente | A requisição não contém campos obrigatórios; revise a operação | | `BRIDGE_CORE_0103` | Requisição inválida | A requisição é inválida; revise o corpo e os parâmetros | | `BRIDGE_CORE_0104` | Cursor inválido | O cursor fornecido é inválido; use um cursor obtido em uma resposta anterior | Nenhum desses erros deve ser repetido sem alterações. `detail` descreve o problema e, quando possível, identifica o campo ou parâmetro incorreto; a mesma requisição falhará da mesma forma até ser corrigida. ## Códigos de erro de templates Códigos das operações de templates. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_TEMPLATE_0001` | Template de provedor não encontrado | Nenhum template de provedor encontrado para o workspace e nome informados | Retornado como `404` por `GET .../templates/{templateId}` quando o ID ou nome não corresponde a um template de WhatsApp do workspace. ## Códigos de erro de workspace Códigos das operações de workspace. | Código | Título | Mensagem | | ---- | -------------- | ------- | | `BRIDGE_WORKSPACE_0001` | Workspace não encontrado | O workspace solicitado não foi encontrado | | `BRIDGE_WORKSPACE_0002` | Workspace fora da organização | O workspace não pertence à organização informada | | `BRIDGE_WORKSPACE_0003` | Workspace sem canais de provedor disponíveis | O workspace não tem canais de provedor disponíveis | | `BRIDGE_WORKSPACE_0004` | Campo não configurado no workspace | O workspace não tem um campo configurado; `409` de `POST .../conversations/{conversationId}/release` | --- # Histórico de alterações Source: https://docs.bridge.new/pt-br/changelog Mudanças da API Bridge que afetam sua integração, das mais recentes para as mais antigas. ## Visão geral Mudanças que afetam as chamadas que você já faz, das mais recentes para as mais antigas. Alterações aditivas, como um novo endpoint ou campo opcional, não são listadas aqui, exceto quando substituem algo que será removido; elas aparecem na referência da [API REST](https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade.md) quando são disponibilizadas. **Nota** As entradas antigas abaixo não registraram datas de vigência. As datas de implantação não foram verificadas, e a ordem das entradas não define uma data de lançamento. A data de remoção dos filtros de lista obsoletos **ainda não foi anunciada**. Continue usando o contrato atual documentado até a publicação de uma mudança efetiva e use os endpoints de consulta disponíveis em novas integrações. ## Melhorias na documentação Esta revisão esclarece o contrato existente da API e apresenta guias de integração por tarefa. Ela renomeia o recurso de landing pages para **Custom Connections**, explica a reutilização e a recuperação de conversas outbound e melhora as orientações de erros e webhooks. As assinaturas existentes da API e as URLs de documentação `/lead-capture` são preservadas. A data de revisão da documentação não é uma data de implantação ou descontinuação da API. --- ## A criação de uma conversa pode recuperar uma conversa liberada `POST /conversations` costumava retornar `409 BRIDGE_PROVIDER_CHANNEL_0001` quando nenhuma linha estava livre. Agora, se os Contatos solicitados tiverem uma conversa liberada com recuperação, ela é recuperada e retornada com `201` e seu `id` existente. Portanto, você pode receber um `id` que já armazenou. Se essa conversa tiver outros Contatos ou linhas, a requisição retorna `409 BRIDGE_CONVERSATION_0105`. Veja os detalhes na referência da [API REST](https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade.md). --- ## Encontre um contato ou usuário por um identificador **Aviso** **Essa mudança removerá parâmetros de query que existem hoje.** Eles ainda funcionam e estão marcados como obsoletos na referência da [API REST](https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade.md). A data em que deixarão de ser aceitos será publicada aqui antes da mudança; os endpoints de consulta que os substituem já estão disponíveis. ### O que muda **Disponível agora:** `GET /contacts/lookup` e `GET /users/lookup` retornam um contato ou usuário do Bridge — chamado de usuário interno na referência da API — por um identificador. **Obsoleto, com remoção prevista:** os endpoints de listagem deixarão de filtrar. `GET /contacts` e `GET /users` manterão apenas `limit` e `cursor`. | Parâmetro obsoleto | Substituição | | ------- | ----------- | | `GET /contacts?search=` — um telefone celular | `GET /contacts/lookup?type=PHONE&value=…` | | `GET /contacts?search=` — um e-mail | `GET /contacts/lookup?type=EMAIL&value=…` | | `GET /contacts?search=` — um nome | **Nenhuma** | | `GET /contacts?ownerEmail=` | **Nenhuma** | | `GET /users?email=` | `GET /users/lookup?type=EMAIL&value=…` | | `GET /users?status=` | **Nenhuma** — cada linha já contém `status` | Depois da remoção, o parâmetro será **rejeitado**, não ignorado. Enviá-lo retornará `400` com `BRIDGE_CORE_0103`, e a resposta identificará o parâmetro. Essa decisão é intencional: uma chamada que ignorasse silenciosamente o filtro retornaria a primeira página de todo o workspace, permitindo que você a interpretasse como um resultado correspondente à busca. ### O que fazer **Se você pesquisa por celular ou e-mail**, migre para o endpoint de consulta correspondente. Ele retorna o mesmo objeto que a lista fornece em cada linha e retorna `404` quando não há correspondência. `type` aceita os tipos de identificador já usados pela API em outros contextos: os mesmos valores de `identifierType` de um participante de conversa. Contatos aceitam `ID`, `EMAIL` e `PHONE`; usuários do Bridge aceitam `ID` e `EMAIL`, pois o celular de um usuário interno não é um identificador consultável no Bridge. `ID` é aceito pelo mesmo motivo: um código que já trabalha com o par `{identifierType, identifier}` não deve precisar tratar um dos valores de forma diferente para montar outra URL. Ele retorna exatamente o mesmo resultado de `GET /contacts/{contactId}`, que continua sendo a URL canônica de um contato. Prefira essa URL quando já tiver o ID. ```bash # Before curl "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts?search=%2B14084029292" \ -H "x-api-key: $BRIDGE_API_KEY" # After curl "https://api-connect-us.bridge.new/bridge/api/v1/workspaces/$WORKSPACE/contacts/lookup?type=PHONE&value=%2B14084029292" \ -H "x-api-key: $BRIDGE_API_KEY" ``` Um `PHONE` é interpretado da mesma forma que o celular enviado na criação de um contato: números sem código de país usam o país padrão do workspace, e espaços e separadores são ignorados. Em um `EMAIL`, o domínio é convertido para minúsculas, mas a parte local é comparada exatamente como foi enviada. **Nota** Um celular em formato internacional começa com `+`, que precisa ser codificado como `%2B` na query string. A maioria dos clientes HTTP faz isso quando você fornece os parâmetros em um mapa, em vez de montar a URL manualmente. Um `value` incompatível com seu `type`, como e-mail, celular ou UUID malformado, é rejeitado com `422` e `BRIDGE_CORE_0101` antes de qualquer consulta. Trate esse caso separadamente de `404` se repassar diretamente dados informados por usuários: um significa *você enviou algo que não é um identificador*; o outro, *ninguém neste workspace tem esse identificador*. **Se você filtra usuários do Bridge por status**, leia `status` em cada linha. Ele é calculado, não armazenado, e já aparece em todas as respostas. Hoje, a lista retorna apenas usuários ativos, a menos que você envie `status`; após a remoção do parâmetro, ela retornará usuários ativos e desabilitados. O mesmo vale para `GET /users/lookup`: ele retorna o usuário do Bridge ativo ou desabilitado, priorizando o ativo quando um e-mail corresponde aos dois. Hoje, `GET /users?email=` não retorna um usuário desabilitado. Portanto, confira `status` na resposta se sua aplicação deve agir apenas sobre usuários ativos. **Se você pesquisa contatos por nome**, não haverá substituição; entenda o que deixará de estar disponível. O parâmetro encontra apenas o **nome completo exato**: primeiro nome, um espaço e sobrenome. Ele nunca encontra prefixos, trechos do nome ou apenas o sobrenome. Se funciona no seu caso, você já está fornecendo o nome completo. **Se você filtra contatos por responsável**, não haverá substituição. Liste a página e filtre por `ownerId` no seu próprio código. `ownerId` é o ID do usuário do Bridge responsável pelo contato, não um e-mail. Obtenha-o uma vez com `GET /users/lookup?type=EMAIL&value=…` e compare com seu `id`. ### Por quê Filtrar por esses parâmetros faz o custo da chamada depender do tamanho do workspace, não do tamanho da resposta. Buscar um contato por telefone em um workspace grande exige ler dezenas de milhares de registros para retornar um único resultado. Pedir uma página maior torna a operação mais lenta, não mais rápida. Os endpoints de consulta leem apenas os registros que contêm o identificador. Por isso, os filtros estão sendo removidos, em vez de corrigidos: quando existe uma substituição, ela é estritamente melhor. A pesquisa por nome, que não tem substituição, nunca encontrou nada além do nome completo exato. --- ## Tópicos relacionados - [Códigos de erro](https://docs.bridge.new/pt-br/error-codes.md) — Referência completa, incluindo `BRIDGE_CORE_0103` e `BRIDGE_CORE_0101` - [Referência da API REST](https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade.md) — Endpoints de consulta, seus parâmetros e respostas - [Limites de requisições](https://docs.bridge.new/pt-br/rate-limits.md) — Cota por workspace e como respeitar os intervalos de nova tentativa --- # Receba webhooks do Bridge Source: https://docs.bridge.new/pt-br/webhooks Conecte um receptor HTTPS aos eventos do Bridge e entenda autenticação, confirmação de recebimento e processamento assíncrono. Webhooks enviam eventos **do Bridge para seu sistema**. Configure um callback HTTPS e assine as famílias de eventos de que sua integração precisa. O Bridge envia JSON usando `POST`; seu receptor autentica e armazena o evento antes de retornar `2xx`. Use a [API REST de integrações](https://docs.bridge.new/pt-br/credentials.md) quando seu sistema precisar ler ou alterar um recurso do Bridge. Uma assinatura de webhook, sozinha, não cria uma integração bidirecional completa com o CRM: seu receptor precisa mapear identificadores, processar o evento e implementar qualquer gravação de volta desejada por meio da operação REST documentada. ## Implemente o receptor ### Escolha os eventos Leia a [referência de eventos](https://docs.bridge.new/pt-br/webhooks/events.md) e selecione a família e a versão de assinatura adequadas ao seu fluxo. ### Verifique e armazene cada requisição Siga o guia de [verificação de assinaturas](https://docs.bridge.new/pt-br/webhooks/verifying-signatures.md) para a serialização HMAC exata e o de [recebimento de eventos](https://docs.bridge.new/pt-br/webhooks/receive-events.md) para um exemplo de caixa de entrada persistente. ### Configure e teste o callback Informe a URL, a chave de API do webhook e o segredo do cliente no [console administrativo do Bridge](https://docs.bridge.new/pt-br/webhooks/configuration.md). Verifique o callback de teste antes de ativar seu fluxo de negócio. ```mermaid sequenceDiagram participant B as Bridge participant R as Seu receptor participant I as Caixa de entrada persistente participant W as Seu processador B->>R: POST do evento JSON e cabeçalhos de autenticação R->>R: Verifica a chave de API, o HMAC e a política de validade R->>I: Grava o evento verificado ou confirma a duplicata exata I-->>R: Aceitação persistente R-->>B: Confirmação 2xx W->>I: Lê os eventos pendentes W->>W: Aplica a ação de negócio de forma idempotente ``` ## Mantenha as credenciais separadas | Cabeçalho | Finalidade | | --- | --- | | `X-Bridge-API-Key` | Chave de API do webhook configurada para esse callback. Compare-a com o valor esperado. | | `X-Bridge-Signature` | `sha256=` seguido do HMAC-SHA256 da representação canônica do evento do Bridge, usando o segredo do cliente do webhook. | | `X-Bridge-Timestamp` | Segundos Unix usados na verificação de validade temporal pelo receptor. O HMAC **não** inclui esse cabeçalho. | Essas credenciais de webhook são separadas da `x-api-key` da API REST e da `captureKey` de Custom Connections usada no navegador. Mantenha o segredo do cliente do webhook no servidor. ## O que a confirmação de recebimento significa Uma resposta `2xx` significa que seu receptor aceitou o evento. Ela não comprova que a atualização do CRM ou outra ação de negócio terminou. Persista primeiro e processe fora da requisição, para que um serviço posterior lento não atrase a confirmação. O emissor HTTP atual faz três tentativas por operação de entrega, com esperas de um e dois segundos e timeout padrão de dez segundos no socket. Isso não é uma promessa de apenas três tentativas em todo o fluxo do evento. Leia as [regras de novas tentativas, duplicatas e ordenação](https://docs.bridge.new/pt-br/webhooks/receive-events.md) antes de escolher sua política de recuperação. Não presuma entrega exatamente uma vez, ordem global de eventos ou um endpoint público de reenvio. A [referência de eventos](https://docs.bridge.new/pt-br/webhooks/events.md) descreve os payloads; o [guia do receptor](https://docs.bridge.new/pt-br/webhooks/receive-events.md) explica como tratá-los de forma confiável. --- # Verifique requisições de webhook Source: https://docs.bridge.new/pt-br/webhooks/verifying-signatures Verifique a chave de API do webhook e a representação HMAC exata usada pelo Bridge e elimine eventos aceitos repetidos. Verifique cada requisição antes de aceitá-la no seu sistema. Use a chave de API e o segredo do cliente do **webhook** configurados para esse callback; eles são separados da chave da API REST de integrações. ## Cabeçalhos de autenticação | Cabeçalho | Verificação | | --- | --- | | `X-Bridge-API-Key` | Comparação em tempo constante com a chave de API do webhook configurada | | `X-Bridge-Signature` | `sha256=` seguido do digest hexadecimal HMAC-SHA256 em letras minúsculas | | `X-Bridge-Timestamp` | Segundos Unix dentro da janela temporal aceita; o exemplo permite cinco minutos para o passado ou para o futuro | Os nomes dos cabeçalhos não diferenciam maiúsculas de minúsculas. ## Exatamente o que é assinado O Bridge constrói a entrada do HMAC a partir do evento JSON usando a expressão Python abaixo e depois codifica a string em UTF-8: ```python json.dumps(event, sort_keys=True).encode("utf-8") ``` Ela ordena recursivamente as chaves dos objetos, preserva a ordem dos arrays, aplica escapes a caracteres não ASCII e usa os espaços padrão do Python após vírgulas e dois-pontos. Não acrescenta uma quebra de linha. A chave é o segredo do cliente codificado em UTF-8. Essa é uma convenção de serialização JSON do Python, não RFC 8785 / JCS. Não a substitua por um digest dos bytes brutos arbitrários da requisição, JSON compacto, um `JSON.stringify` genérico do JavaScript ou uma string prefixada pelo timestamp. Espaços, escapes Unicode e formatação de números podem mudar a entrada do HMAC mesmo quando o objeto interpretado parece equivalente. Use o verificador Python abaixo ou teste outra implementação com o vetor antes de conectá-la. **Aviso** A entrada atual do HMAC contém apenas o JSON do evento. **`X-Bridge-Timestamp` não está incluído na assinatura.** Verifique a validade temporal, mas não trate o timestamp sozinho como proteção criptográfica contra reenvio: um payload e uma assinatura anteriormente válidos podem ser apresentados com outro timestamp. Autentique a chave de API do webhook e use uma caixa de entrada persistente e processamento idempotente de negócio, conforme o guia de [recebimento de eventos](https://docs.bridge.new/pt-br/webhooks/receive-events.md). ## Verificador Python Salve como `bridge_webhooks.py`. Ele retorna o objeto interpretado e verificado para que o código posterior use a mesma interpretação que foi autenticada. Obtenha os segredos de variáveis de ambiente do servidor ou do seu armazenamento de segredos. ```python import hashlib import hmac import json import re import sqlite3 import time class VerificationError(ValueError): pass def canonical_payload(event): # Match Bridge's Python json.dumps defaults: sort recursively, ASCII escapes, # a space after commas and colons, then UTF-8. This is not RFC 8785 / JCS. return json.dumps(event, sort_keys=True).encode("utf-8") def _unique_object(pairs): result = {} for key, value in pairs: if key in result: raise VerificationError("Duplicate JSON object key") result[key] = value return result def verify_webhook(raw_body, headers, webhook_api_key, client_secret, *, now=None, tolerance=300): headers = {key.lower(): value for key, value in headers.items()} received_key = headers.get("x-bridge-api-key", "") if not received_key or not webhook_api_key or not client_secret: raise VerificationError("Missing webhook credentials") if not hmac.compare_digest(received_key.encode("utf-8"), webhook_api_key.encode("utf-8")): raise VerificationError("Invalid webhook API key") received_signature = headers.get("x-bridge-signature", "") if not re.fullmatch(r"sha256=[0-9a-f]{64}", received_signature): raise VerificationError("Invalid signature format") timestamp = headers.get("x-bridge-timestamp", "") if not re.fullmatch(r"[0-9]+", timestamp): raise VerificationError("Invalid timestamp") current_time = time.time() if now is None else now if abs(current_time - int(timestamp)) > tolerance: raise VerificationError("Timestamp outside the permitted window") try: event = json.loads(raw_body.decode("utf-8"), object_pairs_hook=_unique_object) except (UnicodeDecodeError, json.JSONDecodeError) as exc: raise VerificationError("Invalid JSON body") from exc if not isinstance(event, dict): raise VerificationError("Expected a JSON object") expected = "sha256=" + hmac.new( client_secret.encode("utf-8"), canonical_payload(event), hashlib.sha256 ).hexdigest() if not hmac.compare_digest(expected, received_signature): raise VerificationError("Invalid webhook signature") return event ``` A janela de cinco minutos é uma política do receptor; mantenha o relógio do servidor sincronizado. O verificador também rejeita chaves JSON duplicadas e ambíguas. Não desative a autenticação ao investigar uma divergência: confira as credenciais configuradas e compare a entrada canônica com os dados de teste abaixo. ## Vetor de assinatura reproduzível Estes valores são dados de teste sintéticos, não credenciais reais nem um evento para enviar ao Bridge. Ao testar a validade temporal, defina o argumento `now` do verificador como `1800000000`. | Valor | Dado de teste | | --- | --- | | Segredo do cliente | `bridge-docs-test-secret` | | Chave de API do webhook | `bridge-docs-test-key` | | Cabeçalho de timestamp | `1800000000` | | Assinatura esperada | `sha256=5536c29fd98baab6ffe46dd9517adb185b32202864cbb5a76146172fc0b39423` | Objeto do evento: ```json { "eventId": "evt_docs_001", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_docs", "timestamp": "2026-01-01T00:00:00Z", "payload": { "name": "José", "tags": [ "café", "one" ], "active": true, "count": 2 } } ``` String JSON exata assinada (as sequências `\u` abaixo são barras invertidas ASCII literais, não caracteres decodificados): ```text {"entity": "contact", "eventId": "evt_docs_001", "eventType": "contact.updated", "payload": {"active": true, "count": 2, "name": "Jos\u00e9", "tags": ["caf\u00e9", "one"]}, "timestamp": "2026-01-01T00:00:00Z", "workspaceId": "ws_docs"} ``` Alterar um campo deve fazer a verificação falhar. Mudar apenas a ordem das chaves de entrada ou enviar Unicode literal em vez de escapes Unicode JSON ainda deve ser validado após interpretar e reconstruir a mesma representação canônica. ## Após a verificação Confirme a gravação do evento em uma caixa de entrada persistente antes de responder. Um HMAC válido confirma a representação autenticada do evento; não comprova que a ação de negócio foi executada, que o evento é novo ou que representa o estado mais recente do recurso. Continue com [entrega, duplicatas e ordenação](https://docs.bridge.new/pt-br/webhooks/receive-events.md). --- # Receba eventos de forma confiável Source: https://docs.bridge.new/pt-br/webhooks/receive-events Verifique, persista e confirme webhooks; depois processe com segurança duplicatas e eventos fora de ordem. Um receptor de webhooks tem duas responsabilidades: aceitar rapidamente um evento autenticado e processá-lo de forma confiável. Mantenha chamadas lentas ao CRM, enriquecimento e outras tarefas de negócio fora da requisição HTTP. ## Receba → verifique → persista → confirme 1. Leia o corpo e os cabeçalhos da requisição. 2. Verifique a chave de API do webhook, o HMAC canônico e a política de timestamp com o [verificador](https://docs.bridge.new/pt-br/webhooks/verifying-signatures.md). 3. Armazene atomicamente o evento verificado em uma caixa de entrada persistente ou confirme que esse evento exato já está armazenado. 4. Retorne uma resposta `2xx` prontamente. Processe os eventos armazenados em um worker e torne cada ação de negócio idempotente. Retorne sucesso somente após a aceitação persistente. Se o armazenamento estiver indisponível, retorne uma resposta diferente de `2xx` para não confirmar a tentativa de entrega. Uma duplicata já armazenada deve receber `2xx` novamente. ## Regras de novas tentativas O emissor atual faz até **três tentativas HTTP** para uma operação de entrega. Ele espera **um segundo** e depois **dois segundos** antes das tentativas restantes. Qualquer resposta `2xx` encerra essas tentativas. Uma resposta diferente de `2xx`, uma falha de conexão ou uma exceção na requisição pode acionar a próxima tentativa. O timeout padrão do socket é de **10 segundos** por tentativa; confirme em poucos segundos, em vez de contar com uma tolerância de 30 segundos. O payload, a assinatura e os cabeçalhos de timestamp são reutilizados nessa operação de entrega. Essas três tentativas limitam uma operação de envio, **não o total de todas as entregas de um evento ao longo do fluxo**. Se um evento anterior for entregue novamente, ele poderá acionar o emissor outra vez. Não há aqui promessa de um número total de tentativas ou de um prazo máximo para reenvios. Não conte com o cabeçalho de resposta `Retry-After` para definir o intervalo das tentativas do Bridge. Se todas as tentativas falharem, a entrega é considerada malsucedida. Não presuma repetição automática indefinida nem um endpoint público de reenvio. Para investigar, guarde o workspace, o tipo, o ID e o horário aproximado do evento e entre em contato com o suporte do Bridge. Não inclua credenciais de webhook em mensagens de suporte ou logs da aplicação. ## Duplicatas e identidade do evento Seu serviço pode ter confirmado a gravação de um evento mesmo que o Bridge não tenha recebido sua resposta `2xx`. Uma nova tentativa não deve causar outra atualização do CRM, fatura, mensagem ou outro efeito de negócio. Delimite o registro da caixa de entrada por `workspaceId`, `eventType` e `eventId`. Armazene também um digest do evento verificado. Não presuma que `eventId` seja globalmente único em todas as famílias de notificação: algumas usam um ID derivado da entidade. Preserve payloads diferentes que compartilhem um ID e aplique idempotência de negócio à operação executada pelo worker. O exemplo abaixo elimina repetições exatas usando os três identificadores e a impressão digital SHA-256 do evento canônico. Essa é uma chave da caixa de entrada deste exemplo, não um novo campo de requisição do Bridge. Não expire um registro de deduplicação apenas porque a janela de cinco minutos do timestamp terminou. Esse cabeçalho não é assinado, portanto a janela não define um prazo seguro de expiração para proteção contra reenvios. Escolha a retenção conforme suas necessidades de conciliação de negócio e mantenha as ações no destino idempotentes. O exemplo não exclui registros da caixa de entrada automaticamente. ## Receptor persistente mínimo Adicione estas definições ao módulo `bridge_webhooks.py` do guia [verifique requisições de webhook](https://docs.bridge.new/pt-br/webhooks/verifying-signatures.md). O módulo do verificador já inclui as importações usadas abaixo. ```python class SQLiteInbox: """Single-service example inbox. Use a shared durable store for multiple replicas.""" def __init__(self, path): self.path = str(path) with sqlite3.connect(self.path) as db: db.execute("""CREATE TABLE IF NOT EXISTS webhook_inbox ( workspace_id TEXT NOT NULL, event_type TEXT NOT NULL, event_id TEXT NOT NULL, fingerprint TEXT NOT NULL, body TEXT NOT NULL, received_at REAL NOT NULL, processed INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(workspace_id, event_type, event_id, fingerprint) )""") def accept(self, event): identifiers = [event.get(key) for key in ("workspaceId", "eventType", "eventId")] if not all(isinstance(value, str) and value for value in identifiers): raise VerificationError("Missing event envelope identifiers") body = canonical_payload(event) fingerprint = hashlib.sha256(body).hexdigest() with sqlite3.connect(self.path, timeout=3) as db: cursor = db.execute( """INSERT OR IGNORE INTO webhook_inbox (workspace_id, event_type, event_id, fingerprint, body, received_at) VALUES (?, ?, ?, ?, ?, ?)""", (*identifiers, fingerprint, body.decode("utf-8"), time.time()), ) inserted = cursor.rowcount == 1 # Context manager commits before the request can be acknowledged. return inserted def make_wsgi_app(inbox, webhook_api_key, client_secret): """Verify, commit an inbox record, then acknowledge; workers process it later.""" def app(environ, start_response): if environ.get("REQUEST_METHOD") != "POST": start_response("405 Method Not Allowed", [("Allow", "POST")]) return [b""] try: length = int(environ.get("CONTENT_LENGTH") or "0") if length < 1: raise VerificationError("Missing JSON body") raw_body = environ["wsgi.input"].read(length) headers = { "x-bridge-api-key": environ.get("HTTP_X_BRIDGE_API_KEY", ""), "x-bridge-signature": environ.get("HTTP_X_BRIDGE_SIGNATURE", ""), "x-bridge-timestamp": environ.get("HTTP_X_BRIDGE_TIMESTAMP", ""), } event = verify_webhook(raw_body, headers, webhook_api_key, client_secret) inbox.accept(event) # A duplicate exact event is also acknowledged. except (VerificationError, ValueError): status, body = "400 Bad Request", b'{"accepted":false}' except sqlite3.Error: status, body = "503 Service Unavailable", b'{"accepted":false}' else: status, body = "200 OK", b'{"accepted":true}' start_response(status, [("Content-Type", "application/json"), ("Content-Length", str(len(body)))]) return [body] return app ``` Crie a aplicação WSGI na configuração do servidor: ```python import os from bridge_webhooks import SQLiteInbox, make_wsgi_app application = make_wsgi_app( SQLiteInbox(os.environ["WEBHOOK_INBOX_PATH"]), os.environ["BRIDGE_WEBHOOK_API_KEY"], os.environ["BRIDGE_WEBHOOK_CLIENT_SECRET"], ) ``` Use um caminho persistente para o banco neste exemplo de um único serviço. Ao executar várias réplicas do receptor, use um armazenamento compartilhado com restrição atômica de unicidade equivalente. Aplique as políticas de tamanho de requisição e de rede no servidor HTTP e faça a terminação HTTPS nele. Este exemplo termina na aceitação persistente. Um worker precisa ler as linhas com `processed=0`, executar a ação de negócio de forma idempotente e marcá-las como processadas somente após o sucesso. Uma confirmação local não comprova que a ação de negócio terminou. ## Ordenação e conciliação Não dependa de uma ordem global de entrega. Famílias diferentes de recursos e tentativas de entrega independentes podem se intercalar. Encaminhe cada evento pelo `eventType` publicado e use o esquema da assinatura correspondente. Quando o payload incluir `sequence`, trate-o como uma indicação de ordem do recurso ou fluxo, não como um contador global compartilhado por todos os workspaces ou famílias de eventos. Não o invente para eventos cujo esquema não tenha sequência. Preserve os timestamps e identificadores de origem e evite substituir um estado mais recente por uma notificação antiga. Quando a API REST permitir ler o recurso, consulte o estado atual se o evento deixar o resultado incerto; nos demais casos, siga a orientação da família de eventos ou contate o suporte. Não exija um campo universal `version` em todos os envelopes. Para as famílias de eventos aceitas por esse serviço, a versão configurada na assinatura seleciona o transformador registrado e o esquema de payload daquela família. Siga o esquema documentado para a família e a assinatura; não presuma uma propriedade de versão que seu envelope não publica. ## Teste o receptor antes de colocar em produção Verifique o vetor de assinatura fornecido, payload alterado, chave de API incorreta, timestamps expirados e futuros, entrega duplicada após reiniciar o processo, falha de armazenamento e dois payloads diferentes com o mesmo ID. O reenvio de um payload previamente assinado com um novo timestamp demonstra por que a caixa de entrada persistente é necessária além da verificação temporal. Use o webhook de teste do console do Bridge para validar a conexão e as credenciais configuradas depois de implantar o receptor. Um teste bem-sucedido demonstra que o caminho de callback funciona; não estabelece garantias de entrega ou ordem para todos os eventos de negócio. --- # Configure webhooks Source: https://docs.bridge.new/pt-br/webhooks/configuration Configure a URL de callback, as credenciais de webhook e as assinaturas de eventos no console administrativo do Bridge. Você pode gerenciar todas as configurações de webhook diretamente no [console administrativo do Bridge](https://admin.bridge.new). Isso inclui definir o endpoint, as chaves de autenticação e os tipos de evento a assinar. --- ## Configure os webhooks Siga estas etapas no console administrativo do Bridge: 1. **Entre** no console administrativo do Bridge. 2. Acesse **Developers → Webhooks**. 3. Preencha os seguintes dados: - **Webhook URL:** a URL HTTPS completa do seu endpoint. - **API Key:** usada para identificar o workspace. - **Client Secret:** usado para gerar e verificar assinaturas de webhook (HMAC-SHA256). 4. Em **Select Event Types**, selecione os tipos de evento que deseja assinar. --- ## Conectores nativos de CRM e webhooks personalizados Um conector nativo de CRM e um webhook personalizado são caminhos de entrega separados. Para um CRM conectado, verifique a configuração ativa do conector e os recursos exibidos no console. Esta página não afirma que todos os eventos são sincronizados, que nenhuma configuração é necessária ou que as atualizações têm um prazo fixo em tempo real. Configure um webhook personalizado quando seu serviço precisar receber um evento e aplicar seu próprio processamento. Você pode assinar uma família de eventos também usada por um conector nativo. Se seu receptor gravar no mesmo CRM, coordene os dois caminhos para evitar executar a mesma ação de negócio duas vezes. A confirmação de um webhook personalizado comprova apenas que seu receptor o aceitou. Use [aceitação persistente e processamento idempotente](https://docs.bridge.new/pt-br/webhooks/receive-events.md); não presuma que dois caminhos de entrega garantem atualizações do CRM exatamente uma vez. --- ## Opções de assinatura de eventos O Bridge oferece atualmente as seguintes categorias: ### Notificações de resumo de conversa v1 Receba uma notificação por dia, por conversa, quando a IA do Bridge gerar o resumo diário. - `conversation_summary.created` ### Notificações de tarefas v1 Receba notificações quando tarefas forem criadas ou seu estado mudar. - `task.created` - `task.status_changed` - `task.assigned` - `task.unassigned` - `task.remove_reminder` - `task.field_updated` ### Atualizações de contatos v1 Receba notificações quando contatos forem criados, atualizados ou excluídos. - `contact.created` - `contact.updated` - `contact.deleted` ### Notificações de chamadas v1 Receba um webhook para cada fase do ciclo de uma chamada — criada, chamando, iniciada e finalizada — além da transcrição por IA, quando estiver pronta. Chamadas não são excluídas. - `call.created` - `call.updated` - `call.transcription.created` ### Notificações de reuniões v1 Receba uma notificação quando uma reunião chegar ao estado CREATED. Reuniões não são excluídas, portanto somente o evento `meeting.updated` é emitido. - `meeting.updated` ### Notificações de e-mail v1 Receba uma notificação depois que um e-mail for processado e o resumo por IA estiver disponível. E-mails não são excluídos, portanto somente o evento `email.updated` é emitido. - `email.updated` --- ## Verifique sua configuração Depois que você salva a configuração, o Bridge envia automaticamente um **webhook de teste** ao endpoint para confirmar que ele está acessível e respondendo corretamente. O endpoint deve responder com: - **Código de status HTTP:** `200–299` - **Content-Type:** `application/json` (opcional) - **Tempo de resposta:** confirme prontamente após a aceitação persistente. O emissor usa timeout padrão de dez segundos no socket por tentativa HTTP; não conte com uma tolerância de 30 segundos. Veja as [regras de novas tentativas](https://docs.bridge.new/pt-br/webhooks/receive-events.md#retry-behavior). --- ## Gerencie os webhooks Você pode gerenciar a configuração a qualquer momento no console: | Ação | Descrição | | ------------------ | ------------------------------------------------------------------- | | **Edit** | Atualize a URL, a chave de API ou os eventos assinados | | **Disable Events** | Pause temporariamente tipos de evento específicos sem excluir o webhook | | **Delete** | Remova permanentemente uma configuração de webhook | --- ## Tópicos relacionados - [Visão geral](https://docs.bridge.new/pt-br/webhooks.md) - [Verificação de assinaturas](https://docs.bridge.new/pt-br/webhooks/verifying-signatures.md) - [Tipos de evento](https://docs.bridge.new/pt-br/webhooks/events.md) --- # Eventos de webhook Source: https://docs.bridge.new/pt-br/webhooks/events Famílias de eventos, exemplos de payload e versões de assinatura dos webhooks do Bridge. Os webhooks do Bridge entregam payloads estruturados em JSON sempre que ações específicas ocorrem no workspace. Cada evento segue um esquema consistente para facilitar a interpretação e a validação. --- ## Estrutura comum dos eventos O exemplo abaixo ilustra o envelope comum; `"string"` representa um tipo, não um valor de evento para enviar. Leia os exemplos específicos de cada família a seguir. Não presuma que `eventId` seja globalmente único entre famílias de notificação. ```json { "eventId": "string", "eventType": "string", "entity": "string", "workspaceId": "string", "timestamp": "string", "payload": {} } ``` --- ## Notificações de resumo de conversa v1 Disparadas uma vez por dia, por conversa, quando a IA do Bridge gera o resumo diário. O resumo reúne os principais pontos da troca de mensagens e os participantes internos e externos envolvidos. ### Tipos de evento | Tipo de evento | Descrição | | --------------------------------- | ---------------------------------------------------- | | `conversation_summary.created` | Um resumo diário da conversa foi gerado | ### Exemplo de payload ```json { "eventId": "evt_summary_001", "eventType": "conversation_summary.created", "entity": "conversation_summary", "workspaceId": "ws_123", "timestamp": "2026-05-19T05:03:15.910Z", "payload": { "conversationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "summaryDate": "2026-05-19", "summary": "- Advisor asked the customer about their preferred schedule and offered to book a product demo.\n- Customer replied they are unavailable on Monday morning.\n- Advisor offered alternative slots later in the week and is waiting for confirmation.", "externalUsers": [ { "id": "c1d2e3f4-a5b6-7890-cdef-012345678901", "first_name": "Ana", "last_name": "Garcia", "cellphone": "+57300000000" } ], "internalUsers": [ { "id": "d4e5f6a7-b8c9-0123-defa-234567890123", "first_name": "Bob", "last_name": "Smith", "cellphone": "+57301000000", "email": "bob.smith@example.com" } ], "initMessageId": "f1e2d3c4-b5a6-7890-fedc-ba0987654321", "endMessageId": "a9b8c7d6-e5f4-3210-abcd-ef9876543210", "createdAt": "2026-05-19T05:03:15.910Z", "updatedAt": "2026-05-19T05:03:15.910Z" } } ``` --- ## Atualizações de tarefas v1 Disparadas quando tarefas são criadas ou seu estado muda, incluindo status, atribuição e lembretes. Os payloads variam conforme o tipo de evento. O campo `details` descreve o que mudou naquele evento específico. ### Tipos de evento | Tipo de evento | Descrição | | ---------------------- | ------------------------------------------------- | | `task.created` | Uma nova tarefa foi criada | | `task.status_changed` | O status da tarefa mudou, por exemplo, de OPEN para CLOSED | | `task.assigned` | Um usuário foi atribuído à tarefa | | `task.unassigned` | Um usuário deixou de estar atribuído à tarefa | | `task.remove_reminder` | Um lembrete da tarefa foi removido | | `task.field_updated` | Um campo da tarefa foi atualizado | ### Exemplos de payload ```json Created { "eventId": "evt_123456789", "eventType": "task.created", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:30:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example task description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:30:00.000Z" }, "assignees": [ { "assigneeId": "user_456", "assigneeType": "USER" } ], "conversations": [ { "id": "conv_123", "status": "ACTIVE", "createdAt": "2026-01-14T09:10:00.000Z", "updatedAt": "2026-01-14T09:10:00.000Z" } ] } } ``` ```json Assigned { "eventId": "evt_123456790", "eventType": "task.assigned", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:31:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "assignee": { "assigneeId": "user_456" } } } } ``` ```json Unassigned { "eventId": "evt_123456791", "eventType": "task.unassigned", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:32:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "assignee": { "assigneeId": "user_456" } } } } ``` ```json Status changed (open → closed) { "eventId": "evt_123456792", "eventType": "task.status_changed", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:33:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "details": { "statusChange": { "fromStatus": "OPEN", "toStatus": "CLOSED" } } } } ``` ```json Status changed (closed → open) { "eventId": "evt_123456793", "eventType": "task.status_changed", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:34:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example task description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:34:00.000Z" }, "conversations": [ { "id": "conv_123", "status": "ACTIVE", "createdAt": "2026-01-14T09:10:00.000Z", "updatedAt": "2026-01-14T09:10:00.000Z" } ], "details": { "statusChange": { "fromStatus": "CLOSED", "toStatus": "OPEN" } } } } ``` ```json Reminder removed { "eventId": "evt_123456794", "eventType": "task.remove_reminder", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:35:00.000Z", "payload": { "taskId": "task_456", "actorType": "USER", "actorId": "user_123", "details": { "reminder": { "reminderId": "rem_123" } } } } ``` ```json Field updated { "eventId": "evt_123456795", "eventType": "task.field_updated", "entity": "task", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:36:00.000Z", "payload": { "taskId": "task_123", "actorType": "USER", "actorId": "user_123", "task": { "title": "Sample task", "description": "Example updated description", "type": "TASK", "priority": "NORMAL", "status": "OPEN", "sourceType": "MANUAL", "dueDate": "2026-01-20T00:00:00.000Z", "recurrenceEnded": false, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-01-15T10:36:00.000Z" }, "details": { "fieldUpdate": { "changedFields": ["description"] } } } } ``` --- ## Atualizações de contatos v1 Disparadas quando registros de contatos são criados, atualizados ou excluídos. ### Tipos de evento | Tipo de evento | Descrição | | ----------------- | ---------------------------- | | `contact.created` | Um novo contato foi criado | | `contact.updated` | Um registro de contato foi atualizado | | `contact.deleted` | Um registro de contato foi excluído | ### Exemplos de payload Os campos de titularidade dependem de o contato estar vinculado a um CRM externo: - **Contatos sincronizados com CRM** contêm `crmContactId` e `crmLastSyncedAt`; a identidade do contato é gerenciada pelo CRM, não por um usuário interno do Bridge. - **Contatos nativos do Bridge**, sem vínculo com CRM, contêm `internalUserOwnerId`: o usuário do Bridge responsável pelo registro. Esses grupos são mutuamente exclusivos: um contato sincronizado não inclui `internalUserOwnerId`, e um contato não sincronizado não inclui `crmContactId` nem `crmLastSyncedAt`. Cada entrada em `openAttributes` e `closedAttributes` inclui um `name` legível por pessoas junto de `customAttributeId`. Nos atributos fechados, `closedCustomAttributeIds` é um array de objetos `{ id, content }`, em que `content` é o rótulo de exibição da opção selecionada. ```json CRM-synced { "eventId": "evt_contact_001", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:30:00.000Z", "payload": { "id": "contact_123", "firstName": "John", "lastName": "Doe", "email": "john@example.com", "cellphone": "+1234567890", "languageCode": "EN", "openAttributes": [ { "customAttributeId": "attr_open_1", "name": "Account Number", "content": "14" } ], "closedAttributes": [ { "customAttributeId": "attr_closed_1", "name": "Preferred Language", "closedCustomAttributeIds": [ { "id": "opt_1", "content": "ENGLISH" } ] }, { "customAttributeId": "attr_closed_2", "name": "Software Tools", "closedCustomAttributeIds": [ { "id": "opt_2", "content": "Go" }, { "id": "opt_3", "content": "Postgres" } ] } ], "crmContactId": "crm_456", "crmLastSyncedAt": "2026-01-10T09:00:00.000Z", "createdAt": "2026-01-01T00:00:00.000Z", "updatedAt": "2026-01-15T10:30:00.000Z" } } ``` ```json Bridge-native (no CRM) { "eventId": "evt_contact_002", "eventType": "contact.updated", "entity": "contact", "workspaceId": "ws_123", "timestamp": "2026-01-15T10:32:00.000Z", "payload": { "id": "contact_456", "firstName": "Jane", "lastName": "Smith", "email": "jane@example.com", "cellphone": "+1987654321", "languageCode": "EN", "openAttributes": [ { "customAttributeId": "attr_open_2", "name": "Education level", "content": "Secondary" } ], "closedAttributes": [ { "customAttributeId": "attr_closed_1", "name": "Preferred Language", "closedCustomAttributeIds": [ { "id": "opt_1", "content": "ENGLISH" } ] }, { "customAttributeId": "attr_closed_3", "name": "Gender", "closedCustomAttributeIds": [ { "id": "opt_4", "content": "FEMALE" } ] } ], "internalUserOwnerId": "user_789", "createdAt": "2026-01-05T15:47:49.000Z", "updatedAt": "2026-01-15T10:32:00.000Z" } } ``` --- ## Notificações de chamadas v1 Disparadas à medida que uma chamada percorre seu ciclo de vida. O Bridge emite no máximo um webhook por fase do ciclo, por chamada. Assim, a integração recebe uma sequência clara de quatro fases — criação, toque, início e término — em vez de todas as transições intermediárias gravadas internamente. A fase atual pode ser determinada pelo estado da chamada e pelo status dos participantes: | Fase | Como identificar | | -------- | ------------------------------------------------------------------------ | | created | O estado é CREATED e nenhum participante ingressou ou está chamando | | ringing | Um participante tem status RINGING e ninguém ingressou ainda | | started | O estado é STARTED e dois participantes estão JOINED | | finished | O estado é FINISHED | Chamadas não atendidas pulam a fase de início: a integração recebe apenas created, ringing e finished. Quando uma chamada termina, o Bridge processa a gravação em um fluxo assíncrono de transcrição por IA. Quando a transcrição fica pronta, a integração recebe um evento adicional `call.transcription.created` com o texto completo dividido em segmentos por interlocutor e com marcação de tempo. Esse evento chega **depois** de `call.updated (finished)`, normalmente de alguns segundos a poucos minutos depois, conforme a duração da chamada. A diarização, que identifica os interlocutores, depende da qualidade da fonte de áudio; gravações mono podem produzir um único rótulo de interlocutor para toda a transcrição. ### Tipos de evento | Tipo de evento | Descrição | | ----------------------------- | ----------------------------------------------------------- | | `call.created` | Uma nova chamada foi provisionada | | `call.updated` | Uma fase da chamada mudou: toque, início ou término | | `call.transcription.created` | A transcrição por IA de uma chamada finalizada está pronta | ### Exemplos de payload ```json Created { "eventId": "evt_call_001", "eventType": "call.created", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:05.815Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "CREATED", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:05.815Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "INITIALIZED" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "INITIALIZED" } ] } } } ``` ```json Ringing { "eventId": "evt_call_002", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:06.243Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "CREATED", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:06.243Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "INITIALIZED" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "RINGING" } ] } } } ``` ```json Started { "eventId": "evt_call_003", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:12.771Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "STARTED", "startedAt": "2026-05-04T00:48:12.125Z", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:12.771Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "JOINED", "joinedAt": "2026-05-04T00:48:12.125Z" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "JOINED", "joinedAt": "2026-05-04T00:48:12.124Z" } ] } } } ``` ```json Finished { "eventId": "evt_call_004", "eventType": "call.updated", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:48:20.113Z", "payload": { "callId": "call_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "callType": "ONE_TO_ONE", "channelProvider": "WHATSAPP", "state": "FINISHED", "startedAt": "2026-05-04T00:48:12.125Z", "finishedAt": "2026-05-04T00:48:19.389Z", "createdAt": "2026-05-04T00:48:05.815Z", "updatedAt": "2026-05-04T00:48:20.113Z", "participants": { "internal": [ { "userId": "user_internal_1", "name": "Jane Doe", "email": "jane@example.com", "status": "LEFT", "joinedAt": "2026-05-04T00:48:12.125Z", "leftAt": "2026-05-04T00:48:19.388Z" } ], "external": [ { "userId": "user_external_1", "name": "John Smith", "email": "john@example.com", "status": "LEFT", "joinedAt": "2026-05-04T00:48:12.124Z", "leftAt": "2026-05-04T00:48:19.387Z" } ] } } } ``` ```json Transcription created { "eventId": "evt_call_005", "eventType": "call.transcription.created", "entity": "call", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:50:14.231Z", "payload": { "callId": "call_abc123", "transcriptionId": "txn_xyz789", "conversationId": "conv_xyz", "duration": "27", "startedAt": "2026-05-04T00:48:12.125Z", "finishedAt": "2026-05-04T00:48:19.389Z", "transcript": [ { "speaker": "0", "text": "Hi, how can I help you today?", "start": 1.44, "end": 5.2 }, { "speaker": "1", "text": "I have a question about your product.", "start": 5.5, "end": 12.3 } ] } } ``` Cada segmento da transcrição contém o rótulo `speaker` da diarização, normalmente `"0"`, `"1"` etc., o `text` e os deslocamentos `start`/`end` em segundos desde o início da chamada. --- ## Notificações de reuniões v1 Disparadas quando uma reunião chega ao estado CREATED. Cancelamentos de reuniões são informados pela notificação de e-mail correspondente. ### Tipos de evento | Tipo de evento | Descrição | | ----------------- | ------------------------------------------ | | `meeting.updated` | Uma reunião chegou ao estado `CREATED` | ### Exemplo de payload ```json { "eventId": "evt_meeting_001", "eventType": "meeting.updated", "entity": "meeting", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:46:40.954Z", "payload": { "meetingId": "meeting_abc123", "conversationId": "conv_xyz", "messageId": "msg_xyz", "subject": "Meeting with John Smith", "providerType": "TEAMS", "status": "CREATED", "organizerInternalUserId": "user_internal_1", "internalParticipants": ["user_internal_1"], "externalParticipants": ["user_external_1"], "startDateTime": "2026-05-04T01:00:00.000Z", "endDateTime": "2026-05-04T01:15:00.000Z", "createdAt": "2026-05-04T00:46:29.944Z", "updatedAt": "2026-05-04T00:46:40.954Z", "provider": { "joinUrl": "https://teams.microsoft.com/l/meetup-join/...", "calendarEventId": "AAMkADhlMWVlMWJhLWUyZTMtNDllOC...", "chatId": "MWM1Zjg4MmUtZjk0Mi00YjJkLTgyNTItNmRiODNiZmM1NWEw", "providerMeetingId": "MSowODJkZmFjYy1iNDZmLTRiNDItOGYzOS0xMzI0NDcyMzUwMWUq..." } } } ``` --- ## Notificações de e-mail v1 Disparadas depois que um e-mail é processado e o resumo por IA está disponível. O campo `sentFromBridge` indica a direção: true para e-mails enviados pelo workspace, false para e-mails recebidos. ### Tipos de evento | Tipo de evento | Descrição | | --------------- | ---------------------------------------------------- | | `email.updated` | Um e-mail chegou ao estado resumido | ### Exemplo de payload ```json { "eventId": "evt_email_001", "eventType": "email.updated", "entity": "email", "workspaceId": "ws_123", "timestamp": "2026-05-04T00:45:31.261Z", "payload": { "emailId": "email_abc123", "conversationId": "conv_xyz", "threadId": "AAQkADhlMWVlMWJhLWUyZTMtNDllOC05MDg2LWMzNjFkMTI5MjM4MA...", "providerType": "OUTLOOK", "status": "PROCESSED", "subject": "Project update", "sender": "jane@example.com", "recipients": [ { "recipientEmail": "john@example.com" } ], "summary": "Jane confirms the project is on track and shares next steps.", "importance": "NORMAL", "sentFromBridge": true, "hasAttachments": false, "sentAt": "2026-05-04T00:45:09.000Z", "createdAt": "2026-05-04T00:45:09.000Z", "updatedAt": "2026-05-04T00:45:31.261Z" } } ``` --- ## Observações - O Bridge pode acrescentar novas categorias de eventos no futuro. - Sempre verifique o campo de tipo de evento para escolher qual tratador executar. - Configure e dê suporte à versão selecionada para cada assinatura de evento. O envelope comum não declara um campo universal `version`; não o exija nem o invente. Veja [recebimento de eventos](https://docs.bridge.new/pt-br/webhooks/receive-events.md) para tratar duplicatas e ordenação. --- ## Tópicos relacionados - [Visão geral](https://docs.bridge.new/pt-br/webhooks.md) - [Verificação de assinaturas](https://docs.bridge.new/pt-br/webhooks/verifying-signatures.md) - [Configuração no console](https://docs.bridge.new/pt-br/webhooks/configuration.md) --- # Custom Connections Source: https://docs.bridge.new/pt-br/lead-capture/index Use Custom Connections para registrar leads da sua landing page e colocar uma mensagem inicial de WhatsApp na fila de envio. ## O que essa integração faz Sua landing page envia um lead ao Bridge. Em seguida, o Bridge abre a conversa no WhatsApp usando um template aprovado. Você não envia a mensagem: o Bridge faz o envio. **Aviso** **Uma resposta `202` significa que o lead foi aceito, não que a mensagem foi enviada.** A primeira mensagem de WhatsApp é transmitida depois por um serviço separado. O texto de confirmação deve dizer algo como "entraremos em contato pelo WhatsApp em breve", nunca "já enviamos uma mensagem". ## O que você precisa e onde obter São quatro valores: a URL do endpoint, sua `captureKey`, a chave do site reCAPTCHA e o nome da ação reCAPTCHA. Você não precisa montá-los manualmente. No console administrativo do Bridge, em **LeadScout → Capture snippet**, um administrador do workspace gera um exemplo de integração que já contém os quatro valores. Ele entrega esse bloco à pessoa responsável pela página, que não precisa ter acesso ao console. **Nota** O exemplo é um ponto de partida, não um script pronto para publicar sem adaptações. Você é responsável pelo formulário e pelo texto de consentimento. Veja os [requisitos de consentimento](https://docs.bridge.new/pt-br/lead-capture/consent.md). ## Próximos passos ### [Requisitos de consentimento](https://docs.bridge.new/pt-br/lead-capture/consent.md) O que o aceite deve informar e o que você declara ao enviá-lo. ### [Requisitos de templates](https://docs.bridge.new/pt-br/lead-capture/templates.md) Escolha um template de Utility ou Marketing compatível e entenda os requisitos de cada categoria. ### [Guia de integração](https://docs.bridge.new/pt-br/lead-capture/integration.md) Integre o formulário e trate CAPTCHA, consentimento, respostas e erros. ### [Referência de erros](https://docs.bridge.new/pt-br/lead-capture/errors.md) Todas as respostas do endpoint e quais problemas você pode corrigir. --- # Requisitos de consentimento Source: https://docs.bridge.new/pt-br/lead-capture/consent O que o aceite deve informar e o que você declara ao enviar consent.status GRANTED. ## O que o formulário deve conter Sua landing page deve solicitar um aceite explícito antes de enviar um lead. Você define o texto, mas ele precisa cumprir dois requisitos da Meta: - **Identificar a empresa.** Não basta dizer "nós" ou "nossos parceiros": informe qual empresa entrará em contato com a pessoa. - **Informar que a pessoa receberá comunicações dessa empresa pelo WhatsApp.** Não basta dizer "podemos entrar em contato": identifique o canal. A Meta inclui formulários de sites entre as formas aceitas de obter esse consentimento. Por isso, uma caixa de seleção na landing page é suficiente, desde que o texto informe os dois pontos. **Aviso** Uma caixa previamente marcada não representa aceite. O mesmo vale para um texto em letras pequenas sob o botão de envio, sem nenhuma interação do visitante. A pessoa precisa realizar a ação. ## O que você declara **Nota** Ao enviar `consent.status: "GRANTED"`, **você** declara que houve consentimento. Não verificamos, nem podemos verificar, se o visitante marcou a caixa: registramos que você nos informou esse aceite e quando ele ocorreu. Se o envio de WhatsApp da sua empresa sofrer alguma restrição, esse é o registro apresentado em seu nome. Por isso, `capturedAt` é mais importante do que pode parecer. Ele deve representar o momento em que o visitante realmente consentiu, não o momento em que seu servidor enviou a requisição nem um timestamp gerado em um processamento noturno. Se for necessário comprovar o aceite, a diferença entre esses momentos será um dos primeiros pontos analisados. Envie o horário como um timestamp ISO 8601: ```json { "consent": { "status": "GRANTED", "capturedAt": "2026-08-26T14:32:07.184Z" } } ``` Se não houve consentimento, não envie o lead. Um envio com qualquer status diferente de `GRANTED` é rejeitado com `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED`. ## Um exemplo para adaptar Este exemplo é ilustrativo, não um texto padrão para copiar sem adaptações. Só você sabe o que enviará e por quê; o texto precisa refletir essa comunicação. > ☐ Concordo em receber mensagens de WhatsApp da **Acme Motors** sobre o orçamento que acabei de solicitar. O que torna o exemplo adequado: ele identifica a empresa, informa o canal e descreve o assunto das mensagens. O que o tornaria inadequado: omitir a empresa, dizer apenas "mensagens" sem mencionar o WhatsApp ou incluir esse aceite em uma caixa genérica de termos e condições que também trate de assuntos não relacionados. --- # Requisitos de templates Source: https://docs.bridge.new/pt-br/lead-capture/templates Categorias de templates aceitas e orientações para abrir conversas por Custom Connections. ## Categorias de templates aceitas O template que abre a conversa pode ser da categoria **utility** ou **marketing**: - **Templates Utility**: estritamente transacionais, relacionados ao que o visitante acabou de enviar, como a confirmação de recebimento de uma consulta. Essa categoria tem tarifas menores de conversa no WhatsApp. - **Templates Marketing**: podem incluir linguagem promocional, descontos, ofertas especiais ou abordagens diretas de venda. São cobrados pelas tarifas padrão de marketing do WhatsApp. **Nota** Templates **Authentication** não podem ser usados com Custom Connections. Qualquer template configurado com a categoria `AUTHENTICATION` será rejeitado. Você configura e submete os templates diretamente no Meta WhatsApp Manager. A aprovação é um requisito para colocar a integração em produção. ## Classificação da Meta e entrega **Aviso** A Meta classifica os templates pelo conteúdo, não apenas pela categoria selecionada na submissão. Se um template submetido como UTILITY contiver linguagem promocional, a Meta poderá reclassificá-lo como MARKETING ou rejeitá-lo. Escolher a categoria correta desde o início evita problemas de classificação e mantém a entrega e a cobrança de acordo com o esperado. ## Exemplos por categoria **Utility (transacional)** — confirma o recebimento de uma consulta sem ofertas promocionais: ```text Hi {{1}}, thanks for your enquiry about the {{2}}. A member of our team will follow up here shortly. ``` **Marketing (promocional)** — inclui linguagem promocional, descontos ou ofertas de venda: ```text Hi {{1}}, thanks for your enquiry about the {{2}}. Book this week and get 15% off — reply YES to claim. ``` ## Orientações práticas - **Escolha Utility** quando o objetivo principal for responder rapidamente de forma transacional, confirmando a solicitação do visitante. Mantenha a mensagem estritamente relacionada ao que ele enviou, sem apelos promocionais, para preservar a categoria Utility e sua tarifa menor. - **Escolha Marketing** quando quiser oferecer imediatamente descontos de apresentação, incentivos promocionais ou produtos do catálogo após a captura. - **Evite templates Authentication**: essa categoria é exclusiva para senhas de uso único e códigos de verificação e é rejeitada no envio para leads de campanha. - Quando a pessoa responde, inicia-se uma sessão normal de conversa. As restrições de categoria do template deixam de se aplicar às mensagens recebidas e às respostas dos atendentes ou Agentes. --- # Guia de integração Source: https://docs.bridge.new/pt-br/lead-capture/integration Conecte um formulário de landing page ao Bridge: exemplo, CAPTCHA, consentimento, respostas e tratamento de erros. ## O exemplo O console administrativo do Bridge fornece um exemplo de integração gerado com a configuração do workspace. A versão ampliada abaixo acrescenta validação e retorno visual do envio. Antes de executá-la, copie os valores de configuração do exemplo gerado para os campos de substituição. Adapte o formulário e o texto de consentimento à sua página. **Acme Motors é uma empresa fictícia usada no exemplo abaixo.** Substitua esse nome pela empresa que entrará em contato com o visitante e descreva as mensagens de WhatsApp que ele está aceitando receber. Veja os [requisitos de consentimento](https://docs.bridge.new/pt-br/lead-capture/consent.md). O script demonstra validação, retorno visual do envio e tratamento de erros. Mantenha inalterados os campos da requisição e a ação reCAPTCHA da configuração gerada. ```html

``` ## O que o exemplo faz - Verifica os campos obrigatórios do formulário antes de obter um token de CAPTCHA. - Registra `consent.capturedAt` quando o visitante marca a caixa de seleção. Se o navegador restaurar um estado antigo com a caixa já marcada, solicita uma nova ação de consentimento. - Permite um envio por vez e mantém o botão desabilitado após a aceitação, evitando outro envio nessa instância do formulário. - Apresenta uma resposta `202` como aceita e enfileirada e exibe o `requestId` retornado como referência para suporte. Nunca informa que uma mensagem de WhatsApp foi entregue. - Mostra falhas recuperáveis de CAPTCHA e gera um token novo a cada tentativa manual. Não repete um POST automaticamente. - Trata uma falha de rede após o envio como um resultado incerto; não afirma que o lead foi rejeitado nem que é seguro reenviá-lo. Esse retorno visual é implementado no cliente, não representa uma garantia de deduplicação no backend. Adapte as mensagens visíveis à sua página e use a [referência de erros](https://docs.bridge.new/pt-br/lead-capture/errors.md) para o diagnóstico. ## A chave de captura não é uma chave de API **Nota** O guia de [autenticação](https://docs.bridge.new/pt-br/credentials.md) orienta a nunca colocar uma chave no frontend. Essa regra se aplica à chave da API de integrações e continua válida. A `captureKey` é um valor de outro tipo. Ao contrário da `x-api-key` usada pela API de integrações, a `captureKey` foi projetada para estar no HTML da página, onde qualquer pessoa pode lê-la. Ela não concede acesso de leitura a nenhum dado: apenas identifica a qual workspace pertence um envio. O abuso é limitado por duas outras verificações: o token de reCAPTCHA e a aceitação de envios somente dos domínios cadastrados para o workspace. Nunca use a chave da API de integrações aqui e nunca a coloque em uma página. ## Inclua o ID do workspace na URL O ID do workspace deve estar no corpo da requisição **e** na URL, como `?workspaceId=...`. Ele precisa estar nos dois lugares porque o navegador envia uma requisição preliminar de CORS antes da requisição principal. Essa requisição preliminar não contém corpo. Sem o ID na URL, não conseguimos identificar o workspace nem retornar o cabeçalho que autoriza seu domínio, e o navegador bloqueia a requisição antes de enviá-la. É importante configurar isso corretamente desde o início: essa falha aparece como um erro de CORS no console do navegador, e a requisição principal não chega aos nossos logs, pois não saiu da página. ## Gere o token de CAPTCHA no envio do formulário Um token reCAPTCHA v3 vale por cerca de dois minutos. Se ele for gerado no carregamento da página, muitas vezes já terá expirado quando a pessoa terminar de preencher o formulário. A rejeição retorna `403`, o que pode parecer um problema de permissão, embora a causa seja a expiração. ## Gere um novo token para cada tentativa Cada token pode ser verificado uma única vez. Se um envio falhar e você tentar novamente com o mesmo token, a repetição será indistinguível de um ataque e retornará o mesmo erro recebido por um bot. Sempre chame `grecaptcha.execute` novamente antes de tentar outro envio. ## O que enviar A [referência do endpoint](https://docs.bridge.new/pt-br/api-reference/campaign-leads/registrar-um-lead-de-campanha.md) contém o contrato completo. Estes são os campos cujo significado não fica evidente apenas pelo esquema: ### `brandId` (`string`) A marca comercializada pela landing page, não o ID de uma linha, canal ou telefone. Obrigatório somente se o workspace tiver marcas habilitadas. **Nunca é necessário informar um ID de linha.** ### `landingUri` (`string`) A origem e o caminho da página, sem a query string. Os parâmetros UTM são enviados separadamente em `utm`, e a query string completa pode conter IDs de cliques ou tokens de sessão que não devem ser armazenados. Envie `https://example.com/offer`, não `https://example.com/offer?gclid=...`. ### `consent` (`object`) Sua declaração de que o visitante consentiu e de quando isso aconteceu. Veja os [requisitos de consentimento](https://docs.bridge.new/pt-br/lead-capture/consent.md): o texto de aceite no formulário não é opcional. ### `utm` (`object`) Coletado da query string com base em uma lista de permissões: parâmetros `utm_*` e quaisquer nomes adicionais configurados no console. Usamos uma lista de permissões, em vez de uma lista de exclusões, porque a coleta excessiva de dados não pode ser desfeita. ## Após o envio Uma resposta `202` significa que o lead foi aceito e colocado na fila. Isso **não** significa que uma mensagem foi enviada: o envio acontece depois, em um serviço separado. Informe ao visitante que entrará em contato em breve. Qualquer outra resposta é um erro. Consulte a [referência de erros](https://docs.bridge.new/pt-br/lead-capture/errors.md) para entender cada caso e saber se você pode corrigi-lo. --- # Referência de erros Source: https://docs.bridge.new/pt-br/lead-capture/errors Todas as respostas do endpoint de Custom Connections e quais problemas você pode corrigir. As respostas de erro seguem o formato de detalhes de problema da [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457): `type`, `title`, `status` e, em alguns casos, `detail`. **Nota** **As respostas de erro não contêm um ID de requisição.** Somente uma resposta bem-sucedida `202` contém esse identificador. Se precisar de suporte, informe a URL da página e o horário aproximado. ## Todas as respostas | Status | `type` | O que aconteceu | Você pode corrigir? | | --- | --- | --- | --- | | `400` | `invalid_payload` | Um campo está ausente ou tem formato inválido. | Sim | | `400` | `BRIDGE.CAMPAIGN_LEADS.INVALID_PHONE` | Não foi possível interpretar o telefone como um número válido. | Sim — valide antes de enviar | | `400` | `BRIDGE.CAMPAIGN_LEADS.CONSENT_NOT_GRANTED` | `consent.status` não era `GRANTED`. | Sim | | `400` | `BRIDGE.CAMPAIGN_LEADS.BRAND_OR_LINE_REQUIRED` | O workspace tem marcas habilitadas, mas nenhum `brandId` foi enviado. | Sim | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_DISABLED` | O recurso Custom Connections não está habilitado para esse workspace. | Não — entre em contato com o Bridge | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTURE_KEY_MISMATCH` | A chave de captura está ausente ou incorreta. | Sim | | `403` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_REJECTED` | O token de CAPTCHA estava ausente, expirado, já havia sido usado ou recebeu uma pontuação muito baixa. | Em alguns casos — veja abaixo | | `403` | `BRIDGE.CAMPAIGN_LEADS.ORIGIN_NOT_ALLOWED` | O domínio da página não está cadastrado para esse workspace. | Não — entre em contato com o Bridge | | `422` | `BRIDGE.CAMPAIGN_LEADS.CAPTCHA_PROVIDER_UNAVAILABLE` | Não conseguimos acessar o provedor de CAPTCHA. | É seguro tentar novamente | | `500` | `unexpected_error` | Ocorreu uma falha do nosso lado. | Não | Somente a primeira falha é informada. As verificações seguem esta ordem: workspace e chave de captura, telefone, consentimento, marca, CAPTCHA e, por último, domínio. Corrigir um erro pode revelar o próximo. ## Sobre a rejeição do CAPTCHA `CAPTCHA_REJECTED` abrange quatro situações. Verifique como a integração trata o token antes de atribuir a rejeição à pontuação: - **O token expirou.** Ele foi gerado cedo demais. Um token reCAPTCHA v3 dura cerca de dois minutos; gere-o quando o formulário for enviado, não no carregamento da página. - **O token já foi usado.** Cada token pode ser verificado uma única vez. Se você repetiu um envio malsucedido sem gerar outro token, a repetição é rejeitada. - **Nenhum token foi enviado.** Verifique se o cliente obtém um token e o inclui em `recaptchaToken` em todos os envios. - **A pontuação foi muito baixa.** A verificação contra bots rejeitou essa tentativa. Não contorne essa proteção. As quatro situações retornam o mesmo código, portanto a resposta sozinha não identifica a causa. Primeiro, confirme que o token foi incluído, gerado no momento do envio e renovado a cada tentativa. ## Sobre o erro 422 É uma falha temporária do nosso lado: não conseguimos acessar o provedor de CAPTCHA e, por isso, não foi possível decidir se o envio era legítimo. **É seguro tentar novamente.** O lead é preservado quando isso acontece, e uma nova tentativa não pode gerar uma mensagem duplicada. Gere um novo token de CAPTCHA para a tentativa, como faria em qualquer outro envio. ## Sobre o erro de domínio A ordem das verificações merece atenção. O domínio da página é comparado com os domínios cadastrados para o workspace. Porém, o domínio verificado é o **informado pelo provedor de CAPTCHA**, não o que aparece nos cabeçalhos da própria requisição. Essa verificação ocorre *depois* que o token é validado. Na prática, uma página hospedada em um domínio não cadastrado falha na etapa de CAPTCHA com `ORIGIN_NOT_ALLOWED`, não com um erro de CORS. Se isso acontecer mesmo quando o restante da integração funciona, o domínio não está na configuração do workspace. Entre em contato com o Bridge para cadastrá-lo. --- # Verificar integridade Source: https://docs.bridge.new/pt-br/api-reference/health/verificar-integridade **Referência da operação:** `get /bridge/api/health` **operationId:** `health_bridge_api_health_get` Endpoint de verificação de integridade para confirmar que a API está em funcionamento. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Obter conversa por id Source: https://docs.bridge.new/pt-br/api-reference/conversations-api/obter-conversa-por-id **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}` **operationId:** `get_conversation_by_id_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__get` Obtém uma conversa específica pelo seu identificador único no workspace. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Atualizar conversa Source: https://docs.bridge.new/pt-br/api-reference/conversations-api/atualizar-conversa **Referência da operação:** `patch /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}` **operationId:** `update_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__patch` Atualiza os detalhes da conversa, incluindo participantes, status e nome. Aceita atualizações parciais: inclua apenas os campos que deseja alterar. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Consultar conversas com filtros flexíveis Source: https://docs.bridge.new/pt-br/api-reference/conversations-api/consultar-conversas-com-filtros-flex%C3%ADveis **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/conversations` **operationId:** `get_conversations_bridge_api_v1_workspaces__workspaceId__conversations_get` Consulta conversas com opções flexíveis de filtragem. Permite buscar por identificadores de usuários externos (ID, e-mail ou telefone) ou por participantes internos, com paginação e filtro por status. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Criar conversa com identificação flexível de usuários Source: https://docs.bridge.new/pt-br/api-reference/conversations-api/criar-conversa-com-identifica%C3%A7%C3%A3o-flex%C3%ADvel-de-usu%C3%A1rios **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations` **operationId:** `create_conversation_bridge_api_v1_workspaces__workspaceId__conversations_post` Cria uma conversa com identificação flexível de usuários. Os usuários externos podem ser identificados por ID, e-mail ou telefone. Usuários internos só são atribuídos quando informados explicitamente; caso contrário, as conversas são distribuídas em rodízio por uma equipe ou ficam abertas para qualquer usuário interno disponível. Quando não há uma linha livre e os Contacts têm uma conversa liberada com exatamente os participantes solicitados, essa conversa é recuperada e retornada, mantendo seu `id` e histórico. O `name` e o `status` da solicitação não são aplicados a ela. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Liberar conversa Source: https://docs.bridge.new/pt-br/api-reference/conversations-api/liberar-conversa **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/conversations/{conversationId}/release` **operationId:** `release_conversation_bridge_api_v1_workspaces__workspaceId__conversations__conversationId__release_post` Libera uma conversa: marca-a como liberada, remove os participantes externos e move-a para a seção RELEASED. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Criar mensagem Source: https://docs.bridge.new/pt-br/api-reference/messages-api/criar-mensagem **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/messages` **operationId:** `create_message_bridge_api_v1_workspaces__workspaceId__messages_post` Cria uma mensagem em uma conversa específica. Para uma mensagem de texto ou um anexo enviado, inclua todos os campos obrigatórios: `conversationId`, `messageBody` e `enableExternalBroadcast`. Anexe os arquivos enviados usando os identificadores retornados em `mediaIds`; consulte [Enviar um anexo](https://docs.bridge.new/pt-br/guides/send-attachments.md). Uma resposta bem-sucedida retorna `messageId`; não contém uma confirmação de entrega do provedor. Consulte [Respostas e novas tentativas](https://docs.bridge.new/pt-br/guides/responses.md). [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Obter contato por um identificador Source: https://docs.bridge.new/pt-br/api-reference/contacts-api/obter-contato-por-um-identificador **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/lookup` **operationId:** `retrieve_contact_by_identifier_bridge_api_v1_workspaces__workspaceId__contacts_lookup_get` Obtém um contato específico por qualquer um de seus identificadores no workspace. `type=ID` retorna o mesmo contato que GET /contacts/{contactId}, a URL canônica de um contato e a opção preferida quando você já tem seu ID. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Obter contato por id Source: https://docs.bridge.new/pt-br/api-reference/contacts-api/obter-contato-por-id **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}` **operationId:** `retrieve_contact_by_id_bridge_api_v1_workspaces__workspaceId__contacts__contactId__get` Obtém um contato específico pelo seu identificador único no workspace. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Atualizar contato Source: https://docs.bridge.new/pt-br/api-reference/contacts-api/atualizar-contato **Referência da operação:** `patch /bridge/api/v1/workspaces/{workspaceId}/contacts/{contactId}` **operationId:** `update_contact_bridge_api_v1_workspaces__workspaceId__contacts__contactId__patch` Atualiza um contato no workspace informado. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Listar contatos Source: https://docs.bridge.new/pt-br/api-reference/contacts-api/listar-contatos **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/contacts` **operationId:** `get_contacts_bridge_api_v1_workspaces__workspaceId__contacts_get` Consulta uma lista paginada de contatos do workspace. A lista é ordenada por data de criação. Os filtros `ownerEmail` e `search` estão obsoletos e serão removidos; para encontrar um contato por um identificador, use /contacts/lookup. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Criar contato Source: https://docs.bridge.new/pt-br/api-reference/contacts-api/criar-contato **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts` **operationId:** `create_contact_bridge_api_v1_workspaces__workspaceId__contacts_post` Cria um contato no workspace informado. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Criar ou atualizar contato Source: https://docs.bridge.new/pt-br/api-reference/contacts-api/criar-ou-atualizar-contato **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/contacts/partial` **operationId:** `create_partial_contact_bridge_api_v1_workspaces__workspaceId__contacts_partial_post` Cria ou atualiza um contato usando apenas o celular. Classifica-o como NORMAL ou PARTIAL. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Criar uploads pré assinados de arquivos Source: https://docs.bridge.new/pt-br/api-reference/files-api/criar-uploads-pr%C3%A9-assinados-de-arquivos **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/files` **operationId:** `create_preloaded_files_bridge_api_v1_workspaces__workspaceId__files_post` Carregue um anexo, como um PDF, uma imagem ou um documento, antes de criar uma mensagem. Esta operação retorna os dados de um PUT pré-assinado; os bytes do arquivo são enviados separadamente. Após o upload ser concluído, use o `mediaId` retornado na operação de envio. Siga [Enviar um anexo](https://docs.bridge.new/pt-br/guides/send-attachments.md) para as etapas de checksum, upload e mensagem. Gera URLs pré-assinadas para upload de arquivos (Presigned PUT). Valida a extensão, contentType e os limites por tipo. O checksum é obrigatório: envie o resumo SHA-256 em checksumBase64 (Base64). O upload deve incluir o cabeçalho x-amz-checksum-sha256 com o mesmo valor. --- Para fazer upload dos arquivos, você DEVE usar a URL pré-assinada retornada com o método HTTP PUT. Envie o arquivo exatamente para a URL indicada, sem modificações, conforme exigido pelo AWS S3 para PUT com URL pré-assinada. Consulte a documentação oficial do AWS S3: [Documentação do AWS S3 sobre Presigned PUT](https://docs.aws.amazon.com/AmazonS3/latest/userguide/PresignedUrlUploadObject.html). Inclua todos os cabeçalhos obrigatórios indicados na resposta, por exemplo, 'x-amz-checksum-sha256' com o valor SHA-256 correto. A AWS rejeitará o upload se você não usar o método HTTP ou os cabeçalhos corretos.
TipoExtensãoTipo de conteúdoTamanho máximo
Imagem.jpegimage/jpeg16 MB
.jpgimage/jpeg
.pngimage/png
.webpimage/webp
GIF.gifimage/gif3 MB
.mp4video/mp4
Vídeo.avivideo/x-msvideo64 MB
.movvideo/quicktime
.mp4video/mp4
Áudio.m4aaudio/mp416 MB
.mp3audio/mpeg
.oggaudio/ogg
.wavaudio/wav
Documento.docapplication/msword100 MB
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.pdfapplication/pdf
.pptapplication/vnd.ms-powerpoint
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.txttext/plain
.xlsapplication/vnd.ms-excel
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
[Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Consultar atributos personalizados por workspaceid Source: https://docs.bridge.new/pt-br/api-reference/custom-attributes-api/consultar-atributos-personalizados-por-workspaceid **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/settings/attributes` **operationId:** `get_custom_attributes_by_workspace_bridge_api_v1_workspaces__workspaceId__settings_attributes_get` Retorna os atributos personalizados do workspace informado. Por padrão, retorna apenas atributos **ativos** (sem um `deletedAt` no passado). **Filtros:** - `category`: filtra por `OPEN` ou `CLOSED`. Omita para retornar todas as categorias. - `includeArchived`: use `true` para incluir atributos arquivados (com `deletedAt` no passado). Padrão: `false`. - `isRequired`: use `true` para retornar apenas atributos obrigatórios e `false` para retornar apenas opcionais. Omita para retornar todos. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Obter canais de provedores por workspace Source: https://docs.bridge.new/pt-br/api-reference/provider-channels-api/obter-canais-de-provedores-por-workspace **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels` **operationId:** `get_provider_channels_by_workspace_id_bridge_api_v1_workspaces__workspaceId__provider_channels_get` Obtém os canais de provedores pelo identificador do workspace. Esta resposta expõe `provider` e `identifier`, semelhante a um número de telefone, para cada canal; não retorna `providerChannelId`. Para as linhas de um Agent, leia `agents[].lines[].providerChannelId` na lista de Agents. Não substitua um ID de canal por um número de telefone. Consulte [Conceitos e identificadores](https://docs.bridge.new/pt-br/guides/identifiers.md). [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Obter canais por workspace e tipo de provedor Source: https://docs.bridge.new/pt-br/api-reference/provider-channels-api/obter-canais-por-workspace-e-tipo-de-provedor **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/provider-channels/{messageProviderType}` **operationId:** `get_provider_channels_by_workspace_id_and_provider_type_bridge_api_v1_workspaces__workspaceId__provider_channels__messageProviderType__get` Obtém os canais de provedores pelo identificador do workspace e tipo de provedor. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Iniciar conversa de saída do leadscout com um lead conhecido Source: https://docs.bridge.new/pt-br/api-reference/leadscout-api/iniciar-conversa-de-sa%C3%ADda-do-leadscout-com-um-lead-conhecido **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/outbound` **operationId:** `initiate_leadscout_outbound_bridge_api_v1_workspaces__workspaceId__leadscout_outbound_post` Inicia uma conversa de saída do LeadScout com um Contact conhecido. O Contact já deve existir. A Bridge seleciona um Agent de prospecção para uma linha de WhatsApp elegível. O template é referenciado por template.id ou template.name; id tem precedência quando ambos são informados. Ele deve existir e estar APPROVED, e qualquer Bridge User de handoffOverride deve ser válido. Um contact.providerChannelId explícito é respeitado. Sem ele, a seleção automática prefere uma linha livre, depois uma conversa liberada recuperável com este Contact e, por último, uma conversa ativa ocupada somente quando forceSend=true. A disponibilidade é avaliada por Contact em cada linha, não pela ocupação global da linha. forceSend=true reutiliza uma conversa ativa elegível; não a ignora nem cria uma nova. Uma reutilização bem-sucedida retorna alreadyInitiated=true e persiste o novo template e os acompanhamentos. Uma conversa liberada recuperável pode ser recuperada com qualquer um dos valores, mantém seu ID e retorna recovered=true. Esta opção não torna utilizáveis as conversas bloqueadas nem as liberadas não recuperáveis. A rota legada pode reutilizar uma conversa controlada por um humano ou outro Agent; ao contrário da saída de Agents, ela não exige a verificação de controle pelo Agent solicitado. Uma sessão aberta do LeadScout ainda não expirada continua bloqueando uma nova solicitação de saída com 409 BRIDGE_AI_LEADSCOUT_0017; a impossibilidade de finalizar uma sessão expirada retorna 409 BRIDGE_AI_LEADSCOUT_0018. As outras validações continuam valendo. As mensagens adicionais são persistidas; a persistência não comprova a entrega nem uma espera pela resposta do lead. Uma solicitação com falha pode deixar trabalho parcial, portanto não trate forceSend como idempotência nem repita às cegas uma solicitação com resultado incerto. Consulte [o guia completo de saída](https://docs.bridge.new/pt-br/guides/agent-outbound.md) para a matriz false/true, os indicadores de resposta, as diferenças em relação à saída de Agents, os erros e a transferência. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Solicitar transferência manual do leadscout para usuários internos Source: https://docs.bridge.new/pt-br/api-reference/leadscout-api/solicitar-transfer%C3%AAncia-manual-do-leadscout-para-usu%C3%A1rios-internos **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/leadscout/conversations/{conversationId}/handoff` **operationId:** `request_leadscout_handoff_bridge_api_v1_workspaces__workspaceId__leadscout_conversations__conversationId__handoff_post` Solicita a transferência manual de uma conversa controlada pelo LeadScout para um ou mais usuários internos. A solicitação é confirmada com `202 Accepted`; a atribuição é processada de forma assíncrona. A resposta repete os destinatários solicitados e um ID de rastreamento para correlação. A resolução de usuários internos (por ID ou EMAIL) ocorre depois e não é refletida nesta resposta. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Descobrir as variáveis agnósticas de um modelo Source: https://docs.bridge.new/pt-br/api-reference/templates-api/descobrir-as-vari%C3%A1veis-agn%C3%B3sticas-de-um-modelo **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/templates/{templateId}` **operationId:** `get_template_discovery_bridge_api_v1_workspaces__workspaceId__templates__templateId__get` Retorna as variáveis de um template: `key`/`label`/`callerMustSupply`/`isCustom`/`default`, independentes da posição na Meta. Nunca retorna o endereço ou índice de uma posição da Meta. `templateId` aceita o `id` ou o `name` do template. As operações de saída aceitam `template.id` ou `template.name`, com precedência para um id não vazio. A abertura de conversas usa `onboardingTemplates[].templateId`. Use o seletor exigido pela operação de envio. Consulte [a receita de templates](https://docs.bridge.new/pt-br/guides/send-template.md). Uma variável com `callerMustSupply: true` não tem uma fonte declarada: quem chama deve incluir sua `key` em `parameters` ao enviar; caso contrário, o envio falha com um 422 que identifica a mesma `key`. Uma variável com `callerMustSupply: false` é resolvida pela própria Bridge, por exemplo, o primeiro nome do destinatário, ou já tem um valor que quem chama pode substituir opcionalmente. Uma variável com `isCustom: true` é um valor conhecido apenas por quem chama e tem um `default`: envie-a em `parameters` para usar seu próprio valor, ou omita-a ou deixe-a em branco para enviar `default`. Códigos de erro: - BRIDGE_CORE_0301: o workspace na rota não corresponde ao workspace de quem chama (403) - BRIDGE_TEMPLATE_0001: nenhuma PROVIDER_TEMPLATE foi encontrada para este workspace e identificador. Abrange igualmente um id/name desconhecido, um template de outro workspace e um template que não é PROVIDER_TEMPLATE (404); este endpoint nunca confirma a existência de um template fora do workspace de quem chama [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Obter usuário interno por um identificador Source: https://docs.bridge.new/pt-br/api-reference/internal-users-api/obter-usu%C3%A1rio-interno-por-um-identificador **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/users/lookup` **operationId:** `retrieve_internal_user_by_identifier_bridge_api_v1_workspaces__workspaceId__users_lookup_get` Obtém um Bridge User específico por qualquer um de seus identificadores no workspace. `type=ID` retorna o mesmo usuário que GET /users/{userId}, a URL canônica de um usuário interno e a opção preferida quando você já tem seu ID. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Obter usuário interno por id Source: https://docs.bridge.new/pt-br/api-reference/internal-users-api/obter-usu%C3%A1rio-interno-por-id **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/users/{userId}` **operationId:** `retrieve_internal_user_by_id_bridge_api_v1_workspaces__workspaceId__users__userId__get` Obtém um usuário interno específico (agente humano) pelo seu identificador único no workspace. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Listar usuários internos Source: https://docs.bridge.new/pt-br/api-reference/internal-users-api/listar-usu%C3%A1rios-internos **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/users` **operationId:** `get_internal_users_bridge_api_v1_workspaces__workspaceId__users_get` Consulta uma lista paginada de usuários internos do workspace. A lista é ordenada por data de criação. Os filtros `email` e `status` estão obsoletos e serão removidos; para encontrar um usuário interno por um identificador, use /users/lookup. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Listar os agents de um workspace Source: https://docs.bridge.new/pt-br/api-reference/agents-api/listar-os-agents-de-um-workspace **Referência da operação:** `get /bridge/api/v1/workspaces/{workspaceId}/agents` **operationId:** `list_agents_bridge_api_v1_workspaces__workspaceId__agents_get` Lista os Agents do workspace com seu status, disponibilidade e linhas. Inclui todos os Agents, independentemente do status; `available` indica se podem iniciar conversas. Uma página pode conter menos itens que `limit`; continue a paginação enquanto `cursor` não for null. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Iniciar conversa de saída com um contact como agent específico Source: https://docs.bridge.new/pt-br/api-reference/agents-api/iniciar-conversa-de-sa%C3%ADda-com-um-contact-como-agent-espec%C3%ADfico **Referência da operação:** `post /bridge/api/v1/workspaces/{workspaceId}/agents/{agentId}/outbound` **operationId:** `start_agent_outbound_bridge_api_v1_workspaces__workspaceId__agents__agentId__outbound_post` Inicia uma conversa de saída com um Contact conhecido, atendida pelo Agent indicado. Funciona com Agents LeadScout e Service. Primeiro é resolvido o Contact e depois o Agent, que deve existir no workspace e estar disponível (consulte `GET /agents`). O template é referenciado por `template.id` ou `template.name` (id tem precedência quando ambos são enviados), deve existir e estar APPROVED, e qualquer Bridge User de `handoffOverride` deve ser válido. Se `template.media.mediaId` for desconhecido, a solicitação falha com 400 `BRIDGE_AI_LEADSCOUT_0016` somente depois de a conversa ser criada ou recuperada, portanto uma nova tentativa após esse erro pode responder de forma diferente. As regras do corpo (`consent.status=GRANTED` sem `capturedAt`, ou `template.media` sem exatamente um de `mediaId` ou `url`) falham com 400 `BRIDGE_CORE_0103`. A conversa é aberta em uma das linhas ativas de WhatsApp do Agent, sob seu controle, com o template como primeira mensagem. A linha é escolhida nesta ordem: - Uma linha livre. - Caso contrário, uma linha com uma conversa liberada recuperável com este Contact. A recuperação retorna `recovered=true` e substitui o contexto de saída anterior e `agentContext`. Isso acontece mesmo com `forceSend=false`. - Se nenhuma linha estiver livre ou for recuperável: `forceSend=false` (padrão) falha com 409 `BRIDGE_AI_LEADSCOUT_0008`; `forceSend=true` reutiliza uma linha ocupada por uma conversa ativa com este Contact, dando preferência a uma controlada por este Agent. Se a conversa escolhida for controlada por outro Agent ou por um Bridge User, a chamada falha com 409 `BRIDGE_AI_AGENT_OUTBOUND_0006` e nada é gravado. Libere-a primeiro e tente novamente. Linhas cuja conversa está bloqueada ou foi liberada sem recuperação nunca são usadas; assim, se nenhuma linha estiver ocupada por uma conversa ativa, a chamada falha com 409 `BRIDGE_AI_LEADSCOUT_0008` mesmo com `forceSend=true`. `contact.providerChannelId` é uma preferência: a linha indicada é usada quando está livre ou é recuperável; caso contrário, a mesma ordem é aplicada entre todas as linhas do Agent. Entre as linhas ocupadas, uma controlada por este Agent tem prioridade; se nenhuma for, a linha indicada é reutilizada (e pode falhar com 0006). A reutilização de uma conversa depende do tipo de Agent: - LeadScout: se sua sessão do LeadScout ainda estiver aberta e não expirada, a chamada falha com 409 `BRIDGE_AI_LEADSCOUT_0017` (`extra` inclui `conversationId`, `sessionId` e `stage`). Se uma sessão expirada não puder ser finalizada, falha com 409 `BRIDGE_AI_LEADSCOUT_0018`. - Service Agent: uma sessão de serviço aberta e não expirada continua; uma sessão expirada é encerrada como abandonada e uma nova é aberta. Consulte [o guia completo de saída](https://docs.bridge.new/pt-br/guides/agent-outbound.md) para os pré-requisitos, a tabela de decisão de forceSend, a recuperação, o trabalho parcial e as decisões seguras de nova tentativa. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição. --- # Registrar um lead de campanha Source: https://docs.bridge.new/pt-br/api-reference/campaign-leads/registrar-um-lead-de-campanha **Referência da operação:** `post /leadscout/campaign-leads` **operationId:** `create_campaign_lead_leadscout_campaign_leads_post` Registra um lead captado pela página de destino de um tenant e coloca na fila a primeira mensagem de saída do WhatsApp. Um 202 significa que o lead foi aceito, não que uma mensagem foi enviada. [Contrato OpenAPI exato](https://docs.bridge.new/pt-br/api-reference/campaign-leads.openapi.yaml) Este corpus contém guias e descrições de operações. Ele não inclui todos os schemas de requisição e resposta. Leia o contrato OpenAPI vinculado antes de gerar uma requisição.