# 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:
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/*"
}
]
}
```
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"
}
]
}
```
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
### Select the channels you want to use
* You will always have access to an email sender
* If you choose to use SMS, unless previously provisioned, you will have to go through the SMS application flow. This can take up to 7 business days and will require you to verify your business information. You can go through that application later in the wizard if you select SMS here.
### Select Content Builder Style
* You can choose to use AI to build an initial starter template for you to get started.
* Alternatively you can start from scratch and build your content entirely manually.
### Email Content
* Here is a breakdown of all the available fields and how they are used in the content builder.
* From Email: This is the email that will be used to send the broadcast.
* From Name: When delivered, this will be the name that appears in the email.
* Reply To Email: This is the email address that will be used to reply to the broadcast.
* From Name and Reply To Email both can be configured in the home screen by clicking the gear icon in the top right corner.
* Subject: This is the subject line of the email.
* Preview Text: This is the text that will be shown in the email preview in email clients.
#### Stripo Editor
We utilize the Stripo email editor to build your email content. This offers out of the box support for dynamic fields such as users first name, last name, and email address, etc.
* **Dynamic Fields:** To make communications more personal you can choose to add dynamic fields to your email content.
* **Responsive Design:** Our email editor offers a responsive design that will automatically adjust the layout of your email to the device it is being viewed on.
### SMS Content
Using our built in phone editor you can also add dynamic fields and images to your SMS content.
* **Sender & Company:** It's important to know where SMS messages are coming from. We've automatically injected your business name as a prefix to the message. But you can change or remove that under the sender and company tab
* **Dynamic Fields:** To make communications more personal you can choose to add dynamic fields to your SMS content.
### Audience
There are 3 ways to select your audience for a broadcast.
#### All Users
You can select all users in your business. This will send to any users that have opted in to receive emails or sms. This is the default option.
#### Select a Segment
You can select a segment that you have already created. This will send to any users that are in the segment. You can select multiple segments along with excluding specific segments.
#### Select Individual Users
You can select individual users that you have in your business to send directly to them.
### Schedule
The final step is to schedule your broadcast. You can schedule it to send immediately or at a specific time. When selecting a specific time, make **sure** to select the timezone you are in.
### Review
You're ready to start sending! Review your broadcast and click send.
## Getting Started: Viewing Your Broadcast
After you've scheduled your broadcast, you can view the status of your broadcast by clicking on it in the broadcast list.
### Recipients
By clicking on the recipients tab, you can view the list of users that will receive your broadcast. Along with what channel they received it on (email or sms).
### Insights
You can view the insights of your broadcast by clicking on the insights tab. This will show you open and click rates for your broadcast. Along with any sales insights that have been attributed to your broadcast.
# Introduction
Source: https://docs.embedreach.com/engage/introduction
Reach's Engage platform gives businesses a simple, but powerful tool to scale customer communications to close deals or bring customers back.
## User Experience for Engage
When your users navigate to the embedded Reach UI, they will have access to powerful communication tools to connect with their customers. The user experience includes:
Your tenants can configure their preferred communication methods. If you'd like to offer it, they can connect their email domains or at minimum choose a unique subdomains and display names.
Tenants can use the shared customer and transaction data using the fields and values they are already familiar with from your application.
A customized email and SMS builder allows designing messages with personalization at the right time.
Reach shows open rates, click rates, conversions, revenue, and other key metrics to continually optimize communication strategies.
## Integrating Engage into your Platform
Implementing Engage for your tenants requires these key 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.
See the [Embeddable UI](/embeddable-ui/integration-overview) section for more details.
Connect your user data via our webhook integration (preferred method) to ensure Engage has access to the most up-to-date customer information for targeting and personalization.
See the [Data Sharing](/data-sharing/introduction) section for more details.
Configure which communication channels and integrations your tenants can access, set up custom sender domains, and define which data fields can be used for segmentation and message personalization.
See \[/engage/channel-integrations] to get started.
## Future Customization Options
In upcoming releases, vertical SaaS providers will be able to further tailor the Engage experience through:
* **Suggested Templates**: Provide industry-specific communication templates for automations and campaigns
* **Default Automations and Segments**: Pre-configure common workflows and customer segments for your industry
* **Custom Integrations**: Connect dynamic communication content such as coupon codes, real-time schedule availability, and product inventory.
Reach out to [support@embedreach.com](mailto:support@embedreach.com) to learn more about these features or get a preview of these upcoming features.
# Glossary
Source: https://docs.embedreach.com/home/glossary
Key terms and concepts used throughout our documentation.
To help illustrate these concepts, we'll use a fictional example: **FestivePro**, a vertical software platform for holiday decoration installers, and its ecosystem of businesses and customers.
## People & Organizations
| Term | Definition | Example |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **Partners** | The vertical software providers who embed Reach functionality into their platform. | FestivePro, the software platform for holiday decoration businesses. |
| **Tenants** | Businesses that use the partner's vertical software platform. These can be nested (e.g. parent companies with multiple brands or locations). | "Five Star Holiday Services," a holiday decoration installation company that uses FestivePro to manage their business. |
| **Users** | Individual contacts whom the tenants serve. | Homeowners and business owners who hire Five Star Holiday Services to install their holiday decorations, e.g. "Noel Brightman". |
| **Groups** | Organizational units to which individual users may belong, relevant for attribution. | "The Brightman Family" or "Main Street Co.", where Noel Brightman is ordering services on behalf of their business. |
## Reach Products
| Product | Purpose | Example |
| ------------ | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Measure** | Track ROAS and view comprehensive ad reporting dashboards across channels. | Five Star Holiday Services sees which ad channels and campaigns drove the most bookings for light installations. |
| **Engage** | Create targeted SMS & Email campaigns using customer data. | Five Star Holiday Services sends personalized emails to previous customers offering early booking discounts for the upcoming season. |
| **Acquire** | AI-powered ad builder and campaign optimization to reach new customers. | Five Star Holiday Services starts advertising online with just a few clicks. |
| **AI Voice** | AI-powered voice answering service that handles incoming calls with natural language processing. | Five Star Holiday Services can answer calls automatically 24/7. |
## "Acquire" & "Measure" Terminology
| Term | Definition | Example |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| **Ad Platforms** | Systems that place advertisements, such as Google or Meta. | Five Star Holiday Services runs Facebook ads targeting homeowners interested in holiday decorations. |
| **Landing Pages** | Marketing websites where tenants direct their customers, often from ads. | [www.fivestarholiday.com](http://www.fivestarholiday.com) showcases their decoration services and portfolio. |
| **Partner-Owned Pages and Forms** | Scheduling pages, lead forms, checkout forms, etc. hosted by the vertical software partner. | FestivePro provides Five Star Holiday Services with an online booking system embedded in their website. |
| **Third-Party Owned Pages and Forms** | External tools like Hubspot, Acuity, or Calendly that are separate from partner-owned pages. | Five Star Holiday Services embeds a Calendly scheduling widget on their site. |
| **Landing Page Visits** | Initial visits to a website, with tracking information about the source. | A homeowner clicks on a Google ad and visits Five Star Holiday Services' website. |
| **Identifications** | When a previously-anonymous visitor provides identifying information. | A visitor fills out a quote request form, providing their name, address, and contact information. |
| **Transaction Data** | Customer information from the partner system that helps provide a picture of revenue and LTV attributable to various sources. | Records of all decoration installations, including services purchased and revenue. |
## "Engage" Terminology
| Term | Definition | Example |
| ------------------------ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Channel Integrations** | The available communication providers and their configurations at the partner level. | FestivePro has turned on select email service providers to enable all their tenant businesses to send emails. |
| **Channel Accounts** | Configured integrations that enable tenants to send communications through various channels. | Five Star Holiday Services' email account configured with their branding and subdomain. |
| **Channel Senders** | Specific sender identities within a channel account, such as email addresses or phone numbers. | [marketing@fivestarholiday.com](mailto:marketing@fivestarholiday.com) and [sales@fivestarholiday.com](mailto:sales@fivestarholiday.com) are two different email senders. |
| **Transaction Data** | Customer information used for analytics, segmentation, and personalization. | Five Star Holiday Services segments customers based on past decoration packages purchased and targets them with relevant upgrades. |
# Welcome to Reach
Source: https://docs.embedreach.com/home/welcome
The industry-first embedded growth and retention platform for vertical software solutions
## Pioneering Embedded Marketing Solutions
Reach is the **first and only** fully embeddable solution that enables vertical software platforms to seamlessly offer powerful growth and retention features to their users. Our revolutionary platform helps businesses leverage customer and purchase data to target the right leads at the right time and measure marketing impact with unprecedented precision—all without leaving your application.
## Our Core Solutions
Track ROAS and view comprehensive ad reporting dashboards across channels
Create targeted SMS & Email campaigns using your customer data
AI-powered ad builder and campaign optimization
Manage your online reputation and reviews
Respond to incoming calls with an AI Voice agent
# Introduction
Source: https://docs.embedreach.com/measure/introduction
Reach's Measure platform gives businesses a consolidated view of their ad campaign performance with actionable insights to optimize their spend and improve their returns.
## User Experience for Measure
When your users navigate to the embedded Reach UI, they will be prompted to enable marketing analytics if they are already running ads. Once they opt-in, they will go through the following steps:
Your tenants will be prompted to connect their advertising accounts. This provides insight into ad spend and helps us connect metrics down to the campaigns that are running.
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.
Reach combines the attribution data and ad platform data with the transaction data that you share with us to show a rich picture.
Reach can optionally send users' transaction data back to the Ad Platforms to help optimize targeting and bidding.
## Integrating Measure into your Platform
Implementing Measure 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: 'measure'` to load the Measure 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.
# Automations Setup
Source: https://docs.embedreach.com/onboarding/automations
Phase 7: Define automation templates for Engage
## Overview
**When needed**: When implementing Engage (email/SMS marketing automation)
Reach's automation system allows your customers to run sophisticated marketing campaigns without building them from scratch. Instead of expecting SMBs to understand email marketing strategy, you provide them with pre-configured, industry-specific automations that work out of the box.
## Understanding the Automation Architecture
**Automations (Campaigns)**: Multi-step workflows triggered by customer behavior or events.
Examples: welcome series after first purchase, win-back campaigns for inactive customers, appointment reminders, renewal notifications.
**Broadcasts**: One-time messages sent to a segment. Your customers can create these themselves from scratch using the message builder.
**Segments (Audiences)**: Groups of customers defined by attributes or behaviors.
Examples: "customers with 1+ pets who haven't booked boarding," "policy holders up for renewal in 30 days," "customers who spent \$500+ last quarter."
**Merge Fields**: Dynamic placeholders that insert personalized data into messages.
Examples: `{{First Name}}`, `{{Business Name}}`, `{{Upcoming Appointment Date}}`.
**Key Distinction**: Your customers can edit automation templates you provide, but they cannot create new automations from scratch. They can, however, create one-time Broadcasts whenever they want. This keeps the experience simple while preventing them from reinventing wheels you've already built.
## The Automation Template Process
### Step 1: You Define Your Automation Library
Reach provides you with a template document to define all automations you want available to your customers.
For each automation, you'll specify:
**Basic Information**:
* **Name**: What customers will see (e.g., "Welcome New Clients," "Win Back Inactive Customers")
* **Description**: Brief explanation of what the automation does and when it triggers
**Message Sequence**: For each email or SMS in the automation:
* **Channel**: Email, SMS, or both
* **Timing**: When to send relative to the trigger event (e.g., "immediately after purchase," "3 days after last visit," "30 days before renewal date")
* **Subject Line** (for email): The email subject
* **Message Content**: Full email or SMS copy, including merge fields
**Segment Definition**:
* **Trigger Conditions**: What causes someone to enter this automation (e.g., "customer makes first purchase," "appointment is completed," "invoice is 30 days past due")
* **Inclusion/Exclusion Criteria**: Additional filters (e.g., "location is in California", "has more than one pet", "does not have auto policy")
### Step 2: Deciding What Data to Expose
Your automation templates will reference data from your schemas (customer attributes, transaction details, custom fields). You control which fields become available as:
**Merge Fields**: Data that can be inserted into message content
**Segmentation Attributes**: Data that can be used to build audience filters
This is done in your schema definition by setting the fields to expose.
### Step 3: Reach Builds Your Automation Library
Once you submit your completed template, Reach will:
1. **Create Automation Templates**: Configure each automation exactly as specified in your template
2. **Build Default Segments**: Set up the audience logic for each automation's trigger conditions
3. **Configure Merge Fields**: Map your schema fields to the message builder so they're available for dynamic insertion
4. **Test Thoroughly**: Verify all automations trigger correctly, messages render properly, and segments identify the right customers
### Step 4: Automations Deploy with Each New Tenant
When one of your customers activates Engage for the first time:
**Automatic Setup**:
* They will be prompted to go through an onboarding flow that collects their business and branding details
* All your defined automations are instantly available in their account and the customer decides which to activate and which not to
* Automations set to "Active" by default start running immediately
* Automations set to "Inactive" are visible but won't send until the customer turns them on
**What Customers See**:
* Clean list of pre-built campaigns relevant to their business
* Toggles to turn each automation on/off
* Preview of message content
* Ability to edit message copy and design
## Customer Customization Capabilities
Your customers can personalize the automations you've provided without breaking them:
**What Customers Can Edit**:
* Message copy and subject lines
* Merge field insertion (selecting from available fields you've exposed)
* Turning automations on/off
**What Customers Cannot Do**:
* Create new automations from scratch (they can create one-time Broadcasts instead)
* Access data fields you haven't exposed
* Delete automations you've provided (they can deactivate them)
* Change timing/sequencing of automations
* Modify segments used for automations
## Iteration and Updates
**Adding New Automations**: Work with Reach to define additional automations for your library. These will be added to all customer accounts during a scheduled deployment.
**Updating Existing Automations**: If you want to modify default content or logic, Reach can push updates to the templates. Customers who haven't customized a specific automation will receive the updates automatically; those who have edited will keep their customizations.
**Seasonal or Event-Based Campaigns**: You can work with Reach to create timely automations (holiday promotions, end-of-year reminders, etc.) and schedule them to become available to all customers at the right time.
## Example Automation Definitions
### Example 1: Welcome New Customer
**Name**: Welcome New Customers
**Description**: Sent immediately after a customer's first purchase to thank them and set expectations
**Trigger**: Customer makes first purchase (transaction count = 1)
**Messages**:
1. **Email - Immediately after purchase**
* Subject: Welcome to \{\{Business Name}}!
* Body: Thank you for choosing us, \{\{First Name}}! We're excited to serve you...
2. **Email - 3 days later**
* Subject: Here's what to expect next
* Body: Hi \{\{First Name}}, just wanted to follow up...
### Example 2: Win-Back Inactive Customers
**Name**: Win Back Inactive Customers
**Description**: Re-engage customers who haven't made a purchase in 90 days
**Trigger**: Last purchase date > 90 days ago
**Exclusion**: Already received this automation in last 180 days
**Messages**:
1. **Email - When they become inactive**
* Subject: We miss you, \{\{First Name}}!
* Body: It's been a while since we've seen you. Here's 15% off your next visit...
2. **SMS - 7 days later (if no purchase)**
* Body: \{\{First Name}}, your 15% off code expires soon! Use: WELCOME15
## Phase 7 Checklist
Automation library document completed with all desired automationsMessage content written for each automationSegment definitions specified (trigger conditions, filters)Merge fields identified from your schemaDefault active/inactive status decided for each automationAutomation library submitted to Reach for implementationTesting completed with Reach to verify automations work correctly
## Next Steps
Configure review requests (if using Reputation)
Implement attribution snippet (if using Measure/Acquire)
# Channel Setup
Source: https://docs.embedreach.com/onboarding/channel-setup
Phase 6: Configure email and SMS for Engage
## Overview
**When needed**: If implementing Engage (email/SMS) or Reputation (review requests)
Phase 6 sets up the communication channels (email and SMS) that Reach will use to send marketing messages on behalf of your customers. This includes domain configuration, sender setup, and consent management.
## Consent Collection
In order for a customer to receive emails and text messages, it is vital that you have a system for maintaining who has opted in and out of various types of marketing messages.
### Email Consent (US)
* **Technically compliant**: Default customers to opted IN for email as long as you provide unsubscribe
* **Reach handles**: Automatic unsubscribe links in every marketing email
* **Your responsibility**: Provide opt-out mechanism if users manage preferences in your platform
### SMS Consent (US)
* **Required**: Direct consent from customer BEFORE sending marketing SMS
* **Proof needed**: Documentation of consent gathering flow (required for Twilio registration)
* **Examples**: Opt-in checkbox at POS terminal, online signup/checkout flow
### Reach's Opt-In Tracking
Reach maintains a record of the opt-in status of each customer for both email and SMS. You can send us this data for individual customers, but it is not required that you do so. If we do not receive any opt-in status from you, Reach will assume the following:
**Default behavior if you don't send opt-in status:**
* Every customer is opted **IN** for email marketing
* Every customer is opted **OUT** for SMS
**Customers can always opt out:**
* Email: Click unsubscribe link in any Reach email
* SMS: Reply STOP to any message
### Updating Opt-In Status via API
If you provide customers or users any means to affect this status outside of Reach communications, you can also update the opt-in status of any customer in Reach using our API. See how at [Update Resource API Documentation →](/api-reference/endpoint/patch-api-resources-schemadefinitionnameorid-externalid)
Simply make a PATCH request to update that resource. In your update, you will set the values of whatever attributes in your customer schema have been mapped to the opt-in attributes for Reach.
You can also retrieve the opt-in status of a specific customer from Reach using our [Get Susbscription by External ID API →](/api-reference/endpoint/get-api-subscriptions-externalid)
## Email Setup
Email sending uses a three-tier architecture for maximum deliverability.
### Initial Domain Setup (One-Time)
You and Reach decide on your base email domain. Two approaches:
### Reach Purchases the Domain
**How it works:**
* Reach buys and owns the domain on your behalf
* Example: `mail-movingcompany.com` or `email-yourplatform.com`
* Reach handles ALL DNS configuration automatically
* Zero DNS management required from you
* Simplest approach with zero ongoing maintenance
**Best for:** Most partners who want a turnkey solution
**Your only decision:** What domain name to use
### You Purchase and Own the Domain
**How it works:**
* You buy and maintain ownership of the domain
* You manage DNS through AWS Route53
* Reach assumes a cross-account IAM role to programmatically provision DNS records
**Requires providing Reach:**
* AWS Account ID
* Role ARN with minimal permissions
* Hosted Zone ID
* Base Domain
**Best for:** Partners who need direct domain control or have existing domain management infrastructure
[Route53 Integration Details →](/engage/channel-integrations#route53)
**Which to choose?** Unless you have a specific business or compliance need to own the domain, Option 1 (Reach-owned) is simpler. Reach handles everything, and you never touch DNS configuration.
### Understanding the Email Infrastructure
The three-tier architecture:
**1. Channel Integration (Base Domain) - One-Time Setup**
The foundational domain that all tenant email addresses will use. Configured once when you first integrate Engage.
* Example: `mail-movingcompany.com`
* For best deliverability: Separate from transactional email domain
**2. Channel Account (Tenant Subdomain) - Auto-Created Per Tenant**
Each tenant gets their own subdomain under the base domain. Holds all DNS records (DKIM, DMARC, return path) for that tenant's email sending.
* Example: `acmemoving.mail-movingcompany.com`
* Created automatically when tenant onboards
**3. Channel Sender (Email Address) - Auto-Created Per Tenant**
The actual "From" address used to send emails, including the user part (before @), display name, and reply-to address.
* Example: `marketing@acmemoving.mail-movingcompany.com`
* Created automatically when tenant onboards
### Complete Flow Example
* **Base domain**: `mail-movingcompany.com` (one-time setup)
* **Tenant channel account**: `acmemoving.mail-movingcompany.com` (auto-created)
* **Sender**: `marketing@acmemoving.mail-movingcompany.com` (auto-created)
Once your Channel Integration is configured, channel accounts and senders are **automatically provisioned** by Reach whenever a new tenant onboards. No additional work required from you.
### Your Responsibilities
* Decide with Reach on base domain approach (Reach-owned vs. self-owned)
* Standardize on sender patterns across your platform
* Ensure compliant opt-in/opt-out flow is in place
### Reach's Responsibilities
* Domain purchase (if using Option 1)
* Channel Account and Sender provisioning
* DNS record generation and verification
* Email sending infrastructure
* Deliverability monitoring
* Bounce and complaint handling
## SMS Setup
SMS uses the same three-tier structure as email, but with tenant-initiated provisioning.
### One-Time Decision
**Your choice:**
* **Reach Managed SMS** (recommended): Reach provisions Twilio subaccount
* **Bring Your Own Twilio**: You provide credentials to existing account
Most partners choose Reach Managed to reduce friction in customer onboarding.
### Your Responsibilities
* **Decision point**: Reach Managed vs. Bring Your Own Twilio
* **Consent gathering**: Ensure SMS opt-in is being captured
* **Proof of consent**: Provide screenshot of standard consent flow (if you have one)
### Reach's Responsibilities
* Create Twilio subaccount for your partner (if using Reach Managed)
* Store and manage Twilio credentials securely
* Provide internal approval workflow
* Provision phone numbers for sending
### Per-Tenant Provisioning (Ongoing)
Unlike email, SMS requires a tenant-initiated application each time:
**Step 1: Tenant Submits SMS Registration Application**
* Tenant completes application **within embedded Reach UI** (not something you build)
* Application requires:
* Legal business information (name, address, EIN/tax ID)
* Use case description
* **Proof of consent capture** - screenshot showing how they obtain SMS opt-in
If you offer a standard consent flow that applies to all tenants, provide Reach with one screenshot. We'll use it for all future tenant applications, streamlining the process.
**Step 2: Reach Provisions Phone Number**
* Creates Channel Account for the tenant (auto-created during application)
* Provisions toll-free phone number in Twilio
* Creates Twilio messaging service for the tenant
* Updates Channel Sender with messaging service SID
**Step 3: Application Approval**
* Typically 5-7 business days for carrier approval
* Once approved, phone number becomes available in Engage SMS builder
### Key Differences from Email
**Consent Documentation Required:**
The critical blocker for SMS approval is proof of consent capture. Tenants must document how they obtain SMS opt-in from customers. This is a regulatory requirement, not a Reach policy.
**Recommended: Provide Standard Consent Template**
Rather than each tenant documenting their own consent flow, provide a standardized opt-in mechanism (e.g., checkbox in your platform's checkout flow) that applies to all tenants. Share this template with Reach once to streamline all future tenant applications.
## Phase 6 Checklist
Consent collection flow designed and implementedEmail domain approach decided (Reach-owned or self-owned)Base domain configured with ReachSMS approach decided (Reach Managed or Bring Your Own Twilio)Standard SMS consent flow screenshot provided (if applicable)Opt-in/opt-out API integration implemented (if users manage preferences in your platform)
## Next Steps
Define automation templates for Engage (if using)
Configure review requests (if using Reputation)
# Credentials & Setup
Source: https://docs.embedreach.com/onboarding/credentials
Phase 1: Getting your Reach credentials and initial setup
## What Reach Provides
* Dev and prod credential sets
* Partner hash and JWT secret
* Partner API Key
* Additional environments upon request
* Shared Slack channel for technical questions
* Access to Partner Dashboard
* Optional Reach Developer MCP Beta access for organization administrators
* Direct line to product and engineering team
## Optional: Connect the Reach Developer MCP (Beta)
The Developer MCP uses browser-based WorkOS authentication, not the API keys or
JWT secrets listed above. An administrator authorizes one WorkOS organization,
which scopes the connection to the corresponding Reach partner and its tenants.
See [Reach Developer MCP (Beta)](/api-reference/developer-mcp) for client setup
and current capabilities.
## Your Responsibilities
### 1. Store Credentials Securely
**Best Practices:**
* Use environment variables or secrets management (AWS Secrets Manager, HashiCorp Vault, etc.)
* Never commit credentials to version control
* Rotate credentials if compromised
* Restrict access to credentials to only necessary team members
### 2. Request Additional Environments
If you need staging, demo, or other environments beyond dev/prod:
1. Contact Reach team via your shared Slack channel
2. Specify what environment you need and its purpose
3. Receive additional credential sets
4. Configure your application to use appropriate credentials per environment
### 3. Join Communication Channels
**Shared Slack Channel Usage:**
* Technical questions during implementation
* Schema definition assistance
* Verifying tracking implementation
* Requesting additional credentials
* Troubleshooting customer setup issues
The Reach team monitors your shared Slack channel during business hours. For urgent production issues, include "@channel" in your message.
## Next Steps
Once your credentials are set up and secured, you're ready to begin frontend integration.
Create JWT authentication endpoint and embed the Reach UI
# Data Sync Setup
Source: https://docs.embedreach.com/onboarding/data-sync-setup
Phase 4: Define schemas for your data structure
## Overview
Phase 4 turns your Phase 3 plan into concrete schemas. You define how your data maps to Reach's system through flexible schema definitions that match your existing data structure—no transformation required.
## The Two-Part Process
You define schemas that describe your data exactly as it exists in your system, and map the fields Reach needs.
Historical import followed by ongoing sync (covered in Phase 5)
This is **self-service** — you create schemas, map fields, and send data through the partner UI or API without waiting on us. During onboarding we'll review the model with you before go-live. If you haven't yet, read [How Reach models your data](/data-sharing/data-model) first; the [Custom Schemas](/data-sharing/custom-schemas) reference has the full JSON format.
## Schema Creation Process
### Step 1: Start from your real data
Use example JSON objects of your customer, transaction, and other important business records **as they exist in your system** as the basis for the schemas you'll define. Don't reshape your data to fit ours — the schema describes your structure as-is.
```json theme={null}
{
"id": "cust_12345",
"email": "john@example.com",
"phone": "+14155551234",
"first_name": "John",
"last_name": "Doe",
"created_at": "2024-01-15T10:30:00Z",
"city": "San Francisco",
"state": "CA",
"total_lifetime_value": 5280.50,
"tags": ["vip", "email_subscribed"]
}
```
```json theme={null}
{
"id": "txn_67890",
"customer_id": "cust_12345",
"amount": 150.00,
"created_at": "2024-03-20T14:22:00Z",
"status": "completed",
"items": [
{
"name": "Service A",
"price": 100.00
},
{
"name": "Service B",
"price": 50.00
}
]
}
```
```json theme={null}
{
"id": "loc_001",
"name": "Downtown Office",
"address": {
"street": "123 Main St",
"city": "Portland",
"state": "OR",
"zip": "97201"
},
"phone": "+15035551000",
"google_business_profile_id": "ChIJ..."
}
```
Send real examples from your database—not idealized versions. Include all fields, even optional ones.
### Step 2: Define custom schemas
Create a schema for each record type. Each schema accepts your exact structure and is assigned a category:
**Schema Categories:**
* **`contacts_schema`**: Customer/contact records
* **`transactions_schema`**: Transaction/billing records
* **`locations_schema`**: Location/address records
* **Additional schemas**: Custom schemas as needed for your business model
**No data transformation required** — your format is accepted as-is. See [Custom Schemas](/data-sharing/custom-schemas) for the JSON Schema format, `$ref` references between schemas, and PII annotations.
### Step 3: Map critical fields
In each schema mapping, identify which fields serve key purposes:
**Customer Schema Mappings:**
* Which field is the email? → `email`
* Which field is the phone? → `phone`
* Which field is the customer ID? → `id`
* Which field is the creation date? → `created_at`
* Which fields for segmentation? → `tags`, `city`, `state`, `total_lifetime_value`
* Which fields for merge fields? → `first_name`, `last_name`
These mappings enable:
* Segmentation for targeted campaigns
* Personalization in emails and SMS
* Attribution logic
**Transaction Schema Mappings:**
* Which field is the amount? → `amount` or `total`
* Which field is the transaction date? → `created_at` or `completed_at`
* Which field links to customer? → `customer_id`
* Which field indicates status? → `status`
* Which fields contain line items? → `items` array
These mappings enable:
* ROAS calculations
* Revenue attribution
* Conversion tracking
**Location Schema Mappings:**
* Which field is the location name? → `name`
* Which field has the address? → `address` object
* Which field links to Google Business Profile? → `google_business_profile_id`
These mappings enable:
* Multi-location reputation management
* Location-based segmentation
* Google Business Profile integration
### Step 4: Send data to the resources endpoint
Once a schema exists, you write records against it at the standard resources endpoint, keyed by schema name:
```bash theme={null}
POST /api/resources/{SchemaName} # e.g. /api/resources/Customer, /api/resources/Transaction
```
Each request accepts your JSON structure directly—no reformatting needed. Writes are an upsert keyed on the record's external ID. See [Ongoing Data Sync](/onboarding/ongoing-sync) for single vs. batch writes and backfill.
## What Data You'll Send
### Customer/Contact Data (Required for All Industries)
**Minimum Required:**
* Email address (primary identifier)
* Unique customer ID from your system
**Highly Recommended:**
* Phone number (enables SMS, improves attribution)
* First and last name
* Creation date/timestamp
* Address (city, state, zip for geographic targeting)
**Optional but Valuable:**
* Custom attributes for segmentation
* Lifetime value or spend metrics
* Customer status (active, inactive, churned)
* Opt-in/opt-out status for email and SMS
* Tags or categories
### Transaction/Billing Data (Varies by Industry)
**E-commerce, Bookings:**
* Order data with line items
* Sent after purchase completion
* Include product/service details
```json theme={null}
{
"externalId": "order_4567",
"customerId": "customer_789",
"amount": 250.00,
"createdAt": "2024-04-15T11:30:00Z",
"status": "completed",
"items": [
{
"name": "Product A",
"quantity": 2,
"price": 100.00
}
]
}
```
**SaaS, Memberships:**
* Agreements/proposals after finalization
* Can be amended over time as contracts change
* Include contract value and terms
```json theme={null}
{
"externalId": "contract_789",
"customerId": "customer_456",
"amount": 12000.00,
"createdAt": "2024-01-10T09:00:00Z",
"startDate": "2024-02-01",
"endDate": "2025-02-01",
"status": "active"
}
```
**B2B Services:**
* Invoice data (even if unpaid)
* More important than payment completion
* Describes the sale before money changes hands
```json theme={null}
{
"externalId": "invoice_123",
"customerId": "customer_789",
"amount": 5000.00,
"invoiceDate": "2024-03-01",
"dueDate": "2024-03-31",
"status": "pending",
"services": [...]
}
```
### Location Data (If Applicable)
**Required for:**
* Reputation product (Google Business Profile mapping)
* Location-based segmentation in Engage
**Skip if:**
* Only using Measure/Acquire
* Single-location businesses
## Key Decision: What Counts as a Transaction?
Work with Reach to define your "conversion event"—the moment that matters for attribution:
**When:** Customer schedules/reserves
**Pros:**
* Shows impact quickly
* Captures intent early
**Cons:**
* Not actual revenue yet
* May include cancellations
**When:** Customer pays
**Pros:**
* Actual revenue
* Most accurate attribution
**Cons:**
* Longer attribution window
* Delayed insights
**When:** Invoice is issued
**Pros:**
* Describes the sale
* Works for B2B/net-terms
**Cons:**
* May not reflect payment
* Requires status updates
You can send updates as transactions progress through stages (booked → paid → fulfilled). This provides both early visibility and eventual accuracy.
## Schema Evolution
Schemas can evolve as your needs change, within strict validation rules that protect existing data:
**Adding new fields** — always safe. Add the field to the schema; existing records are unaffected and the new field becomes available for segmentation and merge fields.
**Renaming, retyping, or removing a field** — restricted once records exist. Removing a field that resources use returns an error rather than silently dropping data; a field that live tenant segments or merge fields depend on is protected. While you're still iterating before go-live, the simplest path is to clear a schema's resources and re-send.
**Adding new schemas** — self-service and independent. Define the new schema and start writing to it at your own pace.
The full change-by-change reference (what's allowed, what errors, and how to fix it) lives in the schema lifecycle guide.
## Phase 4 Checklist
Real JSON examples of customers, transactions, locations
Custom schemas created matching your structure
Critical fields identified for attribution and segmentation
Custom endpoints ready to accept your data
Decision made on what counts as a transaction
## Next Steps
With schemas defined, you're ready to choose a sync method and begin sending data.
Choose sync method and implement ongoing data flow
# Frontend Integration
Source: https://docs.embedreach.com/onboarding/frontend
Phase 2: Embed the Reach UI in your application
### Overview
Phase 2 is about embedding the Reach user interface into your application. Your customers will interact with Reach through this embedded UI to manage their marketing activities.
**You do**:
1. Create a backend endpoint to generate JWT tokens for user authentication
2. Add the iframe embed to your application where you want the Reach UI to appear
3. Configure which Reach products load (measure, acquire, engage, reputation)
4. Customize theming to match your brand
**Reach helps with**:
* Troubleshooting integration issues
* Applying custom styling if you prefer we handle it rather than you doing it in your own code
**Testing**: Use `demo: true` in iframe config to see demo data before completing backend integrations (optional).
Phase 2 is about embedding the Reach user interface into your application. Your customers will interact with Reach through this embedded UI to manage their marketing activities.
For a complete technical guide on embedding the Reach UI, see [iFrame Integration Options](/embeddable-ui/integration-overview).
## Next Steps
With the frontend integration complete, plan what your tenants need *before* you design schemas.
Decide what automations and audiences your tenants need, then work backward to the data
# Integration Overview
Source: https://docs.embedreach.com/onboarding/integration-overview
Complete step-by-step implementation process for Reach
**Optional onboarding assistant:** The [Reach Developer MCP
(Beta)](/api-reference/developer-mcp) gives partner administrators a
way to work with their Reach integration from a compatible AI coding
assistant.
## Implementation Components
Reach implementations have three core integration points, though not all products require all three:
### 1. Frontend UI Embedding
**What**: The Reach interface that your customers interact with
**Responsibility**: Partner implements
**Required for**: All products
**Technical Details**: [Embeddable UI docs](/embeddable-ui/integration-overview)
You'll embed Reach's UI into your application, typically as an iframe (recommended for speed and automatic updates) or React component (for deeper customization). This requires creating a backend endpoint that generates JWT tokens to authenticate users.
### 2. Data Sync
**What**: Sending customer, transaction, and other data to Reach
**Responsibility**: Partner implements
**Required for**: All products
**Technical Details**: [Data Sharing docs](/data-sharing/introduction)
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).
You define flexible schema definitions that match your existing data structure—no transforming data to fit rigid requirements. Work in this order: **decide what your tenants need → derive the data that requires → define the schemas to carry it.** The [Planning phase](/onboarding/planning/engage-automations) walks you through that, and [How Reach models your data](/data-sharing/data-model) explains the model to design against. You can and should send other types of data too; at a minimum we need a copy of the above.
### 3. Attribution & Tracking Snippet (Only for Acquire/Measure)
**What**: JavaScript snippet that tracks customer behavior and form submissions for attribution
**Responsibility**: Partner implements on their own forms; Partner's customers (Tenants) implement on their external marketing sites (if applicable)
**Required for**: Measure, Acquire
**Technical Details**: [Tracking & Attribution docs](/attribution/introduction)
#### What the Tracking Snippet Does
The tracking snippet creates a complete attribution chain from initial visitor to converted customer:
1. **Visitor Identification**: When someone lands on a page with the snippet, Reach generates a unique anonymous identifier for that session
2. **Source Tracking**: The snippet captures where visitors came from—UTM parameters, referrer URLs, ad clicks, organic search, social media, etc.
3. **Cross-page Tracking**: As visitors navigate between pages (marketing site → your booking form), the snippet maintains their identity and source attribution
4. **Identity Resolution**: When a visitor provides their email or phone number, the snippet links that personally identifiable information to their anonymous session and original traffic source
5. **Conversion Attribution**: Later, when you send transaction data to Reach with that same email/phone, Reach connects the revenue back to the original marketing source
#### Why Partners Need to Implement It
Your booking forms are where the critical "identity resolution" moment happens—when an anonymous visitor becomes a known lead. Without the snippet on your forms:
* Reach can track that someone came from an ad
* But cannot connect that visitor to the transaction data you send later
* Attribution breaks—you can't show which ads drove revenue
The snippet must be in your application because that's where your customers' end users convert into leads.
## Let's Get Started
Now you're ready to take the first steps toward embedding Reach and providing your customers with a powerful suite of marketing tools.
Getting your Reach credentials and initial setup
# Ongoing Data Sync
Source: https://docs.embedreach.com/onboarding/ongoing-sync
Phase 5: Choose sync method and implement data flow
## Overview
Phase 5 is about implementing the ongoing flow of data to Reach. Once schemas are defined (Phase 4), you need to choose how to send data and keep it in sync.
## Choose Your Sync Method
Select the method (or combination of methods) that fits your infrastructure:
### Real-Time API
Send customer and transaction records to Reach API as events occur in your system.
**How it works:**
```javascript theme={null}
// When a new customer is created in your system
await fetch('https://api.embedreach.com/api/resources/Customer', {
method: 'POST',
headers: {
'Authorization': `Bearer ${PARTNER_API_KEY}`,
'reach-tenant-id': tenantExternalId,
'Content-Type': 'application/json',
},
body: JSON.stringify({ data: customerData }),
});
```
**Best for:** Partners who want instant analytics and need real-time segmentation
**Pros:**
* Immediate attribution
* Real-time campaign targeting
* Fresh data for segmentation
* Users see changes instantly
**Cons:**
* Requires event hooks in your system
* More API calls (rate limiting considerations)
* Need error handling for each event
### Batch API
Send records to Reach API in scheduled batches (hourly, daily, etc.).
**How it works:**
```javascript theme={null}
// Daily batch sync of yesterday's transactions
await fetch('https://api.embedreach.com/api/resources/Transaction/batch', {
method: 'POST',
headers: {
'Authorization': `Bearer ${PARTNER_API_KEY}`,
'reach-tenant-id': tenantExternalId,
'Content-Type': 'application/json',
},
body: JSON.stringify({
resources: transactionsArray, // Array of transaction objects
}),
});
```
**Best for:** Partners who prefer controlled sync windows or have high transaction volumes
**Pros:**
* Controlled sync windows
* Efficient for high volumes
* Easier error handling
* Can batch similar operations
**Cons:**
* Delayed attribution visibility
* Requires batch processing infrastructure
* Users don't see real-time updates
### Database Access
Grant Reach read-only access to a database view. Reach queries on a schedule to pull new records.
**How it works:**
1. Create read-only database views for customers, transactions, etc.
2. Provide Reach with database credentials (read-only user)
3. Reach queries on schedule (hourly, daily, etc.)
4. No code changes required in your application
**Best for:** Partners who prefer minimal integration work or need to backfill historical data quickly
**Pros:**
* Minimal integration effort
* Easy historical backfill
* Reach manages sync infrastructure
* No API rate limiting concerns
**Cons:**
* Security consideration (database access)
* Less real-time than API methods
* Requires database view creation
* Network connectivity requirements
### CSV Import
Provide Reach with CSV files of your data to be imported.
**How it works:**
1. Export data from your system as CSV
2. Send to Reach team via secure transfer
3. Reach imports and maps to schemas
**Best for:** One-time imports if batch processing or database access are not options
**Pros:**
* Simple for one-time needs
* No integration required
* Quick for historical backfill
**Cons:**
* Not suitable for ongoing sync
* Manual process
* Requires file preparation
* Not scalable
## Hybrid Approaches
Many partners use combinations:
**Database access** for initial historical load → **Real-time API** for ongoing syncs
Best for: Quick historical backfill with real-time updates
**Real-time API** for transactions → **Batch API** for customer updates
Best for: Immediate attribution with efficient customer syncs
**Batch API** for regular syncs → **Database access** for one-time historical backfill
Best for: Ongoing batch syncs with easy historical import
**Real-time API** for new records → **Batch API** for updates
Best for: Fast new record creation with efficient bulk updates
The key is **consistent data flow**—whether event-by-event or in regular batches. Choose what fits your infrastructure and commit to keeping Reach's data in sync with yours.
## Your Responsibilities
Show Reach your existing data structure
What counts as a transaction for attribution
Real-time API, batch API, database access, or hybrid
If using API methods
As customers and transactions are created/updated
## Reach's Responsibilities
* Create custom schemas matching your data
* Map fields to attribution logic
* Provision custom API endpoints
* Handle schema evolution as needs change
* Query database on schedule (if using database access)
## Phase 5 Checklist
Sync method chosen based on infrastructure needsHistorical data backfilledOngoing sync implemented for new recordsUpdate logic implemented for changed recordsTransaction status changes syncedError handling and retries in placeMonitoring and logging configured
## Next Steps
With data flowing to Reach, you're ready for product-specific setup.
Configure email & SMS for Engage (if using)
Implement attribution snippet for Measure/Acquire (if using)
# Welcome to Reach
Source: https://docs.embedreach.com/onboarding/overview
Get started with integrating Reach into your platform
## Overview
This onboarding guide provides a comprehensive walkthrough for implementing Reach products into your platform. For detailed technical specifications, refer to our [API documentation](/api-reference/introduction).
**Work in the order that matches how the product thinks.** Decide what your tenants need → derive the data that requires → define the schemas to carry it. That's why **Planning (Phase 3)** comes *before* schema design: the [planning guides](/onboarding/planning/engage-automations) start from a tenant's business goal in plain English and work backward to the data, so you don't design schemas and then discover they can't answer the questions your tenants actually have.
## Getting Help
**Shared Slack Channel**: Your primary communication channel with Reach's product and engineering team. Use this for:
* Technical questions during implementation
* Schema definition assistance
* Verifying tracking implementation
* Requesting additional credentials for staging/demo environments
* Troubleshooting customer setup issues
**Support Email**: [support@embedreach.com](mailto:support@embedreach.com) for general inquiries
During onboarding, partner administrators can use the **Reach Developer MCP
(Beta)** to work with their Reach integration from a compatible AI coding
assistant. See the [Developer MCP guide](/api-reference/developer-mcp).
## Three Core Integration Points
Reach implementations have three core integration points, though not all products require all three:
**Required for**: All products
**You implement**: JWT authentication + iframe/React embedding
[Learn more →](/onboarding/frontend)
**Required for**: All products
**You implement**: Customer & transaction data APIs
[Learn more →](/onboarding/data-sync-setup)
## Understanding Reach Environments
Reach provides two environments for your implementation (more available upon request):
### Development Environment
* Use for initial integration work and testing
* No real customer data should be used
* Safe for experimentation and iteration
* Credentials provisioned at start of partnership
### Production Environment
* Use only after development integration is complete and tested
* Real customer data flows through this environment
* Credentials typically provisioned after partnership agreement is signed
### Demo Mode
For frontend testing and sales demos without full backend setup, enable demo mode in the iframe config (`demo: true`).
**Features:**
* Shows demo data in the UI without requiring real integrations
* Easy way to show the integrated solution to prospective customers
* Test seamlessly without backend dependencies
* Customizable demo data (ad copy, review content) for your industry
## Quick Navigation
Key concepts to understand
Phase 1-2: Credentials & Frontend integration
Phase 3: Decide what your tenants need, then work backward to the data
Phase 4-5: Schema creation and data syncing
Phase 6: Email & SMS configuration (Engage/Reputation)
Phase 7: Automation templates and segments (Engage)
Phase 8: Internal feedback and Google reviews
Phase 9: Attribution snippet (Acquire/Measure)
Detailed API documentation
Connect an AI coding assistant to your Reach partner account
## What You'll Embed
By following this guide, you'll enable your customers to:
Targeted communication campaigns with pre-built automation templates. No marketing expertise required—just activate and customize industry-specific workflows.
Comprehensive ad reporting dashboards with attribution tracking across all
marketing channels. Your customers can see exactly which marketing efforts
drive revenue.
Automated ad campaign creation and management for Google and Meta. AI
optimizes targeting, budget allocation, and creative elements to maximize ROI.
Automated review requests and feedback collection linked to Google Business Profiles. Turn customer sentiment into actionable insights.
# Planning Engage Automations
Source: https://docs.embedreach.com/onboarding/planning/engage-automations
A planning guide for partners adopting Engage: how automations and segments work, how to translate business goals into supported triggers, and what data you need to send us.
Read this *before* you start scoping the data integration — it will save you a redesign later. Planning for Reputation builds on the same concepts; see the [Planning Reputation Automations](/onboarding/planning/reputation) guide once you've worked through this one.
## The mental model: customer → segment → automation
Three concepts, in this order:
1. **A customer** is one person at one of your tenants. They have an identity (email and/or phone), some attributes (name, opt-in status, custom fields you define), and a history (transactions, events) that you've sent us.
2. **A segment** is a saved question about customers: *"which of this business's customers match these conditions right now?"* Segments are always lists of *people*, never lists of things or events.
3. **An automation** is a trigger plus a sequence of actions. When the trigger fires for a customer, that customer is run through the action sequence — typically an email or SMS, optionally with waits and follow-ups in between.
Every automation answers two questions: **when does it fire?** (the trigger) and **who does it fire for?** (the audience, which is one or more segments). Phrasing both in terms a Reach segment can express is the key to building the automation you want — the [customer-centric rule](#the-customer-centric-rule-and-how-to-reframe-a-business-event) below shows how to get there.
## The three trigger types (and only three)
Every automation on Reach uses exactly one of these. There are no others.
| Trigger | What it does | Typical use |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Broadcast** *(one-time)* | The automation runs once, at a scheduled timestamp (or immediately). Everyone in the audience receives the action sequence on that one run. Then the automation is done. Think of this as a single send to a list, not a recurring rule. | A holiday promotion. A one-off announcement. A campaign to win back lapsed customers in Q4. |
| **Segment entry** *(trigger-based)* | The automation runs for a customer the moment they *enter* a chosen segment. Nearly anything can be modeled as "customer entered segment X," which makes this the most flexible trigger in the system and the one most automations are built on. | A welcome series when a customer is first added. A reminder when a customer becomes overdue. A win-back when a customer hasn't purchased in 60 days. |
| **Date-based** | The automation runs once a year, on a fixed calendar date (e.g. March 15). On that date, everyone in the audience runs through the action sequence. | An annual greeting on a specific holiday. A yearly client appreciation message tied to a known calendar date. |
**Important nuance on date-based triggers.** "Date-based" means a *fixed* month and day for the whole audience. It does **not** mean "send 30 days before each customer's renewal." Per-customer relative dates (birthdays, anniversaries, days-since-purchase, days-until-X) are handled by *segments*, not by date-based triggers. You build a segment like "renewal date is between 30 and 31 days from today" and pair it with a segment-entry trigger.
**Timezone.** All waits and date-based triggers currently evaluate in `America/New_York` (EST/EDT). Plan messaging windows accordingly.
## What a segment can ask about a customer
A segment is a set of conditions joined by AND/OR. Each condition asks about one of the following:
### Built-in customer fields
* `email`, `phone`, `firstName`, `lastName`, `userId`
* Opt-in / opt-out status for email and SMS
* HIPAA consent (if applicable to your vertical)
### Custom fields you define
When you set up your integration, you describe a schema for the customer attributes your platform tracks. Anything in that schema becomes a segmentable field. Examples: `loyalty_tier`, `preferred_location_id`, `plan_type`, `signup_source`.
### Transaction or event history
You can also send us per-customer records — appointments, invoices, orders, reservations, claims, whatever your domain uses. Segments can then ask count-based questions ("has at least 2 invoices in the last 90 days") or date-based questions ("most recent appointment date is within the last 30 days").
### Operators available
Standard comparison (`equals`, `not equals`, `greater than`, `less than`, `contains`, `in [list]`, `exists`, `not exists`) plus date-specific operators that make the customer-centric reframe possible:
* **Today-relative dates:** "field is within last N days," "field is N days from today (before or after)." This is how you express "30 days before renewal" or "7 days after signup."
* **Month/day matching:** recurring annual conditions like "birthday is today" or "anniversary falls in March."
* **Related-resource counts:** "has at least N *X*" where X is a transaction or event you've sent us.
If you can phrase your audience as *"a customer who satisfies these conditions right now,"* you can build it as a segment. If you can't, see the next section.
## The customer-centric rule, and how to reframe a business event
**The rule:** a Reach segment returns *customers*. The question being asked can be about a customer's own attributes *or* about the records related to them — bookings, invoices, appointments, sessions — but the answer is always a list of people. There is no "60 days before a tournament starts" trigger, because a tournament on its own is not a customer.
This shift in framing is the most valuable move you can make during planning. Partners whose product is built around scheduled events, appointments, renewals, or expirations naturally think in business-level events — and the good news is that almost any business-level event you care about can be expressed as a question about customers. The most common technique is to reach *through* a relationship the customer has to another record, and once you've done that translation, the rest of the automation falls into place.
### Working example: a pet-boarding platform
Suppose your platform serves kennels and pet boarding facilities. Each tenant has customers who book multi-day stays. Your tenants tell you: *"I want to send a reminder 7 days before each customer's stay begins, asking them to confirm and complete pre-check-in forms."*
The instinct is to phrase the trigger as a business event: *"7 days before a stay starts."* But "a stay" on its own is not a customer — it's a record that *belongs* to one. The fix is to phrase the question about the customer's relationship to that record.
Decide which records on your side belong to a customer and matter for messaging. For this partner: each customer has zero or more *bookings*, and each booking has a `start_date`, an `end_date`, a `status`, and so on. Send those bookings to Reach as related records attached to the customer.
"Customers who have at least one booking whose `start_date` is between 7 and 8 days from today and whose `status` is *confirmed*." The segment still returns a list of people — but the condition reaches into each person's bookings to find the match.
When a customer enters the segment — that is, when one of their bookings crosses the 7-day threshold — the automation fires and the reminder goes out. As bookings get added, edited, or cancelled and resynced, customers naturally move in and out of the segment.
This pattern generalises. "Send a follow-up to customers whose most recent invoice was paid more than 30 days ago" → segment on *"has at least one invoice with paid\_date more than 30 days ago, and zero invoices with paid\_date in the last 30 days."* "Win back customers who haven't visited in 90 days" → segment on *"has at least one visit, and zero visits in the last 90 days."* The shape is the same: ask about the customer's related records, count or date-filter them, return the customers who qualify.
When the relationship doesn't add anything — for example, the data you care about really is just a property of the customer, like `loyalty_tier` or `signup_date` — you can also segment directly on a customer attribute. Both work. Choose the model that matches how your platform actually stores the data.
**Heuristic:** if the event you care about belongs to a customer (a stay, an invoice, an appointment, a renewal, a session), you can almost always express it as either a customer attribute or a question about related records. If the event truly belongs to the *business* and not to any specific customer (e.g. "the store's 5-year anniversary"), you can't trigger from it — but a broadcast or date-based automation may cover the use case.
## A working example, end to end: a pool-cleaning winback
To make all of this concrete, here's an Engage automation built the way a partner serving pool-cleaning businesses might design it. It uses the related-records pattern above and shows what the final automation looks like in the builder.
### The automation
**Goal.** Win back customers who used to book regular pool cleanings but have lapsed. The thinking: if a customer hasn't had a cleaning in the last 30 days and doesn't have one on the books, they're at risk of churning. Send them a friendly nudge. If they still haven't booked 15 days later, follow up once more.
**How it works.** A segment finds qualifying customers. The moment a customer enters that segment, the automation sends the first email. It then waits 15 days. Before sending the follow-up, it checks whether the customer is *still* in the segment — if they booked a cleaning during the wait, they've already fallen out and the automation exits without bothering them. If they're still lapsed, it waits until the next 9 AM and sends the second email.
### The segment
Each customer at a pool-cleaning business has a collection of *cleanings* sent to Reach as related records. Each cleaning has a `service_date` (when it happened, or is scheduled for) and a `status` (`completed`, `scheduled`, `cancelled`). The segment asks three questions about that collection:
| Condition | What it checks |
| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Has at least 1 cleaning where `status = completed` | The customer has been a customer at some point — we don't want to nudge brand-new contacts who never booked anything. |
| Has 0 cleanings where `status = completed` AND `service_date` is within the last 30 days | They haven't been serviced recently. |
| Has 0 cleanings where `status = scheduled` AND `service_date` is in the future | And they don't have anything on the books either. |
Joined with AND, this returns: *"customers who have used us before, haven't been serviced in the last 30 days, and have nothing scheduled."* Exactly the at-risk cohort.
The segment is dynamic. As days pass, customers cross the 30-day threshold and enter the segment. As customers book a new cleaning, they exit. The automation reacts to both transitions automatically.
### The flow
This is what the automation looks like in the partner-dashboard builder:
Two steps make this flow smarter than a simple two-message sequence. The **check segment membership** step keeps the messaging relevant — it reevaluates segment membership at that point, so a customer who booked a cleaning during the 15-day wait exits the automation cleanly and never receives a redundant nudge. The **wait until 9 AM** step makes sure the follow-up lands at a friendly time of day, 9 AM on day 15 (or the next morning if 9 AM has already passed), rather than whatever hour the previous wait happened to end on.
To run this automation, the partner needs to send Reach: each customer's cleanings (as a collection of related records, each with `service_date` and `status`), and a stable customer identity (external ID, email, name). That's it. Everything else — the segment, the trigger, the timing, the messages — is configured inside Reach.
## What you must send us
Before any of the planning in this guide can run in production, your platform has to deliver the underlying data. Roughly:
### Customer identity
* A stable **external ID** per customer (your platform's identifier).
* **Email** (required to send email), **phone** (required to send SMS), or both.
* **First and/or last name** (for personalization and compliance footer requirements).
* **Opt-in / opt-out signals** for email and SMS — either as fields, or via the events when consent changes.
### Business locations
**Business locations** are **required only if you're using Reputation.** There, every location maps to a Google Business Profile (GBP), and that mapping is what lets Reach route review requests to the right GBP and attribute the resulting reviews back to the correct location — so every Reputation tenant needs at least one location record.
For Engage on its own, locations are **optional but useful.** A single-location tenant doesn't need them. A multi-location tenant benefits from them: if a customer is tied to a specific location and you want messaging scoped accordingly (only customers at the Brooklyn branch, only customers whose preferred location is closed for the season), the customer's preferred or assigned location is a relationship field on the customer — see [Custom attributes](#custom-attributes-on-the-customer) below.
See [Location Data](/data-sharing/requirements#location-data) in the data-sharing requirements for the full list of fields.
### Custom attributes on the customer
Anything you want to segment on that lives directly on the customer. You'll declare these in a schema mapping during onboarding. Examples:
* Customer lifecycle fields: tier, plan, status, signup source.
* Relationship fields: assigned staff member, preferred location, account owner.
* Roll-up date fields, if it's easier to compute them on your side than to send the underlying records: `last_visit_date`, `next_appointment_date`, `renewal_date`.
### Related records (the bookings model from the reframe section)
If your tenants' work is naturally a stream of records per customer — bookings, visits, orders, invoices, claims, sessions, reservations — send those records as related collections rather than flattening them onto the customer. Segments can then count them, find the most recent, filter by date window, or check status. This is almost always the more powerful model: you avoid having to precompute and resync derived fields, and you can express richer questions ("has at least one upcoming booking *and* at least one completed booking in the last year"). See [How Reach models your data](/data-sharing/data-model) for how these related records reference the customer via `$ref`.
### Keep it fresh
Whatever you send must be kept up to date. A segment that asks about a customer's upcoming bookings only works if those bookings are resynced to us when they're added, edited, or cancelled. Automations are only as good as the data behind them.
## Messages, copy, and the email template
An automation isn't just a trigger and an audience — it's also what gets sent. The work to produce that content runs alongside the planning in this guide, not after it. Two parts:
### The email template (one per partner)
As part of onboarding, you'll work directly with Reach to craft a default **email template** — the layout, branding, header/footer, typography, and link styling that wraps every email your tenants send through the platform. You only do this once, and it serves as the starting point for every message in every automation, across every tenant.
Per-tenant branding is automatic. Each tenant's logo, accent colour, business name, address, and other business details are injected into the template via merge fields, so an email from one tenant looks like it came from them and an email from another tenant looks like it came from them — without you or the tenant having to do anything.
From there, two layers of explicit customization exist:
**At the partner level (you).** You can tailor the default template at any granularity you need:
* Override the template for a specific automation (e.g. a distinct look for win-back campaigns).
* Override it for a specific message inside an automation (e.g. a different banner image on just the follow-up).
**At the tenant level (your customers).** Each tenant inherits your defaults — including any partner-level overrides — and can customize further within their own account:
* Override the template for a specific automation or message in their account.
* Bring their own template entirely if they have brand or design requirements your default doesn't accommodate.
Tenant customizations stay scoped to that tenant; they never affect your defaults or other tenants.
Start thinking about the default template early. The decisions are concrete and small in number, but they set the visual identity of every email and you don't want them blocking your launch.
### Message copy (one per automation)
For every automation in your inventory, someone has to write the actual subject line, email body, and — if SMS — the SMS text.
Two practical notes:
* **Draft copy as you plan each automation.** You don't need final wording — even a rough first draft makes the audience and trigger decisions much more concrete, and surfaces things like "this only makes sense if we know the customer's first name" that affect the data side.
* **Personalisation tokens.** If a message needs to address the customer by name, mention their next appointment date, or reference any other piece of customer data, that data needs to be syncing to us. Note the personalisation requirements when you draft the copy so they roll up into your data requirements alongside segment fields.
## Capturing your plan
The intended outcome of working through this guide is a concrete plan with three parts:
1. **An automation inventory** — every Engage automation you want to pre-populate for your tenants. For each, the business goal, the trigger type, the channel, and a draft of the message copy.
2. **An audience translation** — for each automation, the segment definition in terms of fields and operators (or questions about related records), plus a marker of whether it's buildable today, buildable once you send additional data, or something you want to walk through with Reach.
3. **A data checklist** — every field referenced across your segments, rolled up into a single list with current sync status. This is what your engineering team scopes against.
During onboarding, Reach will provide a [planning worksheet](/onboarding/planning/worksheet) that organizes these three pieces into a single document. You'll fill it in, send it back, and we'll review it with you — flagging anything that doesn't fit the supported model and confirming the data fields against our schema-mapping format before your engineers start integrating.
Questions, edge cases, or a use case you can't fit into the model? Bring it to your Reach contact early — most apparent blockers turn out to be reframings, and the few that don't are worth knowing about before you ship.
## Next Steps
With your plan captured, turn it into schemas.
Define the schemas that carry the data your plan requires
# Planning Reputation Automations
Source: https://docs.embedreach.com/onboarding/planning/reputation
A planning guide for partners adopting Reputation: how the default review-request flow works, how to customize it, and what data you need to send us.
The Reputation product covers internal feedback requests, Google review prompts, and the reminders that go with them. Planning a Reputation rollout draws on the same core concepts as Engage — automations, segments, triggers, and the customer-centric framing — so if you haven't already, the [Planning Engage Automations](/onboarding/planning/engage-automations) guide is the right starting point. It explains [the mental model](/onboarding/planning/engage-automations#the-mental-model-customer-segment-automation), [the three trigger types](/onboarding/planning/engage-automations#the-three-trigger-types-and-only-three), and [how segments work](/onboarding/planning/engage-automations#what-a-segment-can-ask-about-a-customer). This guide assumes you've read those sections — or are happy to refer back to them — and focuses on what's specific to Reputation.
## The default setup, ready to use
Reach ships a default Reputation configuration that most partners can adopt more or less out of the box. It's the canonical flow:
1. **Shortly after a customer interaction** (the trigger), an internal feedback request goes out.
2. **If the customer responds positively**, they're prompted to leave a Google review.
3. **If they don't respond at all**, they receive one reminder.
The trigger, cadence, segment logic, and reminder timing are all pre-configured. If that flow matches what your tenants need, you can launch on it with no segment work of your own — you only need to make the decisions in [What you do need to decide](#what-you-do-need-to-decide) below.
## How it maps to Engage concepts
The mapping:
| Reputation concept | What it is in automation terms |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The trigger that starts the flow | A segment-entry trigger (see [trigger types](/onboarding/planning/engage-automations#the-three-trigger-types-and-only-three)) — typically firing when a customer has a recently-completed interaction. |
| The audience | A [segment](/onboarding/planning/engage-automations#what-a-segment-can-ask-about-a-customer). Filters such as "only customers who opted in to review requests" or "only customers above a spend threshold" are segment conditions. |
| The initial feedback request | A send-communication step with a feedback form action template. |
| The Google review prompt | A send-communication step that prompts the customer to leave a Google review. |
| The reminder | A wait step followed by another send, with an optional check-segment-membership guard so anyone who already responded isn't pinged again. |
How these steps are sequenced is one of the decisions you'll make. Some partners turn on **smart routing**, where the Google review prompt is sent only to customers who respond positively to the internal feedback request — directing happy customers toward a public review and routing less-positive feedback to the business privately. Others send the Google review prompt to everyone, either alongside the internal feedback request or as the only ask. Reach supports either model; the smart routing logic, when used, is handled inside the Reputation templates so you don't have to design the branching yourself.
## Customizing audiences
If your tenants have specific requirements — different timing for the internal feedback vs. Google review prompt, additional eligibility filters, or different cohorts handled differently — you provide segment inputs to define those audiences. The [customer-centric rule](/onboarding/planning/engage-automations#the-customer-centric-rule-and-how-to-reframe-a-business-event) is the technique to lean on when an audience involves a customer's recent interactions or upcoming events.
A few examples of Reputation-specific audience filters that partners commonly want:
* **Only customers above a certain spend threshold.** Useful when tenants want to prioritize asking for reviews from high-value customers. Expressed as a segment condition on customer attributes or a sum across related transaction records.
* **Only customers who opted in to review requests.** A boolean field on the customer.
* **Only customers tied to a specific staff member or location.** A relationship field on the customer, useful when tenants want to throttle review velocity per staff member or rotate which locations are actively soliciting reviews.
* **Excluding customers who recently received a request.** Expressed as "has zero feedback requests in the last N days" — protects against over-asking.
If you can express the requirement as a question about customers (directly or by reaching through related records), it's buildable.
## What you do need to decide
Even if you adopt the default flow as-is, two decisions are yours to make.
### Message copy
The default Reputation templates ship with generic wording. Most partners want to brand and tone-match the messages — the initial feedback request, the Google review prompt, and the reminder. As part of onboarding, you'll work directly with Reach to craft a default email template that wraps every message and to finalize the per-message copy. See the [Engage guide's section on messages, copy, and the email template](/onboarding/planning/engage-automations#messages-copy-and-the-email-template) for how this works — the same template you craft for Engage is reused here.
### The internal feedback scale
What scale should the feedback form use? Common choices:
* **Thumbs up / thumbs down.** Simplest. Under smart routing, a thumbs-up sends the Google review prompt; a thumbs-down keeps the feedback internal.
* **A 1–5 number scale.** Slightly more granular. Under smart routing, partners typically treat 4 and 5 as "positive" (route to Google review) and 1–3 as "negative" (private feedback).
* **A star rating, typically 3 or 5 stars.** Visually warmer than a number scale. With 5 stars, 4–5 is the typical positive threshold under smart routing; with 3 stars, 3 is.
If smart routing is on, the scale you choose also determines what counts as "positive" and therefore who receives the Google review prompt. Pick the scale that matches your tenants' brand and how granular they want their feedback data.
## What you must send us
The data requirements for Reputation are a subset of the [Engage data requirements](/onboarding/planning/engage-automations#what-you-must-send-us). At minimum:
* **Customer identity** — a stable external ID, plus email and/or phone, plus first/last name.
* **Business locations** — every tenant needs at least one location record, mapped to a Google Business Profile, so review requests route to the right GBP and the resulting reviews are attributed to the correct location. This matters most for multi-location tenants, but every tenant needs at least one. See [Location Data](/data-sharing/requirements#location-data) for the field list.
* **The customer interaction that triggers the feedback request.** This is the Reputation-specific piece. Whatever event you want to ask about — a completed appointment, a closed service ticket, a finalized order — needs to be sent to Reach as a related record on the customer, with a timestamp and a status. The Reputation segment then asks "has a recently-completed interaction" by reaching through that collection.
* **Opt-in / opt-out signals** for email and SMS.
If your tenants want any of the customization filters above (spend threshold, staff member, review-request opt-in), the fields backing those filters need to sync too. Keep the data fresh on your side — a feedback request that goes out hours after a service is fine; one that goes out three days late feels strange to the customer.
## Capturing your plan
During onboarding, Reach will provide a [planning worksheet](/onboarding/planning/worksheet) that organizes your Reputation plan alongside any Engage automations. For Reputation specifically, the worksheet will capture:
1. **Whether you're adopting the default flow as-is** or customizing the audience.
2. **Any custom segment filters** — described in plain English and in terms of fields/operators.
3. **Your feedback-scale choice**, whether smart routing is on, and (if it is) the threshold that counts as "positive."
4. **Draft message copy** for the feedback request, the Google review prompt, and the reminder.
5. **The data fields** required to support all of the above.
Send the populated worksheet back to your Reach contact. We'll review it with you, flag anything that doesn't fit the supported model, and confirm the data fields against our schema-mapping format before your engineers start integrating.
Questions, edge cases, or a use case you can't fit into the model? Bring it to your Reach contact early — most apparent blockers turn out to be reframings, and the few that don't are worth knowing about before you ship.
# Planning Worksheet
Source: https://docs.embedreach.com/onboarding/planning/worksheet
The three-part worksheet that captures your automation plan before your engineers start integrating.
Once you've worked through the [Planning Engage Automations](/onboarding/planning/engage-automations) guide (and, if you're using Reputation, [Planning Reputation Automations](/onboarding/planning/reputation)), this worksheet is where you write the plan down. Fill it in, send it back to your Reach contact, and we'll review it with you — flagging anything that doesn't fit the supported model and confirming the fields against our schema-mapping format before your engineers start integrating.
It has three parts. They build on each other: the audiences you need determine the data you must send.
## Part 1 — Automation inventory
Every Engage automation you want to pre-populate for your tenants. One row per automation.
| Column | What to capture |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Automation name** | What tenants will see (e.g. "Win back lapsed customers"). |
| **Business goal** | One plain-English sentence: what outcome it drives. |
| **Trigger type** | Broadcast, segment-entry, or date-based (see [the three trigger types](/onboarding/planning/engage-automations#the-three-trigger-types-and-only-three)). |
| **Channel** | Email, SMS, or both. |
| **Message copy (draft)** | Subject + body draft. Rough is fine — it surfaces which customer data the message needs. |
## Part 2 — Audience translation
For each automation, the segment that defines its audience — translated from the business goal into fields and operators.
| Column | What to capture |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Automation** | Links back to a Part 1 row. |
| **Audience in plain English** | "Customers who used us before but haven't been serviced in 30 days and have nothing booked." |
| **Segment definition** | The same audience as conditions — fields, operators, and any [related-record questions](/segments/segments#related-record-conditions-counts-across-a-relationship). |
| **Buildable?** | Buildable today · buildable once you send additional data · needs a walkthrough with Reach. |
## Part 3 — Data checklist
Every field referenced across all your segments and messages, rolled up into a single list. This is what your engineering team scopes against.
| Column | What to capture |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| **Field** | The customer attribute or related-record field (e.g. `cleaning.service_date`). |
| **Source** | Which of your records it comes from, and the schema it belongs to. |
| **Concept** | Contact, transaction, location, or a custom schema (see [How Reach models your data](/data-sharing/data-model)). |
| **Sync status** | Already syncing · needs to be added · derived/rolled-up. |
| **Expose to tenants?** | Whether tenants should see/segment on it, and the friendly name + description if so. |
Bring edge cases and "I'm not sure this fits" rows to your Reach contact early. Most apparent blockers turn out to be reframings — and the ones that don't are worth catching before your engineers build against them.
# Reputation Setup
Source: https://docs.embedreach.com/onboarding/reputation
Phase 8: Configure review requests and feedback
## Overview
**When needed**: If implementing Reputation (reputation management)
Phase 8 sets up review request and feedback collection flows. If you're already setting up Engage, the additional setup for Reputation is minimal.
## What Reputation Does
Automates the process of requesting reviews and collecting feedback from customers after transactions or service completion.
**Features:**
* Private feedback requests (internal only)
* Public review requests (Google Business Profile, etc.)
* Automated sending based on transaction triggers
* Review monitoring and response management
## Your Responsibilities
### 1. Send Location Data to Reach
If your customers have multiple business locations, send location records so they can map to their Google Business Profiles.
### 2. Embed Reputation UI
Include the Reputation iframe in your platform. See more at [Embedding Reach →](/embeddable-ui/iframe/embedding)
### 3. Key Decisions
Work with Reach to decide:
**What to send:**
* Both internal feedback AND public review requests?
* Or just one?
**Which channels:**
* Email, SMS, or both?
**Who receives requests:**
* All customers?
* Only customers with completed transactions?
* Only customers with transactions above certain value?
**When to send:**
* Immediately after transaction?
* X days after transaction completion?
* After specific transaction statuses?
## Reach's Responsibilities
* Configure email and SMS senders (using Phase 6 channel setup)
* Configure templates for review/feedback requests
* Create segments for determining who receives requests and when
* Set up Google Business Profile integration infrastructure
## Customer's Responsibilities
Your customers (tenants) need to:
1. **Connect their Google Business Profile** within the Reach UI
2. **Map locations** (if they have multiple) to their Google Business Profile locations
3. **Customize request templates** (optional - you provide defaults)
These are tenant-side actions performed within the embedded Reach UI. You don't need to build any of this—Reach provides the interface.
## Example Use Cases
### Use Case 1: Request Review After Service Completion
**Trigger**: Transaction status changes to "completed"
**Wait**: 2 days
**Send**: Email request for Google review
**Target**: Customers who completed transaction >\$100
### Use Case 2: Internal Feedback First, Then Review
**Step 1**: Send private feedback request via SMS immediately after transaction
**Step 2**: If feedback is positive (4-5 stars), send public review request 1 day later
**Step 3**: If feedback is negative, alert business owner but don't request public review
## Phase 8 Checklist
Location data schema created (if multi-location)Location data synced to ReachDecision made: Internal feedback, public reviews, or bothDecision made: Email, SMS, or both channelsSending logic defined (who receives requests and when)Reach has configured templates and segmentsReputation UI embedded in platformTested with sample tenant connecting Google Business Profile
## Next Steps
Implement attribution snippet (if using Measure/Acquire)
# Tracking Implementation
Source: https://docs.embedreach.com/onboarding/tracking
Phase 9: Implement attribution snippet for Measure/Acquire
## Overview
**When needed**: If implementing Measure (analytics) or Acquire (ad management)
Phase 9 implements the JavaScript tracking snippet that enables attribution—connecting anonymous website visitors to known customers and ultimately to revenue.
For all technical details of implementing tracking, please see [Introduction to Attribution and Tracking](/attribution/introduction).
## What the Tracking Snippet Does
The tracking snippet creates a complete attribution chain from initial visitor to converted customer:
### 1. Visitor Identification
When someone lands on a page with the snippet, Reach generates a unique anonymous identifier for that session.
### 2. Source Tracking
The snippet captures where visitors came from:
* UTM parameters
* Referrer URLs
* Ad clicks (Google Ads, Meta)
* Organic search
* Social media
* Direct traffic
### 3. Cross-Page Tracking
As visitors navigate between pages (marketing site → your booking form), the snippet maintains their identity and source attribution.
### 4. Identity Resolution
When a visitor provides their email or phone number, the snippet links that personally identifiable information to their anonymous session and original traffic source.
### 5. Conversion Attribution
Later, when you send transaction data to Reach with that same email/phone, Reach connects the revenue back to the original marketing source.
## Why Partners Need to Implement It
Your booking forms are where the critical "identity resolution" moment happens—when an anonymous visitor becomes a known lead.
**Without the snippet on your forms:**
* Reach can track that someone came from an ad
* But cannot connect that visitor to the transaction data you send later
* Attribution breaks—you can't show which ads drove revenue
**The snippet must be in your application** because that's where your customers' end users convert into leads.
## Implementation Steps
### Step 1: Add Tracking Snippet to Your Forms
Add the Reach tracking snippet to pages you host where visitors identify themselves. This is any marketing landing page, booking form, checkout form, quote form, or other type of page that you host for your clients.
### Step 2: Implement createIdentification Calls
When a visitor submits a form with their email or phone, call `createIdentification`.
### Step 3: Provision Snippets for Your Customers
Your customers may have their own external marketing websites. Provide them with pre-populated tracking snippets during their onboarding.
**This will look something like**
```javascript theme={null}
```
### Step 4: Feature Flag for Acquire vs Measure
Add a feature flag to give Acquire to customers paying for it and Measure to customers only paying for Measure. It is up to you to detemine which of your customers has access to which.
Acquire includes all Measure functionality plus ad campaign management. Measure is analytics-only.
## Your Customers' Responsibilities
### For Acquire/Measure Customers
**1. Add tracking snippet to external marketing websites**
If they have their own landing pages or websites not owned by your platform, they need to add the tracking snippet.
**2. For Acquire: Grant access to ad accounts**
* Google Ads account access
* Meta Business account access
* Google Tag Manager (if using)
This is not an implementation step you need to handle. This is done when businesses activate the product by OAuthing within Reach's embedded UI.
## Reach Helps With
* Verifying tracking is working correctly (manual check via Slack)
* Additional form tooling for customers who have their own sites and forms
* Troubleshooting attribution issues
* Sets up and runs ads for customers using Acquire
## Advanced: UTM Parameter Handling
The snippet automatically captures UTM parameters from URLs:
```
https://yourbookingform.com?utm_source=google&utm_medium=cpc&utm_campaign=spring_sale
```
These are automatically associated with the visitor session and carried through to attribution.
## Troubleshooting
**Check:**
* Script URL is correct
* No Content Security Policy blocking
* No ad blockers interfering
* Browser console for errors
**Check:**
* `createIdentification` is being called
* Email or phone is provided
* Network request succeeds (200 OK)
* tenantId is correct
**Check:**
* Snippet is on ALL pages in user journey
* createIdentification called with same email/phone as transaction data
* Transaction data is being synced to Reach
* Customer IDs match between identification and transaction
## Phase 9 Checklist
Tracking snippet added to your booking/lead forms`createIdentification()` implemented on form submissionsSnippet provisioning system built for customersFeature flag implemented for Acquire vs MeasureTesting completed (snippet loads, identifications record)Reach team notified to verify trackingAttribution tested end-to-end
## Integration Complete!
Congratulations! You've completed all 9 phases of Reach integration.
Review the complete integration guide
# Introduction
Source: https://docs.embedreach.com/reputation/introduction
Automated Google review collection and optional private feedback capture.
## Overview
The Reputation feature supports two modes (configured at the partner level):
* **With Private Direct Feedback**: Collect private feedback from all customers via email/SMS, then route satisfied customers to leave public Google reviews
* **Without Private Direct Feedback**: Send customers directly to Google Business Profile to leave public reviews
## How It Works
Send private feedback request via email/SMS to collect ratings and
comments.
Optionally send reminder if no response received.
Request satisfied customers to leave Google reviews with duplicate
prevention.
Optionally send reminder for Google review request if no review left after initial request.
Generate and send replies to customer reviews.
**Key Details:** - Feedback requests sent to all customers, including those
with existing Google reviews - Manual Google review linking available to
prevent duplicate Google review requests
Send Google review requests.
Send reminder if no response received.
Generate and send replies to customer reviews.
**Key Details:** - Duplicate prevention ensures customers never asked twice
* Manual Google review linking available to prevent future Google review
requests
## User Onboarding
Connect Google Business Profile account for review monitoring and direct
review links.
Link business locations to Google Business Profile locations.
Set up email/SMS for automated communications.
Add logo, colors, and brand name. Preview all communication requests
(feedback requests, follow-ups, review requests).
Enable the system to begin sending communications.
## Integration
Use IFrame with `feature: 'reputation'`. See [Embeddable
UI](/embeddable-ui/integration-overview) and [Initializing the
SDK](/embeddable-ui/iframe/embedding#initializing-the-sdk).
Share business location information for Google Business Profile mapping. See
[Data Sharing](/data-sharing/introduction).
Share customer identifiers and transaction data for automated
communications. See [Data Sharing](/data-sharing/introduction).
Configuration mode (with or without private direct feedback) is set at the partner
level. Contact the Reach team to configure this.
# Partner Configurations
Source: https://docs.embedreach.com/reputation/partner-configurations
Configuration requirements and options for partners implementing the Reputation feature.
## Overview
Two configuration modes available:
* **With Direct Feedback**: Collect private feedback first, then route satisfied customers to public Google reviews
* **Without Direct Feedback**: Send customers directly to Google reviews
## Configuration Modes
### With Direct Feedback
1. All customers receive private feedback request via email/SMS
2. Satisfied customers routed to leave Google reviews
3. Concerns captured privately
4. Duplicate prevention across all requests
### Without Direct Feedback
1. Customers receive direct Google review requests
2. Duplicate prevention ensures customers never asked twice
## Key Configuration Areas
### Customer Data Synchronization
* Share customer contact information (email addresses, phone numbers)
* Sync transaction and event completion data
* Maintain accurate customer opt-out preferences
### Request Triggers
* Automated sending based on customer events
* Built-in exclusions for specific transaction types
* **With Direct Feedback**: One feedback request per event, Google review requests only to satisfied customers without existing Google reviews
* **Without Direct Feedback**: One Google review request per customer with duplicate prevention
### Communication Channels
* Email and SMS delivery (configurable by partner)
* Respects marketing preferences and opt-outs
* Branded templates available
### Timing
* **With Direct Feedback**: Initial feedback request, follow-up reminder, then Google review requests to satisfied customers
* **Without Direct Feedback**: Initial review request, follow-up reminder
* All timing is fully configurable - you know your business best and can choose the optimal send times
## Integration Requirements
Partners must share:
* Customer identifiers and contact information
* Event/transaction completion data
* Location mapping information
* Customer communication preferences
Configuration mode is set at the partner level and applies to all tenants. Contact your Reach account representative to configure.
# Embed Example
Source: https://docs.embedreach.com/samples/embed
Full example of setting up the Reach SDK
## Implementation Example
Instead of including the complete implementation here, we've created a ready-to-use CodeSandbox template that you can fork and customize:
[Open Reach SDK Example in CodeSandbox](https://codesandbox.io/p/devbox/brave-andras-8jrg85)
### Getting Started
Once you open the CodeSandbox link, you'll need to update two configuration files:
1. **Client Configuration** (`src/config/reach-config.ts`):
```typescript theme={null}
export const reachConfig = {
// The user/business ID from your system
tenantExternalId: 'YOUR_TENANT_EXTERNAL_ID',
// Your unique vertical saas platform identifier provided by Reach
partnerId: 'YOUR_PARTNER_ID',
// The feature you want to use (e.g., "measure", "acquire")
feature: 'acquire',
// Set to true for additional console logging during development
debug: false,
};
```
2. **Server Configuration** (`server/config/server-config.js`):
```javascript theme={null}
module.exports = {
// Your Reach provided secret key for signing JWTs
jwtSecret: 'YOUR_JWT_SECRET',
};
```
### What's Included
The CodeSandbox example includes:
* A complete React implementation with the Reach SDK
* Token authentication handling
* Proper cleanup and disposal
* JWT token generation on the server
* Basic error handling for authentication
### Next Steps
After updating the configuration files, the Reach SDK will be fully functional in your demo environment. You can then:
1. Test the implementation
2. Copy the relevant code to your own project
3. Customize the UI or callback implementations as needed
# JSON Web Token (JWT) Example
Source: https://docs.embedreach.com/samples/jwt-tokens
Create a Reach compatible JWT on your backend
## Server-Side Implementation Example
Here's an example of a Node.js Express endpoint that generates the required JWT:
```javascript theme={null}
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
// JWT secret key - get this from Reach
const REACH_SHARED_JWT_SECRET = process.env.REACH_SHARED_JWT_SECRET;
// Middleware to ensure user is authenticated
const authenticateUser = (req, res, next) => {
// Implement your authentication logic here
req.user = {
id: 'user_123456789',
email: 'user@example.com',
name: 'Example User',
};
req.tenant = {
id: 'biz_987654321',
};
next();
};
// Reach authentication endpoint
app.get('/reach-authtoken', authenticateUser, (req, res) => {
try {
const now = Math.floor(Date.now() / 1000);
const payload = {
email: req.user.email,
name: req.user.name,
// Your ID for this user - a string, and the same on every token you mint for them
externalId: String(req.user.id),
// Your ID for the business this user belongs to
tenantExternalId: String(req.tenant.id),
partnerId:
'Your unique vertical saas platform identifier provided by Reach',
type: 'tenant',
iat: now,
exp: now + 3600, // 1 hour from now
};
const token = jwt.sign(payload, REACH_SHARED_JWT_SECRET, {
algorithm: 'HS256',
});
res.json({
success: true,
token: token,
});
} catch (error) {
console.error('Error generating token:', error);
res.status(500).json({
success: false,
error: 'Failed to generate token',
});
}
});
```
# Segments
Source: https://docs.embedreach.com/segments/segments
How tenant segments work: the customer-centric model, the full operator reference, and related-record conditions.
A **segment** is a saved question about a tenant's customers: *"which of this business's customers match these conditions right now?"* Segments are dynamic — customers automatically enter and leave as they meet or stop meeting the conditions — and they're what an [automation](/automations/introduction) uses to decide who receives a message.
The fields a segment can ask about come from the data you share. If you haven't yet, read [How Reach models your data](/data-sharing/data-model) to see how contacts, transactions, locations, and your custom schemas become segmentable.
**The customer-centric rule.** A segment always returns a list of **people**, never a list of things or events. A condition can *reach through* a customer's related records — their bookings, invoices, appointments, route stops — but the answer is always the customers those records belong to. There is no "60 days before a tournament" segment, because a tournament on its own is not a customer. If you can phrase your audience as *"a customer who satisfies these conditions right now,"* you can build it as a segment. The [Planning Engage Automations](/onboarding/planning/engage-automations#the-customer-centric-rule-and-how-to-reframe-a-business-event) guide walks through how to reframe a business event as a question about customers.
## Structure
A segment consists of:
* **Name** and **Description** — what it's called and what it's for.
* **Conditions** — the criteria that define membership (see below).
* **Status** — `active` or `deactivated`.
* **Tenant scope** — which of your tenants the segment applies to. A partner-defined segment can target a single tenant, a subset, or all of them.
Segments are almost always created in the **partner dashboard** — by you when you set up segments for your tenants, or by tenants themselves in the embedded segment builder (including the AI builder). The API is for reading and managing segments programmatically, not the usual way they're created. See the [Segments API reference](/api-reference/endpoint/get-api-segments) for the request and response shapes.
## What a condition can ask about
Each condition targets one **field**. Fields come from two places:
### Built-in customer fields
Available for every tenant out of the box:
* **Email**, **phone**, **first name**, **last name**, **user ID**
* Email and SMS opt-in / opt-out status
### Custom fields you expose
Any field from your schema definitions that you've exposed to segmentation becomes conditionable. You control this through the `fields_to_expose` configuration on your partner resource schema definitions — each exposed field carries a friendly **name**, a **description**, a **JSON path** into your data, and an **exposure** target. Only fields exposed to `segments` appear in the segment builder. See [Exposing fields to tenants](/data-sharing/custom-schemas) for how to configure them.
The friendly name and description you give an exposed field are what your tenants see in the builder — and they're also what the AI segment builder reads when a tenant describes an audience in plain language. Write them for a human.
## Operators
The operator you can use on a condition depends on the field's **type**. The type comes from the field's JSON Schema definition (`string`, `number`, `integer`, `boolean`, `array`, a `date` / `date-time` string, or a reference to another schema).
| Field type | Available operators |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| **Number / Integer** | `equals`, `not_equals`, `greater_than`, `less_than`, `in`, `exists`, `not_exists` |
| **String** | `equals`, `not_equals`, `contains`, `not_contains`, `in`, `exists`, `not_exists` |
| **Boolean** | `equals`, `not_equals`, `exists`, `not_exists` |
| **Date / DateTime** | `equals`, `not_equals`, `greater_than`, `less_than`, `exists`, `not_exists`, plus the date-window operators below |
| **Array** | `array_contains` |
| **Reference** (a field that points at another schema) | `equals`, `in`, `exists`, `not_exists` |
What each does:
| Operator | Meaning |
| ---------------------------- | ---------------------------------------------------------------------------------------- |
| `equals` / `not_equals` | Field is (or isn't) one of the supplied values. String comparisons are case-insensitive. |
| `greater_than` / `less_than` | Numeric or date comparison. |
| `in` | Field exactly matches one of a list of values. |
| `contains` / `not_contains` | Case-insensitive substring match (strings only). |
| `exists` / `not_exists` | The field is set / not set (a null or empty value counts as not set). |
| `array_contains` | An array field contains the given value. |
**Supplying multiple values behaves differently per operator.** `equals` and `contains` combine multiple values with **OR** (match any). But `greater_than` and `less_than` combine them with **AND** — so passing two values to `greater_than` means "greater than *both*," i.e. a lower bound of the larger value. Use this deliberately when you want a range.
### Date-window operators (Date / DateTime fields)
These are what make per-customer relative timing possible — "30 days before renewal," "birthday is today," "serviced within a window." A date field's value can be compared against:
* **A fixed date** using `greater_than` / `less_than` / `equals` (e.g. `service_date` is after `2026-01-01`).
* **A relative date** — N days before or after today — using `greater_than` / `less_than`. This is how you express "within the last 30 days" or "7 days from now." (Relative dates support only the `greater_than` / `less_than` and month/day operators; relative `equals` / `not_equals` isn't supported.)
* **`equals_month_day`** — matches the same month and day regardless of year (birthdays, anniversaries).
* **`equals_month_day_year`** — matches an exact month, day, and year.
* **`between_month_day`** — the field's month-and-day falls within a start–end window (handles windows that span a year boundary).
* **`between_month_day_year`** — the field falls within an absolute start–end date window.
### Related-record conditions (counts across a relationship)
The most powerful condition type reaches through a customer's related records and asks a **count** question about them. This is how you express "customers with 4 or more invoices" or "customers with a location that has no route stop scheduled this week."
A related-record condition specifies:
* **which related schema** to look at and the field on it that points back to the customer,
* a **count operator** (`eq`, `gt`, `gte`, `lt`, `lte`) and a **count value**, and
* optional **inner conditions** on the related records (AND-combined), using the same operators above.
Two common shapes:
* **"Has at least N …"** — count operator `gte` (or `gt 0` for "has any"). *"Customers who have at least 1 invoice paid more than 30 days ago."*
* **"Has zero …"** — count operator `eq 0` (or `lt 1`). *"Customers who have no cleaning scheduled in the future."* Combine an at-least condition with a has-zero condition to get an at-risk cohort — see the [pool-cleaning winback example](/onboarding/planning/engage-automations#a-working-example-end-to-end-a-pool-cleaning-winback).
Because the condition still evaluates per customer, the result is still a list of people — the related records only decide *which* people qualify.
## Condition structure
A simple field condition:
```json theme={null}
{
"field": "loyalty_tier",
"operator": "equals",
"value": ["gold"]
}
```
Conditions are grouped with `and` / `or` logic, and groups can nest. A related-record condition references the related schema and its own inner conditions:
```json theme={null}
{
"relatedResource": {
"schemaId": "{invoiceSchemaId}",
"foreignKeyPath": "customerId"
},
"countOperator": "gte",
"countValue": 4,
"conditions": [
{ "field": "status", "operator": "equals", "value": ["paid"] }
]
}
```
In practice, tenants build these in the segment builder UI rather than authoring JSON by hand — the shapes above are for understanding what the builder produces and what the API accepts.
## Usage in automations
Segments define who an automation targets. An automation can use a segment to:
1. **Include** users — the target audience for a communication.
2. **Exclude** users — people who should not receive it.
See [Automations](/automations/introduction) for how segments drive triggers and sends.