# Introduction Source: https://docs.embedreach.com/acquire/introduction Reach's Acquire platform helps businesses create, manage, and optimize paid digital advertising campaigns with AI-powered tools that make advertising accessible to everyone. ## User Experience for Acquire When your users navigate to the embedded Reach UI, they will be prompted to create advertising campaigns if they want to grow their business through digital ads. Once they opt-in, they will go through the following steps: Your tenants will need to connect their Google & Meta accounts where the ads will be created. They will need to have a payment method on file with the Ads platforms. Confirm the geographic areas shared with Reach and define what locations should be included in the target audience. Then set the budget that should be allocated towards the created campaigns. If your tenants have their own landing pages or contact forms not owned by your platform, they'll be prompted to add our code snippet to those systems. This helps use as much first-party data as possible to minimize gaps in attribution. After a brief review period, the campaign goes live with continuous optimization handled by our system to maximize return on investment. The metrics -- powered by a deep integration to the transaction data -- give a detailed picture of campaign performance. ## Integrating Acquire into your Platform Implementing Acquire for your tenants requires three main technical steps: Decide how you want to expose Reach to your users. We support both IFrame and React Component options that give you control to match the look-and-feel of your platform. With the help of a shared secret, we allow you to automatically authenticate your users so they do not need to separately log into Reach. When initializing the SDK, set `feature: 'acquire'` to load the Acquire interface. See the [Embeddable UI](/embeddable-ui/integration-overview) section and [Initializing the SDK](/embeddable-ui/iframe/embedding#initializing-the-sdk) for configuration details. Only relevant if you own and host any contact forms, scheduling widgets, or booking pages. You will need to load the Reach attribution snippet and use the `createIdentification` API to tell Reach when a visitor has identified themselves. See the [Attribution & Tracking](/attribution/introduction) section for more details. Share the customer identifiers (phone, email, etc.) and transaction data (orders, bookings, memberships, etc.) so that Reach can make the connection between visitors and revenue. See the [Data Sharing](/data-sharing/introduction) section for more details. # End User Documentation Source: https://docs.embedreach.com/ai-voice/end-user-docs Complete guide to setting up and managing your AI Voice agent # AI Voice End User Guide This guide covers everything you need to know about configuring and managing your AI Voice agent, including call forwarding, call transfers, and managing blocked numbers. *** # Call Forwarding ## What is Call Forwarding? Call forwarding routes calls from your existing business phone number to your new AI phone number. When customers call your regular number, the call is automatically forwarded to your AI agent, which can handle the conversation, answer questions, and even transfer calls to you when needed. ## Forwarding Types You can choose how calls are forwarded: * **Missed Calls Only**: Your phone rings first, giving you a chance to answer. If you don't pick up, the call forwards to the AI agent. This is the recommended option for most businesses. * **All Calls**: Every call to your business number is immediately forwarded to the AI agent without ringing your business phone first. This means you or your team only need to answer calls that the AI could not answer. Note: this requires careful configuration to avoid infinite loops (see below). * **None**: Calls to your business phone number are never forwarded to the AI agent. The only way calls will reach the AI agent is by calling the agent's number directly. If you use **Blocked Numbers** (see [Blocked Calls](#blocked-calls)), what callers experience depends on which forwarding type you chose—especially whether your business phone rings before the AI is involved. ## How to Set Up Call Forwarding Use **Mobile & Landlines** below if your carrier uses activation dial codes. If you use **VoIP** (Google Voice, Dialpad, Quo, TextNow, Grasshopper, RingCentral, or another provider listed in the app), skip the dial-code tables and follow **[VoIP Providers](#voip-providers)**—the product walks you through provider-specific steps there. ### Mobile & Landlines 1. **Select Your Phone Type**: Choose cell phone, landline, or VoIP, then pick your carrier in the app. 2. **Select Your Carrier**: Choose your phone carrier from the list. 3. **Enter Your Forwarding Number**: Enter the phone number from which you want to forward calls to your AI agent (typically your business line or the phone that receives your business calls). 4. **Choose Forwarding Type**: Select All Calls, Missed Calls Only, or None. 5. **Dial the Activation Code**: Use the carrier-specific dial code provided in the app. The code will include your AI phone number formatted correctly for your carrier. After dialing the code, the system will test the forwarding to ensure it's working correctly. **Required: Disable these settings before testing** These phone settings must be turned off before running the test. Otherwise, they will prevent the AI voice agent from receiving your calls. * **Live Voicemail**: Turn off in Settings → Phone → Live Voicemail (iOS). * **Screen Unknown Callers**: Turn off in Settings → Phone → Screen Unknown Callers → set to "Never" (iOS). #### Carrier-Specific Dial Codes ##### Activation Codes Dial these codes from your phone to activate call forwarding. Replace `(XXX) XXX-XXXX` with your AI phone number in the format shown. | Carrier | All Calls | Missed/No Answer | | --------------------- | ------------------------- | ------------------------- | | **Verizon Mobile** | `*72 (XXX) XXX-XXXX` | `*71 (XXX) XXX-XXXX` | | **Verizon Landline** | `*72 (XXX) XXX-XXXX` | `*92 (XXX) XXX-XXXX` | | **AT\&T Mobile** | `**21* (XXX) XXX-XXXX #` | `**61* (XXX) XXX-XXXX #` | | **AT\&T Landline** | `*72 (XXX) XXX-XXXX` | `*92 (XXX) XXX-XXXX` | | **T-Mobile** | `**21*1 (XXX) XXX-XXXX #` | `**61*1 (XXX) XXX-XXXX #` | | **US Cellular** | `*72 (XXX) XXX-XXXX` | `*92 (XXX) XXX-XXXX` | | **Sprint** | `*72 (XXX) XXX-XXXX` | `*73 (XXX) XXX-XXXX` | | **Spectrum Mobile** | `*72 (XXX) XXX-XXXX` | `*71 (XXX) XXX-XXXX` | | **Spectrum Landline** | `*72 (XXX) XXX-XXXX` | `*92 (XXX) XXX-XXXX` | | **Xfinity Mobile** | `*72 (XXX) XXX-XXXX` | `*71 (XXX) XXX-XXXX` | | **Xfinity Landline** | `*72 (XXX) XXX-XXXX` | `*92 (XXX) XXX-XXXX` | Don't see your carrier? Search your carrier name plus "call forwarding" (or "call forwarding code") to find your provider's instructions. ##### Deactivation Codes Dial these codes from your phone to disable call forwarding: | Carrier | All Calls | Missed/No Answer | | --------------------- | --------- | ---------------- | | **Verizon Mobile** | `*73` | `*73` | | **Verizon Landline** | `*73` | `*93` | | **AT\&T Mobile** | `##21#` | `##61#` | | **AT\&T Landline** | `*73` | `*93` | | **T-Mobile** | `##21#` | `##61#` | | **US Cellular** | `*720` | `*920` | | **Sprint** | `*720` | `*730` | | **Spectrum Mobile** | `*73` | `*73` | | **Spectrum Landline** | `*73` | `*93` | | **Xfinity Mobile** | `*73` | `*73` | | **Xfinity Landline** | `*73` | `*93` | Don't see your carrier? Search your carrier name plus "call forwarding" (or "call forwarding code") to find your provider's instructions. ### VoIP Providers If you're using a supported VoIP provider (Dialpad, Quo, Google Voice, TextNow, Grasshopper, RingCentral, or another listed in the app), call forwarding is set up in that provider's dashboard or app—not with carrier dial codes. The in-app flow shows **step-by-step instructions** for the provider you select; the summary below stays aligned with those steps. #### Dialpad Configure forwarding in **Settings → Your Devices**. See [Dialpad call forwarding](https://help.dialpad.com/docs/call-forwarding). #### Quo Configure forwarding in **Settings → Phone Numbers**, then open your number and use **Call Flows**. See [Quo call forwarding](https://support.quo.com/core-concepts/administration/call-flows/call-forwarding). #### Grasshopper Configure forwarding in **Settings → Call Forwarding Settings → Extensions**. Edit the extension you want to forward (or create a new one) and add your AI agent number as a forwarding destination. See [Grasshopper call forwarding](https://grasshopper.com/features/call-forwarding). #### RingCentral In the RingCentral app, click your profile picture (top left) → **Call rules** → **Forward all calls**. In the **Incoming calls** dropdown, select **Forward the call**, click **Number**, and enter your AI agent number as the external forwarding destination, then **Save**. To disable, return to **Call rules → Forward all calls** and turn **Forward all calls** off (or remove the rule). See [Forwarding calls to an external number](https://support.ringcentral.com/article-v2/Forwarding-calls-external-number.html?brand=RC_US\&product=RingEX\&language=en_US). #### Google Voice Google Voice uses **linked numbers** and **custom call forwarding rules** at [voice.google.com](https://voice.google.com). Full steps appear in the app when you choose Google Voice; use this checklist so documentation matches the product: 1. **Link your AI number** — In Google Voice, open **Settings** (gear) → under **Account**, **New linked number**, and enter your AI agent phone number. Use **Verify by phone** (the small blue link); SMS verification may not be available—phone verification is required. Google Voice will call your AI number with a code; complete verification in Voice (e.g. from the **Calls** tab / recording or transcript, as the app describes). 2. **Forwarding rule** — **Calls** → **Create a rule** → choose who should forward (e.g. **All contacts**) → under **Forward to these numbers**, select your **linked AI number**. Turn **call screening** off; if you hear *"To accept the call, press 1"*, screening is still on—go back and disable it. See [Use custom call forwarding with Google Voice](https://support.google.com/voice/answer/11420769). 3. **Caller ID when forwarding (required)** — In **Settings → Calls**, turn **off** **Show my Google Voice number as caller ID when forwarding calls**. If this stays **on**, the line that receives the forward (your AI number) may only see your **Google Voice number** instead of each **caller's real number**, which breaks correct caller identification for your agent. See [Change caller ID for incoming calls (Google Voice Help)](https://support.google.com/voice/answer/9526789). Google notes this setting does **not** apply to Voice calls placed **over the internet**—those already show the caller's number. #### TextNow Call forwarding on TextNow requires an **Ad-Free+** subscription. Once you have Ad-Free+, configure forwarding from the TextNow app: tap the main menu (top left) → **Settings → Calling → Call Forwarding**, toggle **Call Forwarding** to **ON**, and enter your AI agent phone number when prompted. To change the number later, tap **Forward To** on the Call Forwarding page. See [What is Ad-Free+](https://help.textnow.com/hc/en-us/articles/360043012413-What-is-Ad-Free). ## How to Disable Call Forwarding ### Mobile & Landlines Follow the deactivation instructions we provide in the app. The dial codes are also listed in the table above for convenience—use the code that matches your carrier and the forwarding type you activated. The deactivation code does not require your phone number; just dial the code directly. After you've deactivated with your carrier, the app will ask you to confirm so our settings stay in sync with your actual call forwarding state. If you turned off **Live Voicemail** or **Screen Unknown Callers** (iOS) when setting up forwarding, you can turn them back on in Settings → Phone once call forwarding is disabled. ### VoIP: disable forwarding Follow the disable instructions we provide in the app for your VoIP provider. After you've deactivated with your provider, the app will ask you to confirm so our settings stay in sync with your actual call forwarding state. **Google Voice:** On a computer, open [voice.google.com](https://voice.google.com) → **Calls** → find the rule that forwards to your AI number → open it and **delete** the rule. Optionally, in **Settings → Account**, remove your AI number from **linked numbers** if you no longer want it linked. **TextNow:** In the TextNow app, tap the main menu (top left) → **Settings → Calling → Call Forwarding**, then toggle **Call Forwarding** to **OFF**. *** # Call Transfers ## What are Call Transfers? Call transfers allow your AI agent to route live calls to a human agent (like you or your team) when the caller needs to speak with a real person. The AI agent intelligently recognizes when a transfer is needed based on the prompts you configure. ## Why Call Transfers Matter As capable as AI voice agents are, it's important that customers can still reach a real person when needed. Some situations require human judgment, empathy, or expertise that only a person can provide. Call transfers ensure your customers always have a path to human assistance when necessary. ## How Call Transfers Work Each call transfer consists of: * **Name**: A descriptive name for the transfer (e.g., "Sales Team" or "Support Line") * **Phone Number**: The number where calls in this category should be transferred * **Prompt**: The specific condition that tells the AI when to use this transfer You can configure up to 10 call transfers per AI agent. ## Warm Handoffs When the AI agent transfers a caller to you, you will receive a phone call from the agent's phone number. The agent first provides a summary of the conversation so far. This warm handoff gives you immediate context about what the caller has called about, what information has already been discussed, and any important details. You don't have to ask the same questions the AI already asked—you can pick up right where the conversation left off, providing a seamless experience for your customer. ## Writing Effective Transfer Prompts Transfer prompts must be explicit and specific for the AI to recognize when to use them. Be clear about the scenarios that should trigger a transfer. **Good examples:** * "Transfer to sales when the caller asks about pricing or wants to make a purchase" * "Transfer to support when the caller reports a technical issue or needs troubleshooting help" * "Transfer to billing when the caller has questions about their invoice or payment" **Less effective examples:** * "Transfer if they need help" (too vague) * "Transfer for important calls" (not specific enough) ## Caller ID and Saving Your Number **Important:** When the AI agent transfers a call to you, the incoming call appears as coming from your **AI agent's phone number**, not the original caller's number. You **must** save your AI agent's phone number in your contacts so you recognize incoming transfers and answer them. If you don't recognize the number, you might miss important customer calls. The AI agent can also attempt to transfer to the same number multiple times if the first attempt goes unanswered, giving you multiple opportunities to pick up the call. *** # Agent Actions ## What are Agent Actions? During a call, your AI agent can take actions in the systems connected to your account—checking availability, looking up an account, or starting a booking. The agent does this mid-conversation, so the caller gets an answer on the spot instead of waiting for a callback. The actions available depend on what has been set up for your account. ## Results That Arrive Later Some actions take longer than a caller can wait—a booking that needs confirmation, or a quote that takes time to price. When the result is ready, it is delivered to the AI agent while the call is in progress, and the agent uses it in its next response. The caller is not interrupted, and the agent does not announce the update. If the result arrives after the call has ended, it cannot reach the caller—follow up with them directly. *** # Infinite Loop Prevention ## What is an Infinite Loop? An infinite loop occurs when a call forwarding configuration creates a circular routing pattern where calls bounce endlessly between numbers. The app automatically detects and prevents these configurations. ## When Infinite Loops Occur Infinite loop detection **only applies to "All Calls" forwarding**. Here's why: * **With "All Calls" forwarding**: Every inbound call is immediately redirected to the AI agent, including calls the agent itself places back to that number during a transfer. This creates an infinite loop: Call → Forward to AI → AI calls back → Forward to AI again → Loop continues. * **With "Missed Calls Only" forwarding**: Your phone rings first, giving you a chance to answer before the call forwards. If you don't pick up, the call goes to the agent. The agent can then try to call you back, and your phone rings again—no loop, just another opportunity for you to answer. The delay from ringing prevents the loop. ## How the App Prevents Infinite Loops The app automatically detects when a call forwarding + call transfer configuration could create a loop. The system warns you and blocks the configuration before it can be saved, preventing the issue from occurring. If you see an infinite loop warning, consider: * Changing your forwarding type from "All Calls" to "Missed Calls Only" * Adjusting your call transfer configuration to transfer to a different number *** # Blocked Calls ## What are Blocked Calls? You can block phone numbers in the app. Blocked numbers will **not** be picked up by the AI voice—they will not be responded to and will not go to voicemail. Blocking is best used for spam and other junk callers, and it saves you money since the AI won't answer those calls or use any AI processing on them. ## Important: Blocking does not stop calls to your business line **Blocking a number in Reach does not prevent that person from calling your business phone.** The call can still reach your line as usual—it is only blocked from being handled by your AI agent. This means: * The blocked caller can still reach you or your team if someone answers the phone * Blocked calls do not consume AI Voice usage * Blocked calls do not incur AI processing charges To stop a spam or junk caller from ringing your phone at all, block them on your phone or through your carrier—not only in Reach. ## How blocking works with call forwarding What happens when a blocked number calls depends on **how the call reaches your AI agent**. ### Scenario A: Caller dials your AI agent number directly The call goes straight to your AI agent. **The AI will not answer**, and the call will not use AI processing. ### Scenario B: Caller dials your business number (Missed Calls Only forwarding) 1. Your business phone rings and you see the caller. 2. If you do not answer, the call forwards to your AI agent. 3. **The AI will not answer** the forwarded call. Blocking only stops the AI—the caller can still ring your business line. Use phone or carrier blocking if you want those calls to never ring your phone. ### Scenario C: Caller dials your business number (All Calls forwarding) 1. The call is forwarded to your AI agent immediately—your business phone does not ring first. 2. **The AI will not answer**, and the call will not use AI processing. The caller may hear ringing or silence depending on your carrier; they will not reach a live person or the AI. ## Choosing the right approach | Goal | What to do | | --------------------------------------------------------- | ----------------------------------------------------------------------------------- | | Stop the AI from answering a number | Block in Reach | | Stop your business phone from ringing (Missed Calls Only) | Block on your phone or carrier | | Stop callers entirely when using All Calls forwarding | Block on your phone or carrier; Reach blocking still prevents the AI from answering | ## How to Block a Number You can block numbers in two ways: 1. **From Call Details**: After viewing a call in your call history, click the "Block number" button in the call details view. 2. **From Settings**: Go to Settings → Blocked Numbers and add a number manually. Once blocked, your AI agent will not answer calls from that number. Depending on your call forwarding setup, the caller may still be able to ring your business phone (see [How blocking works with call forwarding](#how-blocking-works-with-call-forwarding)). ## How to Unblock a Number To unblock a number, go to Settings → Blocked Numbers, find the number in your blocked list, and remove it. The number will immediately be able to reach your AI agent again. # Introduction Source: https://docs.embedreach.com/ai-voice/introduction Respond to incoming calls with an AI Voice agent. ## Overview An AI-powered voice answering service that handles incoming calls with natural language processing. Trained on your business data directly from your website, Reach's AI Voice feature includes call forwarding, call transfers to human agents, call recording, and AI-powered customer intake. ## User Experience for AI Voice When your users navigate to the embedded Reach UI, they will be prompted to set up their AI Voice agent. The onboarding process guides them through training the agent, testing it, configuring call forwarding, and setting up call transfers. Once complete, their voice agent is live and ready to handle calls. The business enters their website URL and Reach automatically scrapes it for business details like services offered, business hours, contact information, and more. The business can then review all the information Reach has extracted, edit it, or add additional knowledge manually in plain English. This ensures the AI agent has accurate, comprehensive information about the business. The business can place a test call directly within the app to interact with their AI agent. They can ask questions a typical customer might ask to verify the agent responds accurately and naturally. This allows them to make any needed adjustments before going live. If the business wants to forward calls from their existing phone number to their new AI phone number, they can configure call forwarding here. They'll select their phone type (cell, landline, or VoIP), carrier, and forwarding preference (All Calls, Missed Calls Only, or None). The system provides **carrier dial codes** for traditional carriers or **in-app steps** for supported VoIP providers (including Google Voice), then guides them through testing the setup. The business can configure call transfers to route calls to human agents when needed. Each transfer includes a name, phone number, and a prompt that tells the AI when to escalate the call. This ensures customers can always reach a real person when necessary, even though the AI handles most interactions. Once all steps are complete, the business receives their AI phone number and the agent is live. They can start receiving calls immediately, with the AI agent handling customer inquiries, and transfers routing complex issues to human agents when needed. ## Integrating AI Voice into your Platform Implementing AI Voice for your tenants requires these key technical steps: Decide how you want to expose Reach to your users. We currently support IFrame integration, which gives you control to match the look-and-feel of your platform. With the help of a shared secret, we allow you to automatically authenticate your users so they do not need to separately log into Reach. When initializing the SDK, set `feature: 'voice'` to load the AI Voice interface. See the [Embeddable UI](/embeddable-ui/integration-overview) section and [Initializing the SDK](/embeddable-ui/iframe/embedding#initializing-the-sdk) for configuration details. Connect your user data via our webhook integration (preferred method) to ensure AI Voice Agent has access to the most up-to-date customer information. Share customer identifiers (phone, email, etc.) and transaction data (orders, bookings, memberships, etc.) so that Reach can give context to the Voice Agent. See the [Data Sharing](/data-sharing/introduction) section for more details. ## Coming Soon We're expanding AI Voice integration options to give businesses even more ways to connect with their customers: * **React Component Integration**: Native React components for seamless integration into React-based applications. * **Website Widget**: Embed your AI voice agent directly on your website as an interactive widget. Visitors can instantly start conversations, ask questions, and get answers in real-time—turning every website visitor into a qualified lead. The widget provides a frictionless way for potential customers to engage with your business without picking up the phone, capturing leads 24/7 even when you're not available. # Tools & Live Call Updates Source: https://docs.embedreach.com/ai-voice/tools-and-live-call-updates Let a Voice agent call your API during a call, and push new information into a call that is still in progress. ## Overview A Voice agent does not have to answer only from what it already knows. You can give it **tools** — endpoints on your own API that the agent calls in the middle of a conversation, while the caller is still on the line. Some answers aren't ready that fast. A booking that needs a human to confirm, a quote that takes a minute to price — the agent can't hold the line while you finish. For those, you send the result to Reach once you have it, and the agent picks it up mid-call. The agent calls your API and waits for the answer. You call Reach when the answer is ready. ## Tools You configure tools in the Reach partner dashboard under **Agents → Tools**. Each tool is one endpoint on your API, described so the agent knows when to reach for it. Every tool has: * **A name and description.** The agent reads the description to decide when to call the tool, so write it for the agent: what the tool does, and when it is the right thing to do. * **A URL.** When the agent runs the tool, Reach sends an HTTP request here. * **A credential.** Pick the credential Reach sends with the request and how to attach it. Credentials stay on your platform and are never visible to the agent. * **Inputs.** Each input is one value Reach sends to your API every time the agent runs the tool. An input is either something the agent supplies from the conversation — "what day works for you?" — or something Reach fills in for you. Tools are defined once for your platform and are available to every tenant's Voice agent. A tool can be set inactive to hide it from agents without deleting it. The caller is on the line while your API is working. Answer quickly, and always answer with something. A timeout leaves the agent with nothing to say. ### Work that can't finish during the call When the work can't finish inside a phone call, split it in two: The agent calls your tool. You start the work and return immediately — a confirmation you've got it, plus anything the agent can usefully say right now. When the work finishes, push the result into the call with a live call update. If the call is still going, the agent uses it. Don't have the agent poll a status tool in a loop. Each poll adds dead air the agent can't fill. ## The current call ID Any tool input can be sourced from **Current Voice call ID** instead of being asked of the agent. Reach then fills that input with the ID of the call the agent is on, and sends it on every request. Because Reach fills it in: * It is always present, so the input can't be made optional. * The agent can't invent it, get it wrong, or be talked into changing it. It comes from the call's signed session, not from the conversation. The value is a Reach call ID — a UUID that identifies the call inside Reach: ```json theme={null} { "callId": "8f14e45f-ea6c-4c2b-9b21-b2c0f1f4b2a7" } ``` This is Reach's own identifier, not a phone-network or telephony call ID. You never need one of those — the Reach call ID is the only ID you use to address a call. Store it alongside whatever the tool call started; you'll need it to address the call later. ## Updating a call that's still in progress `PATCH /partner/voice/active-calls/{callId}` pushes new information into a call that is still connected. Send a partner-scoped JWT plus the `reach-tenant-id` header naming the tenant whose call it is — either the Reach tenant UUID or your own external tenant ID. ```bash cURL theme={null} curl -X PATCH https://api.embedreach.com/partner/voice/active-calls/8f14e45f-ea6c-4c2b-9b21-b2c0f1f4b2a7 \ -H "Authorization: Bearer YOUR_PARTNER_SCOPED_JWT" \ -H "reach-tenant-id: tenant_123" \ -H "Content-Type: application/json" \ -d '{ "context": { "booking_status": "confirmed", "booking_window": "Tuesday, 9am to 11am" } }' ``` ```javascript Node.js theme={null} const callId = '8f14e45f-ea6c-4c2b-9b21-b2c0f1f4b2a7'; const response = await fetch( `https://api.embedreach.com/partner/voice/active-calls/${callId}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${process.env.REACH_PARTNER_JWT}`, 'reach-tenant-id': 'tenant_123', 'Content-Type': 'application/json', }, body: JSON.stringify({ context: { booking_status: 'confirmed', booking_window: 'Tuesday, 9am to 11am', }, }), }, ); ``` ```json Response theme={null} { "success": true, "message": "Success", "data": { "callId": "8f14e45f-ea6c-4c2b-9b21-b2c0f1f4b2a7", "status": "active", "appliedContextKeys": ["booking_status", "booking_window"], "filteredContextKeys": [] } } ``` ### What you can send `context` is a flat object of field names to string values. | Limit | Value | | ---------------------- | ----------------------------------------------- | | Fields per request | 1 to 20 | | Field name length | 100 characters | | Value length | 500 characters | | Whole `context` object | 8,192 bytes (field names plus values, as UTF-8) | Values are always strings. Send `"true"`, not `true`; `"49.99"`, not `49.99`. ### Which fields are accepted Reach applies only the fields configured for your platform. Everything else comes back in `filteredContextKeys` with a reason, and is dropped: * `not_configured` — the field name isn't one of your platform's Voice fields, or it's a name Reach reserves. * `invalid_value` — the field is configured, but the value doesn't fit its type. A **Boolean** field needs `"true"` or `"false"`, an **Enum** field needs one of its configured choices, and a **String** field can't be empty. Any value containing control characters or `{{` / `}}` is filtered too, whatever the field's type. A request whose every field was filtered still returns `200`, so read `appliedContextKeys` to confirm what actually landed. Submitted values are never echoed back — the response names fields, never their contents. Your platform's Voice fields are configured by Reach, so ask your Reach contact to add a field before you start sending it. Fields carrying a caller's name, phone, email, or address can't be pushed this way; Reach resolves those from the call itself. Never send secrets, credentials, or regulated data as call context. Field names whose words read like credentials — `auth_token`, `apiKey`, `password`, and the like — are never applied; they come back in `filteredContextKeys` as `not_configured`. ### When the agent uses it Applied fields are available to the agent on its **next natural response**. An update does not interrupt the caller or make the agent speak. Context is data, not direction. The agent is told to treat these values as facts it may use, never as instructions to follow, so you can't steer a call by writing a sentence into a field. ### Only while the call is live A call can only be updated while it is in progress. Once it has completed, disconnected, or failed, the update returns `409` and nothing is applied. If your answer arrives after the call ends, follow up through another channel. ### Retries * Sending the same update twice is safe — the repeat applies the same values. * Two different updates to the same field: the last one wins. * Limits apply per platform (60 updates per minute) and per call (10 per minute). The tighter per-call limit stops a stuck integration from flooding one live conversation. | Status | Meaning | | ------ | ------------------------------------------------------------------------------------------------------------ | | `200` | Applied. Read `appliedContextKeys` and `filteredContextKeys`. | | `400` | The body, the `reach-tenant-id` header, or the call ID is malformed — including a call ID that isn't a UUID. | | `404` | No call with that ID for that tenant. | | `409` | The call is no longer in progress. | | `424` | The update was rejected. Retrying won't change the answer. | | `429` | Too many updates. Back off, then retry. | | `503` | Temporary failure. Retry the same request as-is. | `404` covers both a call ID that doesn't exist and one belonging to a different tenant. Reach answers both the same way, so a call ID can't be used to probe for calls you don't own. See [Update an active Voice call](/api-reference/endpoint/patch-partner-voice-active-calls-callid) for the full request and response schema. # Default Partner Resources Source: https://docs.embedreach.com/api-reference/endpoint/default-partner-resources-introduction Convenience endpoints for default resource schemas Reach provides three default resource schemas that are available to partners upon request: **customers**, **locations**, and **transactions**. These schemas come pre-configured with common fields and can be used immediately once enabled for your partner account. These default schemas can be customized to match your specific data structure. See [Schema Definitions](/api-reference/endpoint/get-partner-schema-definitions) for information on customizing or creating your own schemas. ## Available Default Schemas * **customers**: For storing customer/user data * **locations**: For storing business location data * **transactions**: For storing transaction/order data ## Using Default Resource Endpoints The endpoints in this section provide convenient shortcuts for all CRUD operations on the default resource schemas. These endpoints are equivalent to using the generic [Partner Resources](/api-reference/endpoint/get-api-resources-schemadefinitionnameorid) endpoints with the schema name (`customers`, `locations`, or `transactions`). Operations supported: * **Create**: Single and batch upload * **Read**: List all resources or get by external ID * **Update**: Patch single resource or batch patch * **Delete**: Delete single resource or batch delete # Batch Delete Customer Resources Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-customers-batch DELETE /api/resources/customers/batch Deletes customer resources via the event processor for asynchronous processing. Set cascade to true to also delete referencing resources in other schemas. Set deleteAll to true to delete all customers — without cascade, customers referenced by other schemas are left in place; with cascade, referencing resources are also deleted. # Delete Customer Resource Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-customers-externalid DELETE /api/resources/customers/{externalId} Deletes a single customer resource identified by its external ID # Batch Delete Location Resources Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-locations-batch DELETE /api/resources/locations/batch Deletes location resources via the event processor for asynchronous processing. Set cascade to true to also delete referencing resources in other schemas. Set deleteAll to true to delete all locations — without cascade, locations referenced by other schemas are left in place; with cascade, referencing resources are also deleted. # Delete Location Resource Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-locations-externalid DELETE /api/resources/locations/{externalId} Deletes a single location resource identified by its external ID # Batch Delete Resources Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-schemadefinitionnameorid-batch DELETE /api/resources/{schemaDefinitionNameOrId}/batch Deletes resources within a schema via the event processor for asynchronous processing. Pass externalIds to delete specific resources. Set cascade to true to also delete referencing resources in other schemas. Set deleteAll to true (externalIds must be empty) to target all resources for the schema — without cascade, any resource referenced by another schema is left in place (not deleted); with cascade, referencing resources in other schemas are also deleted. The batch ID can be used to retrieve the status of the batch using the /api/batches/:batchId endpoint. # Delete Resource Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-schemadefinitionnameorid-externalid DELETE /api/resources/{schemaDefinitionNameOrId}/{externalId} Deletes a single resource identified by its schema and external ID # Batch Delete Transaction Resources Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-transactions-batch DELETE /api/resources/transactions/batch Deletes transaction resources via the event processor for asynchronous processing. Set cascade to true to also delete referencing resources in other schemas. Set deleteAll to true to delete all transactions — without cascade, transactions referenced by other schemas are left in place; with cascade, referencing resources are also deleted. # Delete Transaction Resource Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-resources-transactions-externalid DELETE /api/resources/transactions/{externalId} Deletes a single transaction resource identified by its external ID # Delete Tenant Segment Source: https://docs.embedreach.com/api-reference/endpoint/delete-api-segments-id DELETE /api/segments/{id} Delete a tenant segment # Deactivate Schema Source: https://docs.embedreach.com/api-reference/endpoint/delete-partner-schema-definitions-schemaidorname DELETE /partner/schema-definitions/{schemaIdOrName} Deactivates a schema definition, hiding it from list endpoints and freeing its name for reuse. This action is irreversible. All resources using this schema must be deleted first, and the schema must not be used in schema mappings or referenced by other schemas. # Delete Tenant Source: https://docs.embedreach.com/api-reference/endpoint/delete-partner-tenants-id DELETE /partner/tenants/{id} Soft delete a tenant by id # List Tenant Automations Source: https://docs.embedreach.com/api-reference/endpoint/get-api-automations GET /api/automations List all tenant automations # Get Broadcast Experience Source: https://docs.embedreach.com/api-reference/endpoint/get-api-automations-has-broadcast-experience GET /api/automations/has-broadcast-experience Get whether the business has enough broadcast history to be past email best-practices guidance # Get Tenant Automation Source: https://docs.embedreach.com/api-reference/endpoint/get-api-automations-id GET /api/automations/{id} Get a tenant automation by id # Get Recipients for Tenant Automation Source: https://docs.embedreach.com/api-reference/endpoint/get-api-automations-id-recipients GET /api/automations/{id}/recipients Get recipients for a tenant automation by id # Get Statistics for Tenant Automation Source: https://docs.embedreach.com/api-reference/endpoint/get-api-automations-id-statistics GET /api/automations/{id}/statistics Get statistics for a tenant automation by id # Get Statistics for All Tenant Automations Source: https://docs.embedreach.com/api-reference/endpoint/get-api-automations-statistics GET /api/automations/statistics Get statistics for all tenant automations # List Batch Jobs Source: https://docs.embedreach.com/api-reference/endpoint/get-api-batches GET /api/batches Retrieves all batch jobs for a business with pagination. # Get Batch Status Source: https://docs.embedreach.com/api-reference/endpoint/get-api-batches-batchid GET /api/batches/{batchId} Retrieves the current status, progress, and any error details for a batch operation. # List Channel Accounts Source: https://docs.embedreach.com/api-reference/endpoint/get-api-channel-accounts GET /api/channel/accounts List all channel accounts for a business # List Channel Senders Source: https://docs.embedreach.com/api-reference/endpoint/get-api-channel-senders GET /api/channel/senders List all channel senders for a business # List Communication Groups Source: https://docs.embedreach.com/api-reference/endpoint/get-api-communication-groups GET /api/communication-groups List all communication groups # Get Link Click Statistics Source: https://docs.embedreach.com/api-reference/endpoint/get-api-communication-groups-automationid-link-click-stats GET /api/communication-groups/{automationId}/link-click-stats Get link click statistics for an automation # Get Communication Group Source: https://docs.embedreach.com/api-reference/endpoint/get-api-communication-groups-id GET /api/communication-groups/{id} Get a communication group by id # Get Available Merge Fields Source: https://docs.embedreach.com/api-reference/endpoint/get-api-communication-groups-id-merge-fields GET /api/communication-groups/{id}/merge-fields Get available merge fields for a communication group # Get Resource Counts Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-counts GET /api/resources/counts Returns the count of each resource type (schema definition) for the authenticated tenant. Useful for monitoring data syncing and comparing numbers with partner databases. # List Customer Resources Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-customers GET /api/resources/customers Retrieves all customer resources. Can include reference fields to resolve and filter by field values. Supports pagination using cursor and limit parameters. # Get Customer Resource Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-customers-externalid GET /api/resources/customers/{externalId} Retrieves a customer resource by its external ID. Can include reference fields to resolve and filter by field values. # List Location Resources Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-locations GET /api/resources/locations Retrieves all location resources. Can include reference fields to resolve and filter by field values. Supports pagination using cursor and limit parameters. # Get Location Resource Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-locations-externalid GET /api/resources/locations/{externalId} Retrieves a location resource by its external ID. Can include reference fields to resolve and filter by field values. # List Resources Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-schemadefinitionnameorid GET /api/resources/{schemaDefinitionNameOrId} Retrieves all resources using schema name or ID. Can include reference fields to resolve and filter by field values. Supports pagination using cursor and limit parameters. # Get Resource Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-schemadefinitionnameorid-externalid GET /api/resources/{schemaDefinitionNameOrId}/{externalId} Retrieves a resource by its external ID. Can include reference fields to resolve and filter by field values. # List Transaction Resources Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-transactions GET /api/resources/transactions Retrieves all transaction resources. Can include reference fields to resolve and filter by field values. Supports pagination using cursor and limit parameters. # Get Transaction Resource Source: https://docs.embedreach.com/api-reference/endpoint/get-api-resources-transactions-externalid GET /api/resources/transactions/{externalId} Retrieves a transaction resource by its external ID. Can include reference fields to resolve and filter by field values. # List Tenant Segments Source: https://docs.embedreach.com/api-reference/endpoint/get-api-segments GET /api/segments List all tenant segments # Get Segment Conditions Source: https://docs.embedreach.com/api-reference/endpoint/get-api-segments-conditions GET /api/segments/conditions Get all available segment conditions # Get Tenant Segment Source: https://docs.embedreach.com/api-reference/endpoint/get-api-segments-id GET /api/segments/{id} Get a tenant segment by id # Get Users in Tenant Segment Source: https://docs.embedreach.com/api-reference/endpoint/get-api-segments-id-users GET /api/segments/{id}/users Get users in a tenant segment by id # Get Segments by User External ID Source: https://docs.embedreach.com/api-reference/endpoint/get-api-segments-user-externalid GET /api/segments/user/{externalId} Get all segments a user belongs to by their external ID # List Sending Domains Source: https://docs.embedreach.com/api-reference/endpoint/get-api-sending-domains GET /api/sending-domains List all email sending domains for a business # Get Sending Domain Source: https://docs.embedreach.com/api-reference/endpoint/get-api-sending-domains-id GET /api/sending-domains/{id} Get a single sending domain by id # List Subscriptions Source: https://docs.embedreach.com/api-reference/endpoint/get-api-subscriptions GET /api/subscriptions List all subscription information for a resource. Note: This is sorted by lastSubscriptionChangeAt in descending order # Get Subscription by External ID Source: https://docs.embedreach.com/api-reference/endpoint/get-api-subscriptions-externalid GET /api/subscriptions/{externalId} Get subscription information for a specific user by their external ID # List Channel Integrations Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-channel-integrations GET /partner/channel/integrations List all channel integrations for a business # Get Engage usage per tenant Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-engage-tenants GET /partner/engage/tenants Returns every tenant using Engage — one that finished the Engage onboarding wizard, has sent a message, has created a broadcast or has an active automation, or has an SMS number — ranked by total sends. Email and SMS send counts cover the optional date range (startDate, endDate); active automation and SMS number counts are current state. # Get partner-wide Engage tenant usage summary Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-engage-tenants-summary GET /partner/engage/tenants/summary Returns platform-level rollups (tenant count, emails sent, SMS sent) for the same tenant set and date filters as the paginated Engage tenants endpoint. # Get Resource Counts for All Tenants Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-resources-counts GET /partner/resources/counts Returns the count of each resource type (schema definition) for all tenants of the authenticated partner. Counts are grouped by tenant external ID and schema definition. Useful for monitoring data syncing across all tenants and comparing numbers with partner databases. Supports pagination with cursor and limit parameters. # List Schemas Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-schema-definitions GET /partner/schema-definitions Retrieves all active schema definitions for your system # Get Schema Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-schema-definitions-schemaidorname GET /partner/schema-definitions/{schemaIdOrName} Retrieves a specific schema definition by ID or name # Get Partner Schema Mappings Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-schema-mappings GET /partner/schema-mappings Get partner schema mappings (Used to map important fields from partner resources to Reach Functions) # List Tenants Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-tenants GET /partner/tenants List all tenants # Get Tenant Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-tenants-id GET /partner/tenants/{id} Get a tenant by id or external id # Get Tenant Resource Statistics Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-tenants-id-resource-stats GET /partner/tenants/{id}/resource-stats Get resource counts grouped by schema for a tenant # Get SMS Registration Status Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-tenants-id-sms-registration GET /partner/tenants/{id}/sms-registration Get SMS registration application status for a tenant. Returns null if no application exists. # Get voice call aggregates per tenant Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-voice-calls-aggregates GET /partner/voice/calls/aggregates Returns aggregated voice call statistics grouped by tenant for the partner platform. Supports optional date range (startDate, endDate). # Get partner-wide voice call aggregate summary Source: https://docs.embedreach.com/api-reference/endpoint/get-partner-voice-calls-aggregates-summary GET /partner/voice/calls/aggregates/summary Returns platform-level rollups (active tenant count, total calls, duration, cost) for the same date filters as tenant aggregates. Separate from the paginated per-tenant aggregates endpoint. # Update Tenant Automation Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-automations-id PATCH /api/automations/{id} Update a tenant automation # Update Channel Account Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-channel-accounts-id PATCH /api/channel/accounts/{id} Update a channel account # Update Channel Sender Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-channel-senders-id PATCH /api/channel/senders/{id} Update a channel sender # Update Communication Group Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-communication-groups-id PATCH /api/communication-groups/{id} Update a communication group # Batch Patch Customer Resources Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-customers-batch PATCH /api/resources/customers/batch Patches multiple customer resources in a single batch via the event processor for asynchronous processing. # Patch Customer Resource Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-customers-externalid PATCH /api/resources/customers/{externalId} Updates a customer resource by its external ID. This is an incremental update, only provided fields will be updated. # Batch Patch Location Resources Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-locations-batch PATCH /api/resources/locations/batch Patches multiple location resources in a single batch via the event processor for asynchronous processing. # Patch Location Resource Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-locations-externalid PATCH /api/resources/locations/{externalId} Updates a location resource by its external ID. This is an incremental update, only provided fields will be updated. # Batch Patch Resources Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-schemadefinitionnameorid-batch PATCH /api/resources/{schemaDefinitionNameOrId}/batch Patches multiple resources in a single batch via the event processor for asynchronous processing. Fields not included in the request are left unchanged. Null values will explicitly delete the field (required fields cannot be deleted and will return a validation error). The batch ID can be used to retrieve the status of the batch using the /api/batches/:batchId endpoint. The maximum number of resources that can be updated in a single batch is 1000.There are NO ordering guarantees across multiple batches. Within each batch, the patches for each resource are processed in the order they are received. # Patch Resource Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-schemadefinitionnameorid-externalid PATCH /api/resources/{schemaDefinitionNameOrId}/{externalId} Updates a resource by its external ID. This is an incremental update, only provided fields will be updated. Fields not included in the request are left unchanged. Null values will explicitly delete the field (required fields cannot be deleted and will return a validation error). # Batch Patch Transaction Resources Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-transactions-batch PATCH /api/resources/transactions/batch Patches multiple transaction resources in a single batch via the event processor for asynchronous processing. # Patch Transaction Resource Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-resources-transactions-externalid PATCH /api/resources/transactions/{externalId} Updates a transaction resource by its external ID. This is an incremental update, only provided fields will be updated. # Update Tenant Segment Source: https://docs.embedreach.com/api-reference/endpoint/patch-api-segments-id PATCH /api/segments/{id} Update a tenant segment # Update Channel Integration Source: https://docs.embedreach.com/api-reference/endpoint/patch-partner-channel-integrations-id PATCH /partner/channel/integrations/{id} Update a channel integration # Update Tenant Source: https://docs.embedreach.com/api-reference/endpoint/patch-partner-tenants-id PATCH /partner/tenants/{id} Update a tenant # Update an active Voice call Source: https://docs.embedreach.com/api-reference/endpoint/patch-partner-voice-active-calls-callid PATCH /partner/voice/active-calls/{callId} Pushes new context onto one of your tenant’s active Voice calls, addressed by its Reach call ID. Accepted fields become available to the agent on its next natural response. Fields that are not configured for the tenant, or whose values fail their configured type, are reported back as filtered without echoing the submitted values. Calls that have ended return a conflict. Updates are rate limited per partner and per call, and a 503 means the request can be retried as-is. # Create or Duplicate Tenant Automation Source: https://docs.embedreach.com/api-reference/endpoint/post-api-automations POST /api/automations Create a new tenant automation in the draft state # Create Channel Account Source: https://docs.embedreach.com/api-reference/endpoint/post-api-channel-accounts POST /api/channel/accounts Create a new channel account # Create Channel Sender Source: https://docs.embedreach.com/api-reference/endpoint/post-api-channel-senders POST /api/channel/senders Create a new channel sender # Create Communication Group Source: https://docs.embedreach.com/api-reference/endpoint/post-api-communication-groups POST /api/communication-groups Create a new communication group # Reset Communication Group to Default Template Source: https://docs.embedreach.com/api-reference/endpoint/post-api-communication-groups-communicationgroupid-automationid-reset POST /api/communication-groups/{communicationGroupId}/{automationId}/reset Reset a communication group to the default template # Send Test Email/SMS Source: https://docs.embedreach.com/api-reference/endpoint/post-api-communication-groups-id-test POST /api/communication-groups/{id}/test Send a test email/sms to the specified communication group # Upload SQLite database for a tenant Source: https://docs.embedreach.com/api-reference/endpoint/post-api-partner-db-upload POST /api/partner-db/upload Upload a SQLite database file for the authenticated Tenant. Use this when each of your tenants has its own database. Send the file as multipart/form-data with the field name "file". Accepted formats: .db (raw SQLite) or .db.gz (gzip-compressed). Data is synced automatically on a schedule after upload. **Note:** This is an experimental feature. If you are interested in using it, please contact us. # Create Customer Resource Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-customers POST /api/resources/customers Creates a single customer resource using the default customer schema. # Batch Upload Customer Resources Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-customers-batch POST /api/resources/customers/batch Uploads multiple customer resources via the event processor for asynchronous processing. This is more efficient for large batches of data. # Create Location Resource Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-locations POST /api/resources/locations Creates a single location resource using the default location schema. # Batch Upload Location Resources Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-locations-batch POST /api/resources/locations/batch Uploads multiple location resources via the event processor for asynchronous processing. This is more efficient for large batches of data. # Upload Resource Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-schemadefinitionnameorid POST /api/resources/{schemaDefinitionNameOrId} Uploads data to the partner resource table after validating it against the specified schema definition. When upsert is enabled, new data is merged with existing data (preserving existing fields not included in the request). Null values will explicitly delete the field (required fields cannot be deleted and will return a validation error). # Batch Upload Resources Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-schemadefinitionnameorid-batch POST /api/resources/{schemaDefinitionNameOrId}/batch Uploads multiple resources via the event processor for asynchronous processing. This is more efficient for large batches of data. When upsert is enabled, new data is merged with existing data (PATCH-like behavior), preserving existing fields. Null values will explicitly delete the field (required fields cannot be deleted and will return a validation error). The batch ID can be used to retrieve the status of the batch using the /api/batches/:batchId endpoint. The maximum number of resources that can be uploaded in a single batch is 1000. If dependencyWaitTimeout is set to a value > 0, resources with missing dependencies (from schema definitions using $ref fields) will be stored in a pending state. The pending resources will be automatically processed once their dependencies become available. The pending resources will be deleted after the specified duration (dependencyWaitTimeout) if their dependencies are not available. The default value for dependencyWaitTimeout is 0, which means that resources with missing dependencies will be rejected immediately. # Create Transaction Resource Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-transactions POST /api/resources/transactions Creates a single transaction resource using the default transaction schema. # Batch Upload Transaction Resources Source: https://docs.embedreach.com/api-reference/endpoint/post-api-resources-transactions-batch POST /api/resources/transactions/batch Uploads multiple transaction resources via the event processor for asynchronous processing. This is more efficient for large batches of data. # Create Tenant Segment Source: https://docs.embedreach.com/api-reference/endpoint/post-api-segments POST /api/segments Create a new tenant segment # Enable Standard Google Ads Audiences Source: https://docs.embedreach.com/api-reference/endpoint/post-api-segments-audience-uploads-standard POST /api/segments/audience-uploads/standard Create or reuse standard tenant segments and enable Google Ads audience publishing for a connected Google ad account. # Get Count of Users in Include and Exclude Segment Source: https://docs.embedreach.com/api-reference/endpoint/post-api-segments-count POST /api/segments/count Get count of users in an include and exclude segment # Text to Segment Builder Source: https://docs.embedreach.com/api-reference/endpoint/post-api-segments-text-to-segment POST /api/segments/text-to-segment Text to segment builder # Create Sending Domain Source: https://docs.embedreach.com/api-reference/endpoint/post-api-sending-domains POST /api/sending-domains Register a tenant-supplied sending domain and return the DNS records required to verify it # Create Entri Token Source: https://docs.embedreach.com/api-reference/endpoint/post-api-sending-domains-entri-token POST /api/sending-domains/entri-token Issue a short-lived token for the Entri DNS setup modal # Start Sending Domain Verification Source: https://docs.embedreach.com/api-reference/endpoint/post-api-sending-domains-id-verifications POST /api/sending-domains/{id}/verifications Start DNS verification for a tenant-supplied sending domain # Create Channel Integration Source: https://docs.embedreach.com/api-reference/endpoint/post-partner-channel-integrations POST /partner/channel/integrations Create a new channel integration # Upload SQLite database (platform-wide) Source: https://docs.embedreach.com/api-reference/endpoint/post-partner-partner-db-upload POST /partner/partner-db/upload Upload a single SQLite database file for your entire platform. Use this when you have one shared database across all tenants. Send the file as multipart/form-data with the field name "file". Accepted formats: .db (raw SQLite) or .db.gz (gzip-compressed). Data is synced automatically on a schedule after upload. **Note:** This is an experimental feature. If you are interested in using it, please contact us. # Create Schema Source: https://docs.embedreach.com/api-reference/endpoint/post-partner-schema-definitions POST /partner/schema-definitions Creates a new schema definition # Update Schema Source: https://docs.embedreach.com/api-reference/endpoint/post-partner-schema-definitions-schemaidorname POST /partner/schema-definitions/{schemaIdOrName} Updates an existing schema definition. The update can take up to 3 mins to take effect. # Update Partner Schema Mappings Source: https://docs.embedreach.com/api-reference/endpoint/post-partner-schema-mappings POST /partner/schema-mappings Update partner schema mappings (Used to map important fields from partner resources to Reach Functions) # Create Tenant Source: https://docs.embedreach.com/api-reference/endpoint/post-partner-tenants POST /partner/tenants Create a new tenant # Reactivate Tenant Source: https://docs.embedreach.com/api-reference/endpoint/post-partner-tenants-id-reactivate POST /partner/tenants/{id}/reactivate Reactivate a soft-deleted tenant by id # Overview Source: https://docs.embedreach.com/api-reference/endpoint/schema-definitions-introduction Define the shape of your data before you send it A **schema definition** describes your data as it exists in your system — a JSON Schema for your customers, transactions, locations, or any custom record type. These endpoints let you create, read, update, and list those definitions. Defining a schema is self-service; you don't need to wait on Reach to do it for you. **New to this? Read the concepts first — they'll save you a redesign.** Schema definitions are one half of a two-part model, and the shape you choose here determines what your tenants can segment and message on later. * [How Reach models your data](/data-sharing/data-model) — the three canonical concepts (contact, transaction, location), and the definition-vs-mapping distinction. * [Custom Schemas](/data-sharing/custom-schemas) — the JSON Schema format, `$ref` references between schemas, categories, and PII annotations. * [Data Sync Setup](/onboarding/data-sync-setup) — how defining schemas fits into onboarding. A definition on its own is just a shape Reach stores. To turn it into a contact, transaction, or location, pair it with a [Schema Mapping](/api-reference/endpoint/get-partner-schema-mappings). Validation is strict, and it protects existing data: you can always **add** fields, but **removing, renaming, or retyping** a field that resources already use is restricted, and fields that live tenant segments or merge fields depend on are protected. Iterate freely before go-live; be deliberate after. # Overview Source: https://docs.embedreach.com/api-reference/endpoint/schema-mappings-introduction Tell Reach how to read your data as its core concepts A **schema mapping** tells Reach how to interpret your [schema definitions](/api-reference/endpoint/get-partner-schema-definitions) in terms of its three canonical concepts — **contact**, **transaction**, and **location**. It's the step that says "the `email` field on this schema is the contact's email," "this schema is a `transactions_schema` and `transactionTotal` is the amount," and so on. **Definition vs. mapping is the distinction partners most often trip on — read this before you map.** * A **definition** is *the shape of your data* (your field names, your structure). * A **mapping** is *how Reach reads that shape as its concepts*. Two steps, two parts of the UI. Start here: * [How Reach models your data](/data-sharing/data-model) — the concepts and the definition-vs-mapping split. * [Custom Schemas → Partner Schema Mappings](/data-sharing/custom-schemas#partner-schema-mappings) — the full mapping field reference for contacts, transactions, and locations. Define your schemas first, then map them. A mapping references a schema definition by ID, so the definition must exist before you can map it. # Overview Source: https://docs.embedreach.com/api-reference/endpoint/tenants-introduction Create and manage the businesses you serve A **tenant** is one of your customers — a business you manage on behalf of your platform. Creating one is the first call you make against the Reach API: it returns the tenant `id` that every other tenant-scoped call, JWT, and embedded UI session refers back to. ## Identifying a tenant A tenant has two identifiers: the Reach `id` returned by **Create Tenant**, and the `externalId` you supply — your own key for the same business. **Get**, **Update**, **Delete**, and **Reactivate** each accept either one in the path, so you never have to store the Reach `id` if you would rather look tenants up by your own. ## Lifecycle `POST /partner/tenants` with a name and your `externalId`. Reach provisions the tenant's default resources asynchronously, so some of them appear shortly after the response returns rather than in it. `PATCH /partner/tenants/{id}` — every field is optional, so send only what changed. `DELETE /partner/tenants/{id}` deactivates rather than destroys. The tenant drops out of **List Tenants** unless you pass `includeDeleted=true`, and **Get Tenant** keeps returning it with `deletedAt` set. `POST /partner/tenants/{id}/reactivate` restores a deactivated tenant with its data intact. ## What lives on a tenant | Field | What it is for | | --------------------------- | -------------------------------------------------------------------------------------------- | | `name`, `website` | How the business is identified across Reach, and the site the tracking snippet reports from | | `locations` | The business's physical addresses | | `branding` | Logo, colors, brand name, and brand voice — what the embedded UI and generated content adopt | | `timezone`, `businessHours` | When the business is open — see below | | `smsOptInImageUrls` | Evidence of how the business captures SMS consent, used for carrier registration | If your partner account is configured with a location schema, the `locations` you send are stored as location resources rather than on the tenant record. Reads return them either way, so the field behaves the same from your side. ### Merged fields and replaced fields On update, `branding` is **merged** key by key into what is already stored, so you can send just the keys you want to change. `locations`, `smsOptInImageUrls`, and `businessHours` are **replaced wholesale** — send the complete value every time, or you will drop what you left out. ## Listing tenants **List Tenants** is cursor-paginated through `cursor` and `limit` (default 100). Narrow it with `search`, which matches on name, external id, or website; order it with `orderBy` and `orderDirection`; include deactivated tenants with `includeDeleted=true`. For portfolio-wide sweeps, pass `fields` — a comma-separated projection such as `id,name` — to trim the payload to what you actually read. ## Timezone and business hours `timezone` and `businessHours` record when a tenant is open. Both are accepted on **Create Tenant** and **Update Tenant**, and returned by **Get Tenant**. They sit on the business itself rather than on any one product, so one schedule serves every Reach feature that needs it — AI Voice uses `timezone` today to give the agent the tenant's local time. You are the source of truth for both. Reach never infers a timezone from a tenant's address, and an unset value means *not configured* — it does not mean always open, and it does not mean always closed. `timezone` is any IANA timezone id — `America/New_York`, `Europe/London`, `Pacific/Honolulu`. Send `null` to clear it. `businessHours` is an object carrying all seven weekday keys, `monday` through `sunday`. Each key is either `null` or an empty list (closed that day), or a list holding exactly one interval of 24-hour `HH:MM` times: ```json theme={null} { "monday": [{ "open": "09:00", "close": "17:00" }], "tuesday": [{ "open": "09:00", "close": "17:00" }], "wednesday": [{ "open": "09:00", "close": "17:00" }], "thursday": [{ "open": "09:00", "close": "17:00" }], "friday": [{ "open": "09:00", "close": "20:00" }], "saturday": [{ "open": "10:00", "close": "14:00" }], "sunday": null } ``` Those are local wall-clock times in the tenant's `timezone`, never UTC. Reach reads them against the tenant's local clock at the instant it evaluates them, so daylight saving shifts resolve on their own. **The opening time is inclusive and the closing time is exclusive** — against `09:00`–`17:00`, a moment at exactly `09:00` counts as in hours, and a moment at exactly `17:00` does not. The schedule format is deliberately narrow for now: * **One interval per weekday.** Split shifts — a midday closure — are not supported yet. * **`open` must be earlier than `close`.** An interval cannot cross midnight, so overnight hours such as `20:00` to `02:00` cannot be expressed yet. * **All seven weekdays are required, and an update replaces the whole schedule.** There is no per-day merge: send every day on each update, and send `null` for the whole field to clear the schedule. Tenants can also edit their own timezone and hours from the Voice settings in the embedded Reach UI. Those edits write to the same business record, so **Get Tenant** can return values you did not send. Re-read the tenant if your system needs to stay in sync. # Introduction Source: https://docs.embedreach.com/api-reference/introduction Welcome to the Reach API ## Reach Developer MCP (Beta) Connect a compatible AI coding assistant to Reach's partner-wide and tenant-scoped APIs through WorkOS authentication without copying an API key or JWT secret into the assistant. Beta setup instructions, supported capabilities, and example prompts ## OpenAPI Specification Download our OpenAPI specification to import into Postman or other API tools: Download the complete OpenAPI 3.0 specification file ## Authentication API endpoints are authenticated using JWT tokens. Include your signed JWT token in the Authorization header of your requests: ```json theme={null} { "Authorization": "Bearer " } ``` To obtain a JWT secret, please reach out to the Reach team at [support@embedreach.com](mailto:support@embedreach.com) ### API Route Patterns Our API uses two route patterns with different authentication requirements: #### Partner Routes (`/partner/*`) APIs which begin with `/partner` use **partner-scoped JWT tokens** and are used for actions which apply to the partner as a whole. These routes manage partner-level resources and configurations. Some partner actions target a single tenant — for example, [updating an active Voice call](/ai-voice/tools-and-live-call-updates). Those routes take the `reach-tenant-id` header alongside the partner-scoped JWT to name the tenant being acted on. The endpoint's reference page says whether it needs the header. #### Tenant Routes (`/api/*`) APIs which begin with `/api/` are **tenant-scoped**. They can use either: * A **tenant-scoped JWT token** (the tenant is identified from the `tenantExternalId` field in the JWT, so no header is needed), OR * A **partner-scoped JWT token** with the `reach-tenant-id` header set (required), which allows you to take action on the specific tenant When using a partner-scoped JWT with tenant routes, you must include the tenant ID header: ```json theme={null} { "Authorization": "Bearer ", "reach-tenant-id": "" } ``` ### JWT Token Types We have two types of JWT tokens: #### Tenant Scoped JWT This is a JWT token that contains the tenant's external ID (`tenantExternalId`) and is signed with your partner secret. This can be used to send to your Frontend client in order to allow them to make requests that only have access to that tenant. #### Partner Scoped JWT This is a JWT token that contains your partner ID and is signed with your partner secret. This can be used to make requests to partner-level API endpoints or tenant-level endpoints when combined with the `reach-tenant-id` header. Learn more about [our JWT tokens](/embeddable-ui/authentication#jwt-token-requirements) # Introduction Source: https://docs.embedreach.com/attribution/introduction Understanding how Reach attributes marketing activities to business outcomes # Attribution & Tracking To give your businesses a more complete picture of their ads' effectiveness and to better target leads/users, Reach leverages data from your customers' websites and from your platform. ## How Attribution Works Attribution works as follows: 1. A visitor may click on an ad (or a link in a marketing email) and land on a business's website. When Reach is embedded on the website, it can automatically collect this information. 2. If that visitor eventually goes on to identify themselves through some action on the landing page (e.g. requests a quote with an email address or joins a loyalty program with a phone number), Reach can also capture this identifying information and tie it to the ad click. 3. Finally if that visitor eventually transacts with the business (and shares the same email or phone number), Reach can use this transaction data to show a comprehensive view of LTV driven from ads and email engagement. ## Benefits for Targeting The same transaction and customer information that's useful for showing return on ad spend is also helpful for targeting. Your customers can: * Use near-real time purchase data to define an audience for email/sms campaigns (e.g. all customers who haven't made a purchase in 60 days) * Use purchase events as notification triggers (e.g. ask customer for google review once their receipt is completed) * Send data back to ad platforms to optimize campaign targeting based on actual purchasing behavior ## Integration Components There are two components to the integration for attribution and targeting: Embed a javascript snippet in your clients' customer-facing websites or customer-facing widgets. If you don't control the client website, Reach will direct your customers on how to configure this during their onboarding. [Share customer and transaction data](/data-sharing/introduction) with Reach. # Setup Source: https://docs.embedreach.com/attribution/setup Installing and configuring the Reach attribution tracking # Website Snippet Reach attributes revenue to marketing activities using a business's first-party data – we provide a lightweight javascript snippet that can be injected onto a customer's public-facing landing page and tracks when a user lands on a business's website (after clicking on a marketing link) and then later identifies themselves on that same site. ## Who does what Attribution involves two parties, each with distinct responsibilities. **Partners** are responsible for implementing `createIdentification()` on their own app and owned surfaces — logged-in dashboards, post-signup flows, checkout confirmations, and any other page where your platform knows who the user is. Because these are surfaces you control, you wire up the identification calls directly in your application code. **Tenants (your businesses)** are responsible for a simpler task: adding the Reach tracking snippet to their own public-facing website. That's it. During onboarding, Reach handles the rest — we inspect the tenant's site, identify the forms where visitors submit their contact details (quote requests, lead capture forms, contact pages), and configure listeners that automatically fire `createIdentification` on the tenant's behalf. Tenants do not need to write any identification code themselves. Together, these two integration surfaces give Reach a complete picture: the snippet on the tenant's site captures anonymous visits and ad click attribution, Reach's configured listeners capture identifications from public forms, and your platform's `createIdentification` calls capture identifications from logged-in experiences. All of it feeds into a single attribution chain. The rest of this article covers the partner's implementation — how to load the snippet, the best practices around it, and how to call `createIdentification` from your application. ## Basic Installation Please ensure you load this javascript snippet on every page in your app. Add the script to the `` section of your HTML and for optimal performance, place it as early as possible. Embedding this snippet requires two parameters: * **PARTNER\_HASH** – a short, public-facing identifier assigned to your vertical SaaS platform by Reach. This will always be the same value – you can hard-code it into your application. * **TENANT\_EXTERNAL\_ID** – the unique, case-sensitive business ID you use to identify businesses in your platform. This must be the same ID you are setting on tenants that you create in the Reach system. Ideally, this is a value you already have available on any web pages that you host for your clients. Note: you will onboard the business to Reach when they opt-in to using Reach's services in the Management UI. ```html theme={null} ``` Please get in touch with our team if you have any questions about the best way to load the script if you're using your particular web development framework. ### Load it early Place the script tag in ``, not at the bottom of `` and not with `defer`. The snippet tracks page visits as soon as it loads — if it loads late, short sessions and fast bounces won't be recorded. Loading early also ensures `window.reach` is initialized before any `createIdentification` call fires. ### Embed it directly — don't use GTM Load the script tag directly on the page. Do **not** route it through Google Tag Manager or a similar tag management system. GTM is frequently blocked by ad blockers and privacy-focused browsers, which silently drops tracking coverage with no error surfaced to you. ### Don't cache the script aggressively Some of what `analytics.js` returns is server-driven configuration (per-tenant tracking settings, etc.). If you serve the script through a CDN or middleware that caches it with a long TTL, tenants won't pick up configuration updates without a deploy. Short cache windows (a few minutes) are fine; multi-hour or multi-day caches are not. ## Create Identifications The snippet exposes `window.reach.createIdentification(data)`, which ties the current visitor's anonymous session to a real identity. Call it whenever a visitor reveals who they are — this is what enables Reach to attribute a visit (and the ad click that drove it) back to a real customer. At least one of `email` or `phone` is required for a meaningful identification. `source_id` is a good place to pass your platform's internal user ID so Reach can deduplicate records across calls. `createIdentification` deduplicates calls within a session — calling it multiple times with the same data is safe and won't produce duplicate records. ### When to call it **Anonymous / form-based flows** — call `createIdentification` when the visitor submits a form that captures their contact details (quote request, contact us, lead capture, checkout, etc.): ```javascript theme={null} // Make sure this code is placed within a script tag AFTER the reach script is loaded window.reach.createIdentification({ email: 'test@example.com', phone: '+12223334444', f_name: 'test', l_name: 'example', // choose a meaningful name for each unique action that could trigger an identification source_id: 'appointment-scheduling-system', }); ``` **Logged-in experiences** — call `createIdentification` as soon as the visitor's identity is known. There are three moments to cover: 1. **After a successful login** ```javascript theme={null} async function handleLogin(credentials) { const user = await login(credentials); window.reach.createIdentification({ email: user.email, phone: user.phone, source_id: user.id, }); } ``` 2. **After account creation:** ```javascript theme={null} async function handleSignup(formData) { const user = await createAccount(formData); window.reach.createIdentification({ email: user.email, phone: user.phone, source_id: user.id, }); } ``` 3. **On page load when the visitor is already authenticated** (e.g. they return to a logged-in dashboard): ```javascript theme={null} if (currentUser) { window.reach.createIdentification({ email: currentUser.email, source_id: currentUser.id, }); } ``` ## Content Security Policy (CSP) Considerations If you have implemented a strict Content Security Policy (CSP) you may need to update it for the Reach app to be successful. The attribution snippet script is loaded from [https://public.embedreach.com](https://public.embedreach.com) and makes requests to [https://api.embedreach.com](https://api.embedreach.com). Assuming no other scripts on your website, an example strict CSP would look like this: ``` Content-Security-Policy: script-src 'self' https://public.embedreach.com; connect-src 'self' https://api.embedreach.com; ``` This CSP applies to the website attribution snippet only. If you are embedding\ the Reach UI via the SDK, use the CSP described in the [Security Headers (CSP & COOP)](/embeddable-ui/security-headers) guide. ## Onboarding Businesses to Reach Businesses will be automatically onboarded when they opt-in to using Reach's services in the Management UI. The externalId used here should be the same as the externalId passed in as onBusinessCreate() in the Management UI documentation. If your platform does not manage website creation and management on behalf of your clients, they will be shown instructions during Reach's onboarding flow for how to inject the snippet on the most common website creators. ## Cross-Domain Attribution Sometimes, what looks like one website is actually on multiple domains – some common versions of this: * Client owns their website / landing page, but they redirect to another page hosted by the vertical SaaS platform (e.g. "online ordering") where a user will put in their contact information. * Client owns their website / landing page, but they embed an iframe hosted by the vertical SaaS platform (e.g. "request an estimate" or "schedule a call" form) where a user will put in their contact information. The Reach attribution snippet will automatically handle cross-domain attribution for these use-cases as long as it is embedded on both sites. During the implementation process with Reach, please let the team know the domain your platform uses for these "identification" pages to ensure this works correctly. ## Error Handling The script is designed to fail gracefully – no additional error handling is required at this time. Please reach out to our team if you have any concerns. # Testing Source: https://docs.embedreach.com/attribution/testing Verifying your attribution tracking setup is working correctly # Testing Your Attribution Setup After implementing the Reach attribution snippet, it's important to verify your setup through a series of tests. Since attribution involves multiple components working together, we've structured the testing process into clear stages. ## Stage 1: Verify Script Implementation First, confirm that the script is properly installed on your pages: 1. Open your website in Chrome Developer Tools (press F12 or right-click and select "Inspect") 2. Go to the Network tab and filter for "analytics.js" or "embedreach.com" 3. Refresh the page and verify the script loads successfully with a 200 status code 4. Check the Console tab for any errors related to the Reach script **Successful outcome:** The script loads without errors in the network panel and console. ## Stage 2: Verify Configuration Parameters Next, confirm your PARTNER\_HASH and TENANT\_EXTERNAL\_ID are correctly implemented: 1. Check that the script URL in your implementation contains the correct values: ```html theme={null} ``` 2. Verify your PARTNER\_HASH matches the value provided by Reach 3. Confirm that your TENANT\_EXTERNAL\_ID matches the business ID in your platform **Important note:** The tenant must already be created in your system with the correct external ID that matches what's in the script. ## Stage 3: Test Attribution Flow Attribution testing can only be completed *after* Reach has finished the instrumentation process for your specific client. This typically occurs during the business onboarding phase and may take 1-3 business days after submitting client information. Once Reach confirms instrumentation is complete, test the full attribution flow: 1. Create a test marketing link with UTM parameters: ``` https://yourbusiness.com/landing?utm_source=test&utm_medium=email&utm_campaign=test ``` 2. Open an incognito/private browser window and click on your test link 3. Complete an identification action (form submission, account creation, etc.) 4. Check the Reach dashboard after 5-10 minutes to verify the attribution event was captured ## Debug Tools ### Debug Mode Add `reach_debug=true` as a URL parameter to enable detailed console logging: ``` https://yourbusiness.com/landing?reach_debug=true ``` With debug mode enabled, you'll see script initialization and configuration events logged to the console in real-time. ### Cross-Domain Testing If you're using Reach across multiple domains: 1. Verify the script is properly installed on both domains (Stage 1) 2. Confirm both scripts use the same TENANT\_EXTERNAL\_ID (Stage 2) 3. After instrumentation is complete, test the full flow across domains (Stage 3) ## Troubleshooting Common Issues | Issue | Possible Solution | | ---------------------------- | --------------------------------------------------------------------- | | Script not loading | Check your CSP settings and script URL | | Attribution not working | Confirm that Reach has completed instrumentation for your client | | Cross-domain issues | Verify the script is on all relevant domains with matching tenant IDs | | Form submissions not tracked | Wait for Reach to complete form selector setup during onboarding | If you've verified all stages and still encounter issues, please contact [support@embedreach.com](mailto:support@embedreach.com) with: 1. Your PARTNER\_HASH and TENANT\_EXTERNAL\_ID 2. URLs where the script is implemented 3. Any console errors observed 4. Description of the expected vs. actual behavior # Automations Source: https://docs.embedreach.com/automations/automations Overview of Automations # Tenant Automations ## Introduction Tenant Automations allow you to create automated communication workflows that trigger based on specific conditions and [segments](/segments/segments). These automations enable you to send targeted communications to users through various [channels](/engage/introduction) (currently email, with SMS planned for future releases). Please see the API Reference [here](/api-reference/endpoint/get-api-automations) for more information. ## Structure A tenant automation consists of: * **Name**: A descriptive name for the automation * **Status**: The current state of the automation. Can be: * `draft`: Automation is in draft mode and not active * `active`: Automation is enabled and will be processed * `running`: Currently being processed * `scheduled`: Has been scheduled and cannot be cancelled * `completed`: Has finished running * `failed`: Failed to run * `deactivated`: Manually disabled by user * **Business ID**: Links the automation to a specific tenant * **Trigger Type**: Defines when the automation should run. See [Trigger Types](#trigger-types) for more information. * **Trigger Metadata**: Configuration for the trigger. See [Trigger Metadata](#trigger-metadata) for more information. * **Action Data**: Array of actions to perform when triggered. See [Action Data](#action-data) for more information. * **Segments**: Include and exclude segments to target specific users. See [Segments](#segments) for more information. ## Segments Automations use a combination of include and exclude segments to determine which users should receive communications: 1. **Include Segments**: Users must be in this segment to receive communications 2. **Exclude Segments**: Users in this segment will not receive communications, even if they're in the include segment See [Segments](/segments/segments) for more information on creating and managing segments. ## Trigger Metadata Currently supported trigger types: ### One-Time Trigger * Scheduled to run at a specific date and time * Evaluates all users in the target segments * Creates communication jobs for eligible users * Example use case: Promotional campaign or announcement ## Action Data Action Data defines what operations the automation will perform when triggered. Each action in the array contains: * **action\_type**: The type of action to perform (currently supports `send_communication`) * **action\_metadata**: Configuration specific to the action type ### Send Communication Action For actions of type `send_communication`, the action\_metadata includes: * **communication\_group\_id**: Reference to the communication group containing the message configuration Example action data structure: ``` { "action_data": [ { "action_type": "send_communication", "action_metadata": { "action_type": "send_communication", "communication_group_id": "your-communication-group-id" } } ] } ``` Please see the [Channel Senders](/engage/channel-senders) documentation for more information on how to configure communication channels. # Introduction Source: https://docs.embedreach.com/automations/introduction Overview of Automations Reach's Automations system provides a powerful way to create automated communication workflows that trigger based on specific conditions and [segments](/segments/segments). Learn how to create and manage automations to send communications to specific groups of users # Custom schemas Source: https://docs.embedreach.com/data-sharing/custom-schemas # Custom Schemas Custom schemas allow you to define the structure of your data using JSON Schema. Each schema has a category that determines how it's used in the platform. **You can define and map schemas yourself.** Schema definitions and mappings are fully self-service — you create, update, and list them through the partner UI or the [schema-definitions API](/api-reference/endpoint/post-partner-schema-definitions), and you send data against them without waiting on us. That said, getting the *model* right — which records are contacts, transactions, and locations, and how they reference one another — is the part worth doing together. During onboarding we'll run a working session to review your schemas and mappings before you go live, and we're glad to pair on tricky relationships any time after. New to the model? Start with [How Reach models your data](/data-sharing/data-model) — it explains the three canonical concepts (contact, transaction, location) and the definition-vs-mapping distinction that the rest of this page builds on. ## Schema Categories Each schema must have a category that determines its purpose: * **`contacts_schema`**: Customer/contact information * **`transactions_schema`**: Transaction and billing data * **`custom_schema`**: General data models * **`locations_schema`**: Location/address data ## Schema Requirements Schema names must be URL-safe: * Only letters, numbers, hyphens (-), and underscores (\_) * No spaces or special characters * Must be unique (case-insensitive) ## PII Annotations Use `x-pii-type` to mark fields containing personally identifiable information: * `EMAIL`: Email addresses * `PHONE`: Phone numbers * `FIRST_NAME`, `LAST_NAME`, `NAME`: Name fields * `EXTERNAL_ID`: External identifiers ## Schema Examples ### contacts\_schema For customer/contact information: ```json theme={null} { "name": "Customer", "pluralName": "Customers", "description": "Customer contact information", "category": "contacts_schema", "external_id_field": "customerId", "schema": { "type": "object", "title": "Customer", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["customerId"], "properties": { "customerId": { "type": "string", "x-pii-type": "EXTERNAL_ID" }, "email": { "type": "string", "x-pii-type": "EMAIL" }, "phone": { "type": "string", "x-pii-type": "PHONE" }, "firstName": { "type": "string", "x-pii-type": "FIRST_NAME" }, "lastName": { "type": "string", "x-pii-type": "LAST_NAME" }, "emailOptOut": { "type": "boolean", "description": "Email subscription opt-out status. Defaults to false (opted in)" }, "smsOptOut": { "type": "boolean", "description": "SMS subscription opt-out status. Defaults to true (opted out)" }, "customerDetailUrl": { "type": "string", "description": "URL to click-out to the customer detail page" }, "createdAt": { "type": "string", "format": "date-time" } } } } ``` ### transactions\_schema For transaction/billing data: ```json theme={null} { "name": "Transaction", "pluralName": "Transactions", "description": "Transaction and billing information", "category": "transactions_schema", "external_id_field": "transactionId", "reference_schemas": ["Customer"], "schema": { "type": "object", "title": "Transaction", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["transactionId"], "properties": { "transactionId": { "type": "string", "x-pii-type": "EXTERNAL_ID", "description": "External ID" }, "customerId": { "$ref": "reach:schemas/Customer", "x-pii-type": "EXTERNAL_ID" }, "transactionDate": { "type": "string", "format": "date-time", "description": "Datetime ISO string with timezone when transaction occurred" }, "transactionTotal": { "type": "number", "description": "Transaction total in dollars" }, "transactionDetailUrl": { "type": "string", "description": "URL to click-out to the transaction detail page" } } } } ``` ### locations\_schema For location/address data: ```json theme={null} { "name": "Location", "pluralName": "Locations", "description": "Business location information", "category": "locations_schema", "external_id_field": "locationId", "schema": { "type": "object", "title": "Location", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["locationId", "name"], "properties": { "locationId": { "type": "string", "x-pii-type": "EXTERNAL_ID" }, "name": { "type": "string" }, "address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "zipCode": { "type": "string" } } } } ``` ### custom\_schema For general data models: ```json theme={null} { "name": "Product", "pluralName": "Products", "description": "Product catalog information", "category": "custom_schema", "external_id_field": "productId", "schema": { "type": "object", "title": "Product", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["productId", "name"], "properties": { "productId": { "type": "string", "x-pii-type": "EXTERNAL_ID" }, "name": { "type": "string" }, "price": { "type": "number" }, "category": { "type": "string" } } } } ``` ## Partner Schema Mappings After creating custom schemas, you need to configure **Partner Schema Mappings** to tell Reach which fields in your schemas correspond to important data we need to extract and use throughout the platform. Schema mappings define how Reach interprets your custom schema data for: * Contact management and communication preferences * Transaction processing and revenue tracking * Location data for multi-location businesses ### Available Schema Types #### contacts\_schema Mapping Maps customer/contact information from your schema to Reach's contact system: **Required Fields:** * `schemaId`: The ID of your contacts schema * `email`: Field name containing email addresses * `phone`: Field name containing phone numbers * `userId`: Field name for the unique user identifier **Optional Fields:** * `firstName`: Field name for first name * `lastName`: Field name for last name * `fullName`: Field name for full name (alternative to firstName/lastName) * `location`: Field name linking to location data * `emailOptOut`: Field name for email subscription status * `emailOptOutTimestamp`: Field name for email opt-out timestamp * `smsOptOut`: Field name for SMS subscription status * `smsOptOutTimestamp`: Field name for SMS opt-out timestamp * `urlPattern`: URL pattern for deep-linking to customer details (e.g., `/customers/{userId}`) * `status`: Object defining active/inactive status mapping * `field`: Field name containing status * `activeValue`: Value indicating active status * `deactivatedValue`: Value indicating inactive status * `createdDate`: Field name for account creation date #### transactions\_schema Mapping Maps transaction/billing data for revenue tracking and customer journey analysis: **Required Fields:** * `schemaId`: The ID of your transactions schema * `eventType`: Type of transaction event (e.g., "purchase", "subscription", "refund") * `id_field`: Field name for unique transaction identifier * `userId`: Field name linking to the customer * `amount`: Object defining monetary value mapping * `field`: Field name containing the amount * `currency`: Static currency code (e.g., "USD") **Optional Fields:** * `dates`: Object mapping various date fields * `currencyField`: Field name containing dynamic currency (optional, defaults to USD when not mapped) * `createdDate`: Transaction creation date * `paidDate`: Payment completion date * `dueDate`: Payment due date * `startDate`: Service start date * `endDate`: Service end date * `metadata`: Array of field names to include as metadata * `urlPattern`: URL pattern for deep-linking to transaction details * `filter`: JSONLogic rule for conditional event creation #### locations\_schema Mapping Maps location/address data for multi-location businesses: **Required Fields:** * `schemaId`: The ID of your locations schema * `id_field`: Field name for unique location identifier **Optional Fields:** * `name`: Location name/title * `address_line_1`: Primary address line * `address_line_2`: Secondary address line * `address_line_3`: Additional address line * `locality`: City/locality * `district`: State/province/district * `postal_code`: ZIP/postal code * `country_code`: Country code (ISO format) * `phone`: Location phone number * `email`: Location email address * `website`: Location website URL * `urlPattern`: URL pattern for deep-linking to location details ### Schema Mapping Configuration Schema mappings are configured through the Partner API and define a `combined_schema` structure: ```json theme={null} { "type": "combined_schema", "contactsSchema": { "primarySource": { "type": "contacts_schema", "schemaId": "{schemaDefinitionId}", "email": "email", "phone": "phone", "userId": "customerId", "firstName": "firstName", "lastName": "lastName", "emailOptOut": "emailOptOut", "smsOptOut": "smsOptOut", "urlPattern": "/customers/{customerId}", "status": { "field": "status", "activeValue": "active", "deactivatedValue": "inactive" } } }, "transactionsSchema": [{ "type": "transactions_schema", "eventType": "purchase", "schemaId": "{schemaDefinitionId}", "id_field": "transactionId", "userId": "customerId", "amount": { "field": "transactionTotal", "currency": "USD" }, "dates": { "createdDate": "transactionDate" }, "urlPattern": "/transactions/{transactionId}" }], "locationsSchema": [{ "type": "locations_schema", "schemaId": "{schemaDefinitionId}", "id_field": "locationId", "name": "name", "address_line_1": "address", "locality": "city", "district": "state", "postal_code": "zipCode" }] } ``` ### Field Mapping Examples #### URL Patterns URL patterns support field substitution using `{fieldName}` syntax: * Simple field: `/customers/{customerId}` * Nested field: `/orders/{orderId}?customer={customer.email}` * Multiple fields: `/locations/{locationId}/details?region={region}&type={businessType}` #### Status Mapping Define how your status values map to Reach's active/inactive system: ```json theme={null} { "field": "accountStatus", "activeValue": "ACTIVE", "deactivatedValue": "SUSPENDED" } ``` #### Date Field Mapping Map various date fields to track customer lifecycle: ```json theme={null} { "createdDate": "signupDate", "paidDate": "paymentCompletedAt", "startDate": "serviceStartDate", "endDate": "subscriptionExpiresAt" } ``` ## Schema References To reference another schema, use `$ref` with the `reach:schemas/` URI scheme: ```json theme={null} { "customerId": { "$ref": "reach:schemas/Customer" } } ``` When creating a schema with references: 1. Use `$ref` properties to reference other schemas 2. Referenced schemas must already exist ## Creating Resources Use the `/api/resources/:schemaName` endpoint: For example, `POST /api/resources/Customer` accepts: ```json theme={null} { "data": { "customerId": "customer-123", "email": "john@example.com", "firstName": "John", "lastName": "Doe", "emailOptOut": false, "smsOptOut": true, "customerDetailUrl": "https://admin.example.com/customers/customer-123" } } ``` For schemas with references, use external IDs: For example, `POST /api/resources/Transaction` accepts: ```json theme={null} { "data": { "transactionId": "txn-456", "customerId": "customer-123", "transactionTotal": 99.99, "transactionDate": "2024-01-15T10:30:00Z" } } ``` ## API Examples ### Create Customer Schema ```bash theme={null} curl -X POST "https://api.embedreach.com/partner/schema-definitions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "name": "Customer", "pluralName": "Customers", "description": "Customer contact information", "category": "contacts_schema", "externalIdField": "customerId", "schema": { "type": "object", "title": "Customer", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["customerId"], "properties": { "customerId": { "type": "string", "x-pii-type": "EXTERNAL_ID" }, "email": { "type": "string", "x-pii-type": "EMAIL" }, "phone": { "type": "string", "x-pii-type": "PHONE" }, "firstName": { "type": "string", "x-pii-type": "FIRST_NAME" }, "lastName": { "type": "string", "x-pii-type": "LAST_NAME" }, "emailOptOut": { "type": "boolean", "description": "Email subscription opt-out status. Defaults to false (opted in)" }, "smsOptOut": { "type": "boolean", "description": "SMS subscription opt-out status. Defaults to true (opted out)" }, "customerDetailUrl": { "type": "string", "description": "URL to click-out to the customer detail page" }, "createdAt": { "type": "string", "format": "date-time" } } } }' ``` ### Create Transaction Schema (with Customer reference) ```bash theme={null} curl -X POST "https://api.embedreach.com/partner/schema-definitions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "name": "Transaction", "pluralName": "Transactions", "description": "Transaction and billing information", "category": "transactions_schema", "externalIdField": "transactionId", "referenceSchemas": ["Customer"], "schema": { "type": "object", "title": "Transaction", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["transactionId"], "properties": { "transactionId": { "type": "string", "x-pii-type": "EXTERNAL_ID", "description": "External ID" }, "customerId": { "$ref": "reach:schemas/Customer", "x-pii-type": "EXTERNAL_ID" }, "transactionDate": { "type": "string", "format": "date-time", "description": "Datetime ISO string with timezone when transaction occurred" }, "transactionTotal": { "type": "number", "description": "Transaction total in dollars" }, "transactionDetailUrl": { "type": "string", "description": "URL to click-out to the transaction detail page" } } } }' ``` ### Create Product Schema ```bash theme={null} curl -X POST "https://api.embedreach.com/partner/schema-definitions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "name": "Product", "pluralName": "Products", "description": "Product catalog information", "category": "custom_schema", "externalIdField": "productId", "schema": { "type": "object", "title": "Product", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["productId", "name"], "properties": { "productId": { "type": "string", "x-pii-type": "EXTERNAL_ID" }, "name": { "type": "string" }, "price": { "type": "number" }, "category": { "type": "string" } } } }' ``` ### Create Location Schema ```bash theme={null} curl -X POST "https://api.embedreach.com/partner/schema-definitions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "name": "Location", "pluralName": "Locations", "description": "Business location information", "category": "locations_schema", "externalIdField": "locationId", "schema": { "type": "object", "title": "Location", "$schema": "http://json-schema.org/draft-07/schema#", "required": ["locationId", "name"], "properties": { "locationId": { "type": "string", "x-pii-type": "EXTERNAL_ID" }, "name": { "type": "string" }, "address": { "type": "string" }, "city": { "type": "string" }, "state": { "type": "string" }, "zipCode": { "type": "string" } } } }' ``` ### List All Schemas ```bash theme={null} curl -X GET "https://api.embedreach.com/partner/schema-definitions" \ -H "Authorization: Bearer YOUR_API_KEY" ``` ### Get Specific Schema ```bash theme={null} curl -X GET "https://api.embedreach.com/partner/schema-definitions/Customer" \ -H "Authorization: Bearer YOUR_API_KEY" ``` # How Reach models your data Source: https://docs.embedreach.com/data-sharing/data-model The three concepts Reach reasons about, and how your data maps to them: definitions describe your structure, mappings tell Reach how to read it. Everything Reach does revolves around three concepts: **contact**, **transaction**, and **location**. When you share data, you're describing your own records and then telling Reach how to read them in terms of those three. Get that translation right and the rest of the platform — segments, messaging, attribution — falls into place. ## The three canonical concepts | Concept | What it is | What it powers | | --------------- | ------------------------------------------------------------ | ---------------------------------------------------------------- | | **Contact** | A person at one of your tenants — identity plus attributes. | Who receives email and SMS; the anchor for every segment. | | **Transaction** | Something of value — a purchase, invoice, contract, booking. | Revenue tracking and ad attribution (ROAS). | | **Location** | A physical place a tenant operates or services. | Google Business Profile mapping and location-based segmentation. | Anything that doesn't fit one of these three is a **custom schema** — and you should send it anyway (see below). ## Custom schemas: model your structure truthfully Don't flatten your data to fit ours. If your platform has jobs, invoices, estimates, memberships, appointments, or route stops, model each as its own schema exactly as it exists in your system. There's **no penalty for sending data Reach doesn't use yet** — richer relationships mean richer segments later, and the cost of adding a relationship after go-live is higher than the cost of sending it now. ## Definitions vs. mappings — two steps, two parts of the UI This is the distinction that trips people up, so be precise about it: * A **schema definition** is *the shape of your data* — a JSON Schema describing your records as they already exist. Your `customerId`, your `service_date`, your field names. * A **schema mapping** tells Reach *how to read your data as its concepts* — "the `email` field is the contact's email," "this schema is a `transactions_schema` and `transactionTotal` is the amount." Define first, map second. A definition without a mapping is just a shape Reach stores; the mapping is what turns it into a contact, a transaction, or a location. ## Everything resolves to a contact **Segments return people, so every record you send should be traceable back to a contact through references.** A transaction points at the customer who made it; a location points at the customer it serves; a route stop points at a location that points at a customer. As long as that chain exists, a segment can reach through any depth of related records and still answer with a list of contacts. You declare a reference with `$ref` and the `reach:schemas/` scheme: ```json theme={null} "customerId": { "$ref": "reach:schemas/Customer" } ``` ## A concrete chain: pool service A partner serving pool-cleaning businesses has three schemas that reference one another — each hop is a `$ref` from the child up to its parent: Three schema cards referencing upward: Route Stop (custom_schema) references Service Location via locationId, which references Customer (contacts_schema) via customerId. Everything resolves to the Customer at the top. Because every route stop traces up to a customer, Reach can answer a question that never mentions a customer directly — *"customers with a service location that has no route stop scheduled the week before Labor Day"* — and return exactly the people to email. That's the whole point of modeling the relationships instead of flattening them. See the JSON Schema format, `$ref` references, categories, and PII annotations. # Introduction Source: https://docs.embedreach.com/data-sharing/introduction Sharing customer and transaction data with Reach # Data Sharing To better attribute transactions to a business's marketing activities and to improve targeting, Reach requires customer and purchase data. Every business and industry is different, so we'll work with you during your implementation on what resources/attributes are best and how we should go about formatting and collecting that data. ## Required Data At a high level, Reach expects the following: * **For all industries**: Customer lists – sync these to Reach as customers are created/updated. * **For industries with online transactions**: Transaction/order data is the most helpful, shared soon after the transaction occurs. This data should include both the overall price paid and also the goods or services that the transaction is for. * **For industries with contracts billed over time**: Contracts/proposals/agreements will be most helpful, shared after the agreement is finalized. It is OK if these are amended over time. * **For industries with invoicing**: Invoice data is more helpful than when the charge is completed since it best describes the purchase – even if the invoice has not been paid (i.e. if the monetary transaction has not occurred). ## Integration Benefits Sharing this data enables Reach to: 1. Attribute marketing activities to actual business outcomes 2. Create targeted segments for marketing campaigns 3. Calculate accurate return on ad spend (ROAS) 4. Optimize ad targeting based on customer behavior # Methods Source: https://docs.embedreach.com/data-sharing/methods Different ways to share data with Reach # Data Sharing Methods Reach can collect your business data in several ways: ## [API Integration](/api.mdx) For a complete real-time implementation, Reach provides a comprehensive API that allows you to create and edit records for pre-defined schemas. See the [API Reference](/api-reference/introduction) for currently available endpoints. ## Database Queries You can share access to a database view with Reach, and Reach will query your database on a schedule to get any new transactions/invoices/contracts. This approach is: * Low effort to implement * Managed by the Reach team * Useful for batch processing / Ingesting Historical Data ## Best Practices * Send data as close to real-time as possible * Include all relevant customer identifiers (email, phone) * Include a unique ID for all rows sent (User ID, Invoice ID, Order ID, etc) * Link transactions to customer records with consistent IDs * Include line item details for better segmentation capabilities # Requirements Source: https://docs.embedreach.com/data-sharing/requirements Data formats and fields required for Reach integration # Data Sharing Requirements ## Core Data Types Reach requires several core data types to enable full functionality: ### Customer Data Information about the individuals who interact with a business: * Unique customer ID * Email address * Phone number (recommended) * First and last name * Creation date * Any relevant segmentation data ### Transaction Data Details about purchases or conversions: * Transaction ID * Customer ID (to link to customer record) * Amount * Currency * Date and time * Status (paid, pending, etc.) * Line items (products/services purchased) ### Location Data Information about business locations or service areas: * Location ID * Location name * Address * City, state, zip code * Contact information ### Business Data Information about the business utilizing Reach: * Business ID (matching your TENANT\_EXTERNAL\_ID) * Business name * Industry/category * Primary location reference ## Data Format Reach accepts data in JSON format with flexible schemas based on your business model. We'll work with you to establish the optimal format for your specific needs. ## Data Frequency For optimal attribution and targeting: * **Customer data**: Send as soon as created or updated * **Transaction data**: Send in real-time or within minutes of completion * **Location data**: Send upon initial setup and when changed * **Business data**: Send upon initial setup and when changed ## Implementation Support During your onboarding, the Reach team will: 1. Review your data model 2. Recommend appropriate data sharing methods 3. Provide customized implementation guidance 4. Test data flows before going live Contact [support@embedreach.com](mailto:support@embedreach.com) with any questions about data sharing requirements. # Authentication Source: https://docs.embedreach.com/embeddable-ui/authentication Secure authentication for Reach Reach uses JSON Web Tokens (JWT) for secure authentication. Each token links a user in your system to a user in Reach. Please reach out to [support@embedreach.com](mailto:support@embedreach.com) to get a Shared Secret for your platform in order to generate JWT tokens. If your app enforces security headers like Content Security Policy (CSP) or Cross-Origin Opener Policy (COOP), see [Security Headers (CSP & COOP)](/embeddable-ui/security-headers) for required configurations. ## Tenant Scoped JWT Token Requirements Sign your tenant-scoped token with your Shared Secret using `HS256`. It must include the following fields: | Field | Description | Required | | ---------------- | --------------------------------------------------------------- | -------- | | email | User's email address | Yes | | name | User's display name | Yes | | externalId | Your system's unique ID for this user, as a string | Yes | | tenantExternalId | Your system's ID for the user's business | Yes | | partnerId | Your unique vertical saas platform identifier provided by Reach | Yes | | iat | Issued at time (in seconds since epoch) | Yes | | exp | Expiration time (in seconds since epoch) | Yes | | type | Set to `tenant` to mark the token as tenant-scoped | No | Never expose your Shared Secret on the client side. JWT generation must always be handled server-side. ## Identifying the End User `externalId` is how Reach tells your users apart. Each `externalId` becomes a distinct user under that tenant, so activity in the embedded UI can be attributed to a person rather than to the business as a whole. For that to work, `externalId` must be: * **A string.** If your user IDs are numbers, convert them: `String(user.id)`. * **Stable.** Send the same value every time you mint a token for that person. * **Unique within the tenant.** Two people in the same business must never share one. If `externalId` is missing, or is anything other than a string, every request from that tenant resolves to one shared user. The token still authenticates and no error is returned — you simply lose per-user attribution. Sending a numeric ID such as `externalId: 12345` is the most common cause. `email` and `name` are recorded the first time Reach sees a given `externalId`, and are not updated by later tokens. Users are scoped to the tenant they were seen under. The same `externalId` sent with two different `tenantExternalId` values is two separate users, and no user identity is shared across tenants. Reach stores the `externalId`, `email`, and `name` you send for each user. ## Token Lifecycle We recommend tokens expire after 1 hour (3600 seconds). The Reach SDK handles token expiration by calling your onReauthRequested callback when a token expires. For a full server side example of how to generate JWT Tokens that are compatible with Reach please see the examples section [here](/samples/jwt-tokens). # Implementing Callbacks Source: https://docs.embedreach.com/embeddable-ui/iframe/callbacks Handle SDK events correctly The Reach SDK requires callback handlers to manage authentication and tenant events. ## Required Callbacks ### onReauthRequested Callback The `onReauthRequested` callback is triggered when the authentication token expires or becomes invalid. Your implementation should: 1. Fetch a new token from your server 2. Return the new token to update the SDK ```javascript theme={null} const handleReauth = async () => { try { // Fetch a new auth token from your server const response = await fetch('/reach-authtoken'); const data = await response.json(); if (!data.success) { throw new Error('Failed to get new token'); } // Return the new token return data.token; } catch (error) { console.error('Authentication failed:', error); // Handle error appropriately in your UI } }; ``` The SDK will use the returned token to automatically update its authentication state. You do not need to manually dispose and reinitialize the SDK. # Customization Source: https://docs.embedreach.com/embeddable-ui/iframe/customization Style the Reach interface to match your brand You can customize the appearance of Reach to match your application's branding through the theme property in the SDK configuration. ## Theme Configuration Reach supports shadcn/ui's styling conventions, making it easy to maintain consistent design. ```javascript theme={null} const config = { // Other configuration... theme: { styles: { primary: '#00758a', // Primary brand color secondary: 'pink', // Secondary color background: '0 0% 100%', // Page background (HSL format) border: 'border-purple-500', // Fonts 'font-body': 'Inter, system-ui, sans-serif', 'font-heading': 'Montserrat, Arial, sans-serif', }, }, }; ``` ## Color Format Support Reach supports multiple color format types: * HEX colors: #00758a * Named CSS colors: pink * HSL (shadcn/ui format): 240 5.9% 10% (hue saturation lightness) * Tailwind classes: bg-purple-500 We only support the default tailwind background color classes (bg--). Custom color names, bg-inherit, bg-current, and bg-transparent are not supported. To see a full list of supported tailwind colors, please refer to the [tailwind documentation](https://tailwindcss.com/docs/background-color). ## Font Customization Reach allows you to customize the fonts used throughout the interface. You can use any system font or any font available on Google Fonts—just specify the font name in your theme config, and Reach will automatically load it for you. **Example: Using a Google Font** ```javascript theme={null} const config = { theme: { styles: { 'font-body': 'Raleway, sans-serif', // This will load Raleway from Google Fonts 'font-heading': 'Montserrat, Arial, sans-serif', // Montserrat will also be loaded from Google Fonts }, }, }; ``` If you specify a font that is not a system font, Reach will automatically inject the appropriate Google Fonts `` tag for you. You do not need to manually include any font imports. ## Key Style Variables | Variable | Description | Default (Light) | | ---------------------- | ------------------------- | -------------------------------------- | | background | Page background | 0 0% 100% | | foreground | Main text color | 225 15% 16% | | card | Card background | 0 0% 100% | | card-foreground | Card text | 225 15% 16% | | popover | Popover background | 0 0% 100% | | popover-foreground | Popover text | 225 15% 16% | | primary | Primary accent | 210 30% 25% | | primary-foreground | Text on primary | 0 0% 98% | | secondary | Secondary accent | 210 15% 94% | | secondary-foreground | Text on secondary | 210 30% 25% | | muted | Subdued elements | 210 10% 96% | | muted-foreground | Subdued text | 220 10% 45% | | accent | Accent elements | 210 15% 94% | | accent-foreground | Text on accent | 210 30% 25% | | destructive | Error/delete | 0 84.2% 60.2% | | destructive-foreground | Text on destructive | 0 0% 98% | | border | Border color | 220 13% 90% | | input | Form inputs | 220 13% 90% | | ring | Focus rings | 210 30% 25% | | chart-1 | Chart color 1 | 210 50% 50% | | chart-2 | Chart color 2 | 260 50% 55% | | chart-3 | Chart color 3 | 150 50% 45% | | chart-4 | Chart color 4 | 325 50% 55% | | chart-5 | Chart color 5 | 45 80% 55% | | radius | Border radius | 0.625rem | | font-heading | Font for heading elements | "Plus Jakarta Sans" and system fonts\* | | font-body | Font for body elements | Inter and system fonts\* | *System fonts include:* * system-ui * apple-system * BlinkMacSystemFont * Segoe UI * Roboto * sans-serif ## Language Reach supports multiple languages through the `language` configuration option. Currently, we support: * English (en) * Spanish (es) To set the language, simply specify the language code in your configuration: ```javascript theme={null} const config = { // Other configuration... language: { default: 'en', // Set to Spanish }, }; ``` If no language is specified, Reach will automatically detect the user's preferred language based on: 1. URL parameters 2. Browser settings 3. Local storage preferences For language requests or to discuss adding support for additional languages, please contact our support team at `support@embedreach.com`. ## Customizing Verbs in Engage You can customize the verbs used in the Engage feature by providing a custom `language` configuration. ```javascript theme={null} const config = { // Other configuration... language: { overrides: { engage: { en: { ... }, es: { ... }, }, }, }, }; ``` This allows you to customize the verbs used in the Engage feature for your specific use case. For example, if you want to use "Contacts" instead of "Users", you can do the following: ```javascript theme={null} const config = { // Other configuration... language: { overrides: { engage: { en: { user: 'Contacts', user_other: 'Contacts', // The plural form of the word }, es: { user: 'Contactos', user_other: 'Contactos', // The plural form of the word }, }, }, }, }; ``` The full list of verbs that can be customized in Engage can be found below, we support `en` and `es` for each verb: ```json theme={null} { "user": "User", "user_other": "Users", "segment": "Segment", "segment_other": "Segments", "broadcast": "Broadcast", "broadcast_other": "Broadcasts", "automation": "Automation", "automation_other": "Automations", "insight": "Insight", "insight_other": "Insights", "merge_field": "Merge Field", "merge_field_other": "Merge Fields", "extra_merge_field_name": "Custom Field", "extra_merge_field_name_other": "Custom Fields", "advanced_merge_field_name": "Advanced Field", "advanced_merge_field_name_other": "Advanced Fields" } ``` ## Customizing the Measure Dashboard You can customize certain strings in the Measure feature by providing language overrides in your configuration: ```javascript theme={null} const config = { // Other configuration... language: { overrides: { measure: { en: { // The default value for this string is "Transaction ID". // The code below will override the string to read "Order ID" transaction_table_id_header: 'Order ID', }, es: { transaction_table_id_header: 'ID de pedido', // optional Spanish translation }, }, }, }, }; ``` Currently, the following strings can be customized in Measure: ```json theme={null} { "transaction_table_id_header": "Order ID" "transaction_table_created_header": "Order Created" } ``` For language requests or to discuss adding support for additional languages, please contact our support team at `support@embedreach.com`. ## Hiding or Enabling Features We currently support hiding and enabling features in the SDK configuration. ```javascript theme={null} const config = { // Other configuration... hideFeature: { engage: { sms: true, }, }, enableFeature: { engage: { onboarding: true, }, }, }; ``` ## Skipping the Feature Explainer Every feature opens on an explainer landing page that introduces it before any setup begins. If your product already explains the feature, set `explainer` to `skip` and the business drops straight into the onboarding wizard instead. ```javascript theme={null} const config = { // Other configuration... explainer: 'skip', }; ``` | Value | Behavior | | ---------------- | ---------------------------------------------------------- | | `show` (default) | The feature opens on its explainer landing page. | | `skip` | The feature opens with the onboarding wizard already open. | The setting applies to every feature, and the explainer stays reachable: dismissing the wizard reveals it, so a business that wants the introduction can still read it. Unrecognized values log a warning and fall back to `show`. This does not change which businesses see onboarding at all. A business that has already completed setup still lands on its dashboard. # Demo Mode Source: https://docs.embedreach.com/embeddable-ui/iframe/demo Enable demo environment for testing and sales demonstrations The Reach SDK includes a demo mode that provides a fully self-contained demo environment for testing and sales demonstrations. ## Enabling Demo Mode ### Configuration To enable demo mode, add the `demo` property to your configuration object: ```javascript theme={null} const config = { // Required: Enable demo mode demo: true, }; ``` Demo mode works with iframe integration and is also available as a standalone URL that can be sent out as "magic links", giving you flexibility in how you implement the demo experience. ## Use Cases ### Development Environment Demo mode is ideal for local development and testing: * **No backend required**: Test SDK integration without connecting to production systems * **Consistent data**: Reliable demo data that doesn't change between sessions * **Safe testing**: Experiment with configurations without affecting live data ### Sales Demonstrations The self-contained demo environment makes it perfect for sales scenarios: * **Full product showcase**: Demonstrate both Measure and Acquire products * **No setup required**: Prospects can see the full functionality immediately * **Professional presentation**: Clean, consistent demo data for professional demos ## Available Features When demo mode is enabled, you gain access to: * **Complete Measure functionality**: View all ROAS metrics and reporting * **Full Acquire capabilities**: Experience the complete AI campaign builder flow * **Demo data**: Pre-populated with realistic sample data for demonstrations * **All integration modes**: Works seamlessly with both iframe and magic-link implementations ## Customizing Demo Data For prospects or customers who need specific customizations to the demo environment data: **Contact our team at [collaborate@embedreach](mailto:collaborate@embedreach)** with details about: * Industry-specific data requirements * Custom branding needs * Specific use case scenarios * Timeline for customization Custom demo environments can be created to better align with your specific industry, use case, or branding requirements. # Embedding Reach Source: https://docs.embedreach.com/embeddable-ui/iframe/embedding Add Reach to your application interface Embedding Reach into your application is straightforward and flexible. ## Creating a Container Element First, create a div element that will serve as the container for the Reach interface: ```html theme={null}
``` We recommend a minimum height of 500px for optimal user experience, but the interface is fully responsive. ## Importing the SDK There are two approaches to importing the SDK: ### Option 1: Dynamic Script Loading (Recommended for React/Next.js) ```javascript theme={null} const importScript = resourceUrl => { const script = document.createElement('script'); script.src = resourceUrl; script.type = 'module'; script.async = true; document.body.appendChild(script); return script; }; // Usage const script = importScript('https://cdn.embedreach.com/iframe/sdk/sdk.es.js'); ``` For React or Next.js applications, be sure to clean up the script on component unmount: ```javascript theme={null} useEffect(() => { const script = importScript('https://cdn.embedreach.com/iframe/sdk/sdk.es.js'); return () => { if (script && document.body.contains(script)) { document.body.removeChild(script); } }; }, []); ``` ### Option 2: Using a Script Tag ```javascript theme={null} ``` ## Initializing the SDK Once the script is loaded, initialize the SDK with your configuration: The `authToken` must be a valid tenant-scoped JWT token. See [Authentication](/embeddable-ui/authentication) for token requirements. ```javascript theme={null} const loadReachSDK = config => { try { const sdk = new window.ReachSDK(config); return sdk; } catch (err) { console.error('Failed to initialize ReachSDK:', err); throw err; } }; // Example configuration const config = { feature: 'measure', // The Reach feature to load authToken: 'jwt-token', // Initial JWT authentication token // Optional: 'skip' opens the onboarding wizard instead of the explainer landing page explainer: 'show', // Optional theme customization theme: { styles: { primary: '#00758a', }, }, callbacks: { onReauthRequested, // Function to handle token refresh }, }; // Initialize SDK const sdk = loadReachSDK(config); ``` In frameworks like React or Next.js, be careful not to initialize the SDK multiple times. Store the instance in a ref or variable outside the component's render cycle. ## Security Headers (CSP) If your application enforces security headers like Content Security Policy, add the following sources to allow the SDK to load and render the embedded interface: ``` Content-Security-Policy: script-src 'self' https://cdn.embedreach.com; frame-src 'self' https://cdn.embedreach.com; connect-src 'self' https://api.embedreach.com; ``` Notes: * These directives are for the embeddable UI SDK. The script is served from `https://cdn.embedreach.com` and the iframe is hosted on the same domain; API requests go to `https://api.embedreach.com` from inside the iframe. * If you are installing the website attribution snippet instead, that script has different CSP needs. See the [Attribution setup guide](/attribution/setup) for details. See the full [Security Headers (CSP & COOP)](/embeddable-ui/security-headers) guide. ## Iframe sandbox and permissions The SDK creates the Reach iframe with a restrictive [`sandbox`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#sandbox) attribute and grants only the tokens needed for the product to run. The sandbox token list is: * `allow-scripts` — Run JavaScript inside the embedded UI * `allow-same-origin` — Treat the iframe as same-origin with `cdn.embedreach.com` for storage and APIs used by the app * `allow-forms` — Submit forms inside the embedded UI * `allow-popups` — Open new browsing contexts (for example `window.open` or `target="_blank"`) * `allow-popups-to-escape-sandbox` — New windows opened from the iframe are **not** sandbox-restricted, so third-party pages that use strict response headers can load correctly (for example partner booking or intake flows opened in a new tab) * `allow-downloads` — Trigger file downloads from the embedded UI where supported Separately, the iframe sets `allow="microphone"` so Voice features can request microphone access when your host page and browser policy permit it. # Introduction Source: https://docs.embedreach.com/embeddable-ui/iframe/introduction Embed the Reach Marketing Platform in your application as an IFrame Reach SDK allows you to embed our marketing platform directly within your application, providing your users with powerful ad management tools without leaving your interface. ## Prerequisites Before integrating Reach into your application, ensure you have: * **Partner ID**: Your unique vertical saas platform identifier provided by Reach * **Shared Secret**: Used for JWT authentication (provided by the Reach team) * **Designated Location**: A section in your application where Reach will be embedded ## Integration Overview If your app enforces security headers like Content Security Policy (CSP) or Cross-Origin Opener Policy (COOP), see [Security Headers (CSP & COOP)](/embeddable-ui/security-headers) for required configurations. Embedding Reach involves three simple steps: 1. **[Set up Authentication](/embeddable-ui/authentication)**: Create a server endpoint that generates JWT tokens. See [JWT Token Examples](/samples/jwt-tokens) for implementation details. 2. **[Create a Container](/embeddable-ui/iframe/embedding)**: Add a div element where Reach will be embedded 3. **[Initialize the SDK](/embeddable-ui/iframe/embedding#initializing-the-sdk)**: Import and configure the Reach SDK in your frontend # Troubleshooting Source: https://docs.embedreach.com/embeddable-ui/iframe/troubleshooting Solutions for common SDK integration issues If you encounter issues with the Reach SDK, check these common solutions. ## Authentication Issues **Problem**: Token-related errors or 401 Unauthorized responses. **Solutions**: * Verify your JWT contains all required fields * Check that your token is properly signed with the correct secret * Ensure your token hasn't expired (we recommend 1-hour expiration) * Confirm your `handleReauthRequested` callback is properly implemented ## SDK Initialization Problems **Problem**: Errors when initializing the SDK or "ReachSDK is not defined". **Solutions**: ```javascript theme={null} // Wait for script to load before initializing const script = document.createElement('script'); script.src = 'https://cdn.embedreach.com/iframe/sdk/sdk.es.js'; script.async = true; script.onload = () => { // Only initialize after script has loaded const sdk = new window.ReachSDK(config); }; document.body.appendChild(script); ``` Certain web frameworks, including React/Next.js, can make it easy to accidentally initialize the SDK multiple times. ## Display Issues **Problem:** The Reach interface doesn't display properly. **Solutions:** * Ensure the container element has sufficient dimensions (min-height: 500px recommended) * Verify your theme configuration contains valid values * Check for CSS conflicts from your application * Verify your security headers (CSP/COOP) allow the SDK and iframe hosts. See [Security Headers (CSP & COOP)](/embeddable-ui/security-headers) ## Callback Issues **Problem:** Callbacks not firing or errors when they execute. **Solutions:** * Ensure callbacks are properly passed to the SDK configuration * Check that callbacks are defined before they're passed to the SDK * Return a promise from handleReauthRequested that resolves to the new token For more targeted troubleshooting, open your browser's console to check for specific error messages from the SDK. ## Getting Help A full example of the SDK implementation can be found [here](/samples/embed). If you continue to experience issues, contact our support team at `support@embedreach.com` with: * A description of the issue * Browser and environment details * Any relevant console errors * Steps to reproduce the problem # Integration Options Source: https://docs.embedreach.com/embeddable-ui/integration-overview Choose the right integration method for each of our core solutions based on your technical requirements and platform architecture. ## Available Methods Reach offers multiple integration options to fit your development workflow: Simple integration that allows you to embed Reach directly into your application with minimal development effort Native integration that gives you full control over the UI and user experience using our React component library ## Compatibility Matrix Choose the right integration method for each of our core solutions: | Solution | Description | iFrame Embed | React Components | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------: | :--------------: | | Measure | Track ROAS and view comprehensive ad reporting dashboards across channels with consolidated marketing analytics | | | | Engage | Flexible and powerful Email & SMS system to manage business communications across various channels, with sender identity management and reliable message delivery | | | | Acquire | AI-powered ad campaign builder that helps create, manage, and optimize paid digital advertising with automated targeting and budget optimization | | | | Reputation | Monitor and manage your online reviews and customer feedback with automated request workflows and unified analytics that turn customer sentiment into actionable insights | | | | AI Voice | AI-powered voice answering system that automatically answers incoming calls to prevent missed opportunities and drive more sales through intelligent conversation handling | | | ## Integration Flow Regardless of your choice, implement a backend endpoint using JWT tokens to authenticate the logged-in user in Reach. See [authentication](/embeddable-ui/authentication) for details. Select the integration method that best fits your platform architecture and requirements. Embed the Reach components in your application using [iFrames](/embeddable-ui/iframe/embedding) or [React components](/embeddable-ui/react/introduction) If your app enforces security headers like Content Security Policy (CSP) or Cross-Origin Opener Policy (COOP), see [Security Headers (CSP & COOP)](/embeddable-ui/security-headers) for required configurations. # Introduction Source: https://docs.embedreach.com/embeddable-ui/react/introduction Embed the Reach Marketing Platform in your application as a React Component You can also use our Reach React Library to embed Reach into your application. You can see an example Github repository for a React application that uses this library [here](https://github.com/EmbedReach/reach-react-example). We currently only support React 18. ## Install the library ```bash theme={null} npm install @embedreach/components ``` ## Initialize the library Start by importing our css styles at the top of your application: ```javascript theme={null} import "@embedreach/components/styles.css"; ``` Now to integrate Reach components into your application, wrap them with the `ReachProvider` component. The provider requires a `config` object that initializes the Reach SDK with authentication and tenant configuration. ```javascript theme={null} const config = { theme: { ... }, authToken: 'your-auth-token', // Optional: 'skip' opens the onboarding wizard instead of the explainer landing page explainer: 'show', callbacks: { onReauthRequested: async () => { // return your auth token const token = '' }, }, } ... ``` Please see [Authentication](/embeddable-ui/authentication) for more information on how to generate an auth token. If your app enforces security headers like Content Security Policy (CSP) or Cross-Origin Opener Policy (COOP), see [Security Headers (CSP & COOP)](/embeddable-ui/security-headers) for required configurations. Please see [Customization](/embeddable-ui/iframe/customization) for more information on how to customize the components. ## Customization We support the following customization options: * [Color Customization](/embeddable-ui/iframe/customization#color-format-support) * [Language Customization](/embeddable-ui/iframe/customization#language) ## Components Available #### SegmentBuilderDialog We expose a dialog component that can be used to create and edit segments. ```javascript theme={null} void; /** * Optional callback when the segment builder is closed * @param createdSegment - The created segment id or false if the segment was not created, 'error' if there was an error */ onSegmentUpdated?: (createdSegment: string | false | 'error') => void; /** * Optionally pass in a segmentId to edit an existing segment */ segmentId?: string; /> ``` #### CreateAutomationDialog This is the initial modal that can be used to create a new automation. ```javascript theme={null} void; /** * Optionally skip the selection of automation and jump to the automation type * Currently only supports one time automation * * @Note This will remove the ability to select the automation type (e.g. the user will not be able to change the automation type) */ automationType?: AutomationTriggerType.ONE_TIME; /** * Optional function to return extra merge fields for the automation */ getExtraMergeFields?: () => Promise; /** * Optional text and hyperlink to display for * replyTo settings */ replyToSettingsText?: string; replyToSettingsLink?: string; /** * Optional text and hyperlink to display for * from name settings */ fromNameSettingsText?: string; fromNameSettingsLink?: string; /** * Optional function to call prior to scheduling if a user wants to implement custom * logic to block scheduling * * @param args.estimatedEmailRecipients - The estimated number of email recipients * @param args.estimatedSmsRecipients - The estimated number of sms recipients * @param args.scheduleSendAt - The scheduled send time as an ISO date string, or null if not set * * @returns true if the automation should be scheduled, string otherwise that will be displayed to the user in a toast notification */ onBeforeSchedule?: (args: { estimatedEmailRecipients: number; estimatedSmsRecipients: number; scheduleSendAt: string | null; }) => Promise; /> ``` #### ViewAutomationModal This is the component used to view and edit automations. This components allows users to preview communications, edit automation details and view statistics on sent communications. ```javascript theme={null} Promise; /** * Optional callback when a duplication is created */ onDuplicationCreated?: (duplicationId: string) => void; /** * Optional boolean to hide features */ hideSms?: boolean; hideSales?: boolean; /** * Optional text and hyperlink to display for * replyTo settings */ replyToSettingsText?: string; replyToSettingsLink?: string; /** * Optional text and hyperlink to display for * from name settings */ fromNameSettingsText?: string; fromNameSettingsLink?: string; /** * Optional function to call prior to scheduling if a user wants to implement custom * logic to block scheduling * * @param args.estimatedEmailRecipients - The estimated number of email recipients * @param args.estimatedSmsRecipients - The estimated number of sms recipients * @param args.scheduleSendAt - The scheduled send time as an ISO date string, or null if not set * * @returns true if the automation should be scheduled, string otherwise that will be displayed to the user in a toast notification */ onBeforeSchedule?: (args: { estimatedEmailRecipients: number; estimatedSmsRecipients: number; scheduleSendAt: string | null; }) => Promise; /> ``` #### SMSOnboarding This is the component used to onboard a business to SMS. As long as you wrap the component with the `ReachProvider` component, it will automatically update based on the state of the business's SMS registration application. ```javascript theme={null} Promise; /> ``` If you would like to request any additional components, please reach out to us at [support@embedreach.com](mailto:support@embedreach.com). ## Extra Merge Fields The `ViewAutomationModal` component allows you to pass in a function to return extra merge fields for the automation. ```javascript theme={null} getExtraMergeFields?: () => Promise; ``` The expected return type is an array of `ReachMergeField` objects. Each merge field can be either a `static` or `dynamic` type. Each merge field must have a unique `id` that will be used when updating merge field contents. The `type` field determines whether it's a static or dynamic merge field. You **cannot** have two identical template names for **any** merge fields. When a merge field includes an `image` configuration, the image will be automatically added as an attachment to the message. The merge field still provides its text value for use in the message content, while the image serves as a supplementary attachment (e.g., a QR code for a coupon, a product image, etc.). ### Dynamic Merge Field ```javascript theme={null} type DynamicMergeField = { type: 'dynamic'; id: string; mergeFields: { displayName: string; templateName: string; /** * Optional image configuration for this merge field. Auto-applied to SMS if the merge field text is used. */ image?: { placeholderUrl: string; // URL for placeholder image to show in UI maxSize: number; // Max size in bytes for this image (used to deduct from total message size) }; }[]; url: string; // e.g. "https://acme.co/id/" (we require https) }; ``` #### URL Requirements The URL will be called with a `POST` request with the following body: ```javascript theme={null} { userIds: string[]; id: string; // `id` is the id of the dynamic merge field automationId: string; // `automationId` is the id of the automation tenantExternalId: string; // `tenantExternalId` is the external id of the business } ``` And a the following headers: ```javascript theme={null} { 'Authorization': 'Bearer your-auth-token' } ``` Where the `your-auth-token` is a signed JWT token using the shared secret for the platform. The userIds are mapped to the `externalId` [Partner Resource](/api-reference/endpoint/get-api-resources-%7Bschemadefinitionnameorid%7D-%7Bexternalid%7D). The response should be a JSON object with the following format: ```javascript theme={null} { [userId: string]: { /** * The value of the merge field * For text fields: string * For fields with images: { value: string; image?: { url: string } } */ [mergeFieldId: string]: string | { value: string; image?: { url: string } }; } } ``` This means for example if you have a dynamic merge field, you can pass up to 20 merge fields in a single request. ```javascript theme={null} { type: 'dynamic', id: 'unique_id_for_merge_fields', mergeFields: [ { displayName: 'Coupon Code', templateName: 'coupon_code' }, { displayName: 'Expiration Date', templateName: 'expiration_date' }, { displayName: 'Coupon With QR Code', templateName: 'coupon_with_qr_code', image: { placeholderUrl: 'https://acme.co/placeholder-qr-code.jpg', maxSize: 1600 } }, ... // other merge fields you might want to pass ], url: 'https://acme.co/id/' } ``` The URL will be called with the following body: ```javascript theme={null} { userIds: ['123', '456'], id: 'unique_id_for_merge_fields', tenantExternalId: 'acme' // the external id of the business } ``` And the expected response would be where the key is the userId and it returns a dictionary of all the `templateNames` and their values: ```javascript theme={null} { '123': { 'coupon_code': '123456', 'expiration_date': '2021-01-01', 'coupon_with_qr_code': { value: '123456', image: { url: 'https://acme.co/qr-codes/123456.png' } } }, '456': { 'coupon_code': '456789', 'expiration_date': '2021-02-01', 'coupon_with_qr_code': { value: '456789', image: { url: 'https://acme.co/qr-codes/456789.png' } } } } ``` # How Automation Works Source: https://docs.embedreach.com/engage/automation-summary Learn how automations work and how to create them ## Cooldown Periods Think of cooldown like a "waiting period" before your automation can run again for the same customer. ### Why You Need Cooldown Without cooldown, if someone enters your segment multiple times, they'd get the same email over and over. That's spam, and customers hate spam. ### Your Cooldown Options You can configure your automation to: #### 1. Never Run Twice Run only once per customer, ever. **Example:** "Welcome New Customer" email * Customer enters segment → Gets welcome email ✅ * Customer enters segment again later → No email (already got it) ❌ #### 2. Run Always Run every time someone enters the segment. **Example:** "Weekly Newsletter" automation * Customer enters segment → Gets newsletter ✅ * Customer enters segment again next week → Gets newsletter again ✅ * Customer enters segment again → Gets newsletter again ✅ #### 3. Run After Waiting Period Wait a specific amount of time before running again. **Example:** "Follow-up Sequence" with 7-day cooldown * Day 1: Customer enters segment → Gets follow-up email ✅ * Day 3: Customer enters segment again → No email (still waiting) ❌ * Day 8: Customer enters segment again → Gets follow-up email ✅ ### Need Help? If you want to change your cooldown settings or need help configuring your automations, please reach out to the Reach team at [support@embedreach.com](mailto:support@embedreach.com). # Channel Accounts Source: https://docs.embedreach.com/engage/channel-accounts Overview of Channel Accounts ## Introduction Channel Accounts represent configured integrations that enable your tenant to send communications through various channels (email, SMS, etc.). Each channel account is associated with a specific [channel integration](/engage/channel-integrations) and contains the necessary metadata to send messages through that channel (e.g. the base domain for example). Please see the API Reference [here](/api-reference/endpoint/get-api-channel-accounts) for more information. Currently supports email via Reach Managed and Twilio integrations. ## Structure A channel account consists of: * **Status**: Can be either `active` or `deactivated` * **Business ID**: Links the account to a specific tenant this account belongs to. * **Channel Integration ID**: Specifies which integration this account is configured for. See [Channel Integrations](/engage/channel-integrations) for more information. * **Channel Account Metadata**: Contains provider-specific configuration details. See [Channel Account Metadata](#channel-account-metadata) for more information. * **Name**: Optional friendly name for the account * **Creator Origin**: Indicates how the account was created (`manual` or `template`) # Channel Account Metadata ## Supported Channel Account Types ### Reach Managed Email (`reach-managed`) For Reach-managed email accounts, the following configuration is required: * **Type**: `reach-managed` * **Domain Prefix**: The prefix domain of the channel account (e.g. `marketing.embedreach.org` or `marketing.yourdomain.com`) **Response fields** (populated after configuration): * **Base Domain**: The full domain of the channel account * **Message Stream**: Either `broadcast` or `outbound` * **DKIM Verified**: Boolean indicating if DKIM has been verified * **DMARC Verified**: Boolean indicating if DMARC has been verified * **Verified Return Path**: Boolean indicating if return path has been verified ### Twilio (`twilio`) For Twilio accounts, the following configuration is required: * **Type**: `twilio` # Channel Integrations Source: https://docs.embedreach.com/engage/channel-integrations Overview of Channel Integrations ## Introduction Channel Integrations define the available communication providers and their configurations at the platform level (e.g. the mechanism by which we send emails). These integrations allow you to manage what communication providers they want to use for their tenant. Please see the API Reference [here](/api-reference/endpoint/get-partner-channel-integrations) for more information. Currently only email via Reach Managed is supported. SMS + Bring Your Own Provider support is planned for future releases. ## Structure A channel integration consists of: * **Status**: Can be either `active` or `deactivated` * **Channel Provider**: The provider of the communication service (currently only `reach_managed` is supported) * **Channel Type**: The type of communication channel (currently only `email` is supported) ## Available Providers ### Reach Managed Reach Managed is our default email provider and currently the only provider supported. You can optionally bring your own DNS provider such as [Route53](#route53) #### Route53 Reach supports bringing your own domain with Route53. To achieve this, we use [cross account IAM permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies-cross-account-resource-access.html) with minimally scoped permissions. Specifically, to integrate with Route53 we will need the following information: * **AWS Account ID**: Your AWS account ID * **Role ARN**: The ARN of the role that Reach will assume to access Route53 * **Hosted Zone ID**: The ID of the hosted zone that Reach will access * **Base Domain**: The base domain that Reach will access You will need to configure the IAM role with the following permissions: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "route53:ChangeResourceRecordSets", ], "Resource": "arn:aws:route53:::hostedzone/*" // If possible specific the hosted zone id instead of the wildcard }, { "Effect": "Allow", "Action": [ "route53:ListResourceRecordSets" ], "Resource": "arn:aws:route53:::hostedzone/*" } ] } ``` Policy Example And the following assume role policy: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::026090517319:root" // This grants access to the Reach AWS account (not root access) }, "Action": "sts:AssumeRole" } ] } ``` Assume Role Policy Now you can call the [Create Channel Integration](/api-reference/endpoint/post-partner-channel-integrations) endpoint to integrate with Route53, for example you can use the following payload: ```json theme={null} { "channel_provider": "reach-managed", "channel_integration_type": "email", "channel_integration_metadata": { "type": "reach-managed", "customDomain": true, "awsCustomDomainInfo": { "awsAccountId": "026090517319", "roleArn": "arn:aws:iam::026090517319:role/ReachRoute53Role", "hostedZoneId": "Z01234567890123456789", "baseDomain": "example.com" } } } ``` ### Twilio Twilio is a popular SMS provider that we support. To integrate with Twilio we will need the following information: * **Account SID**: Your Twilio account SID * **API Key SID**: Your Twilio API Key SID * **API Key Secret**: Your Twilio API Key Secret You can see [here](https://www.twilio.com/docs/iam/api-keys) for more information on how to get these credentials. # Channel Senders Source: https://docs.embedreach.com/engage/channel-senders Overview of Channel Senders ## Introduction Channel Senders define the specific sender identities used to send communications through your configured [channel accounts](/engage/channel-accounts). For email communications, this represents the "From" address that recipients will see. Please see the API Reference [here](/api-reference/endpoint/get-api-channel-senders) for more information. ## Structure A channel sender consists of: * **Status**: Can be either `active` or `deactivated` * **Business ID**: Links the sender to a specific tenant * **Channel Account ID**: References the [channel account](/engage/channel-accounts) this sender belongs to * **Channel Sender Type**: Can be either `broadcast` or `transactional`. See [Channel Sender Types](#channel-sender-types) for more information. * **Channel Sender Metadata**: Contains sender-specific configuration details. See [Sender Metadata](#sender-metadata) for more information. ## Channel Sender Types ### Broadcast Used for marketing and promotional communications. These senders should be used for: * Newsletter campaigns * Marketing announcements * Promotional offers * General updates ### Transactional Used for business-critical and user-specific communications. These senders should be used for: * Account notifications * Booking confirmations * Payment receipts * System alerts ## Sender Metadata ### Email Sender For email senders, the following configuration is required: * **Type**: `email` or `sms` For email senders, the following configuration is required: * **User Part**: The local part of the email address (e.g., if you want `marketing@yourdomain.com`, specify `marketing`) * **Reply To**: The email address to use for replies. This is optional and defaults to the email address used to create the sender. The domain part of the email address will be automatically appended based on your [channel account](/engage/channel-accounts) configuration. For SMS senders, the following configuration is required: * **From**: The phone number to send SMS messages from (e.g. `+18669728388`) * **Message Service SID**: (Optional) Alternatively, you can specify a Twilio Message Service SID to send SMS messages from * **Friendly Name**: (Optional) A display name for the sender # Communication Groups Source: https://docs.embedreach.com/engage/communication-groups Overview of Communication Groups ## Introduction Communication Groups allow you to define reusable message templates for your automated communications. Each group contains the content and configuration needed to send messages through your configured channels (currently email, with SMS planned for future releases). Please see the API Reference [here](/api-reference/endpoint/get-api-communication-groups-api-communication-groups) for more information. Currently only email message content is supported. SMS message content support is planned for future releases. ## Structure A communication group consists of: * **Business ID**: Links the group to a specific tenant * **Channel Sender**: References the [channel sender](/engage/channel-senders) used to send the communication * **Message Content**: Channel-specific content for the message. See [Message Content](#message-content) for more information. ## Message Content ### Email Content For email messages, the following content can be configured: * **HTML Body**: The HTML content of the email * **Text Body**: A plain text version of the email * **Subject**: The email subject line * **Preview Text**: Optional preview text shown in email clients ### SMS Content SMS message can be configured with the following content: * **Text Body**: The text content of the message * **Company Name**: Optionally a company name to prefix the message with ## Usage Communication Groups are primarily used within [Tenant Automations](/automations/automations) to define the content that will be sent when an automation is triggered. A single Communication Group can be referenced by multiple automations, allowing you to reuse message templates across different automated workflows. ### Example Here's an example of creating a Communication Group for email: # Email Deliverability Source: https://docs.embedreach.com/engage/email-configuration What we do to maximize inbox placement for your marketing email and protect your sending reputation Whether an email reaches the inbox is ultimately decided by the recipient's email provider (e.g. Gmail, Outlook, iCloud, etc.), each of which puts many measures in place to screen for both spam content and untrustworthy sending behavior, such as sending to recipients who never opted in. Like other mainstream email senders, we follow a set of well-established practices to give your messages the best possible odds. Your email also benefits from the reputation our sending infrastructure has built up over time, and we work hard to keep that reputation strong — both by protecting you from bad senders, and by helping you avoid becoming one. Here's a summary of some of the things we do to help maximize the chances your emails get to the inbox and preserve your reputation. ## Sender Domains ### Using Your Own Domain For the highest deliverability, we encourage businesses to connect their own domains. An existing, established domain helps reassure recipients (and their email providers) that the email is authentically coming from the business. If you choose to connect your own domain, you must select a subdomain for marketing (e.g. `send.mybusiness.com`, not `mybusiness.com`). This is to minimize the risk that any transactional emails sent from the root domain get flagged as marketing or spam by providers. ### Using Our Domain For those who choose to use our provided domain, we still provide each business its own dedicated subdomain — this limits how much other senders can affect your reputation. We set up DKIM and Return-Path records at the subdomain level (see more below), so your authentication and sending history are scoped to your own subdomain rather than pooled with everyone else's. ## Authentication + Alignment Every message is signed with **DKIM**, a mechanism that helps verify that the email came from the business. Messages are also sent with a **Return-Path** on the sending domain so that **SPF** authenticates that domain rather than the underlying email infrastructure's. A **DMARC** policy sits on top, tying both of those checks to the visible From address recipients actually see, and giving receiving providers (e.g. Gmail, Outlook, iCloud, etc.) a published policy to consult — along with reporting back to us on anything sent in your domain's name. This strictness about how every message is authenticated adds credibility to each legitimate email you send. ## Intelligent Sending + Reputation Monitoring Large broadcasts are never sent all at once. We release batches of messages and adapt the spacing and batch sizes to how the list is actually performing — never letting the broadcast proceed to further worsen your reputation if there is an unexpected surge of bounces. If you're sending from our provided domain, this same mechanism protects you from other senders' mistakes — a bad campaign gets caught before it affects everyone else on the domain. If a campaign is ever paused, our team will work with you to get it back on track. Hard bounces, spam complaints, and unsubscribes are handled automatically — we manage the required `List-Unsubscribe` headers on your behalf, and stop sending to addresses that are undeliverable or have complained on all future sends. ## In-App Guidance for Best Practices Most deliverability damage is self-inflicted — mailing a purchased list, blasting an entire list at once, or writing to recipients who haven't heard from you in three months or longer. The resulting bounces and spam complaints teach providers to distrust your domain, and reputation is slow to build but quick to lose. Inside the application, you'll notice hints and reminders that push you towards best practices for sending, so you or others on your team can avoid those mistakes. These are prompts rather than restrictions — they surface the tradeoffs at the moment they matter, so you can make an informed decision with the right tools. Beyond those prompts, we encourage you to: * **Only send to people who opted in.** Never mail a purchased, rented, or inherited list — those recipients never agreed to hear from you, and the complaints that follow are the fastest way to damage your reputation. Permission can also go stale, so if someone hasn't heard from you in three months or more, it's worth treating that as re-engagement rather than a routine send. There are reasonable exceptions — someone who signed up for updates about an annual event still expects to hear from you when it comes around. * **Warm up gradually.** A newly connected domain has no sending history — even if you've been active on another platform before. Starting with the most engaged contacts and building volume over several weeks produces better long-term placement than starting at full volume. Segments make it straightforward to send to engaged contacts first. * **Send relevant mail.** Engagement — opens, clicks, and the absence of complaints — is the strongest input to reputation. Segmentation and audience filters exist to target the people most likely to want a given message. * **Send consistently.** Providers build a sender profile over time, and a steady moderate cadence establishes reputation more reliably than long silences broken by large sends. Automations and scheduled campaigns keep that cadence without manual effort. # End User Documentation Source: https://docs.embedreach.com/engage/end-user-docs Complete guide from account setup to sending your first email campaign # Getting Started: Your First Email Campaign This guide walks you through the complete process of setting up your account and sending your first email campaign using the Engage platform. ## Prerequisites * A Reach account with Engage access * Basic understanding of your target audience * Optional: Additional business information for SMS application (if you plan to use SMS) *** # Creating Your First Broadcast ### Get started by clicking the new broadcast button