> ## Documentation Index
> Fetch the complete documentation index at: https://docs.embedreach.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Developer MCP Data Onboarding

> A safe, resumable workflow for designing schemas, installing mappings, and validating source records with the Reach Developer MCP

## What this workflow does

Use this workflow with the Reach Developer MCP to turn a partner's existing source model into reviewed Reach schema definitions and partner schema mappings, then validate the integration with a small set of records. The workflow is resumable: always inspect Reach before proposing or applying changes, rather than assuming a previous run completed.

The MCP is an onboarding and validation surface. Use the Reach API directly for production synchronization and historical backfills.

<Warning>
  We strongly recommend doing initial onboarding writes against an isolated Reach sandbox partner account
  and a dedicated sandbox tenant. A test tenant under a production partner is not isolated: schema
  definitions and mappings affect every tenant owned by that partner, validation records can trigger
  audiences, automations, attribution, review flows, reporting, or billing, and the MCP cannot delete
  them. If the developer chooses to continue in production, explain these risks and obtain their explicit
  approval before writing.
</Warning>

## Operating rules

* Use `reach://docs/openapi` to discover available operations, then read the selected operation's detail resource before calling it. The OpenAPI resource is authoritative for request and response shapes.
* Read existing schemas and mappings before proposing changes. A resumed run must reconcile the desired state with what is already present.
* Recommend an isolated sandbox partner account and dedicated sandbox tenant before writing. Do not infer isolation from a tenant name or test-tenant flag. If the authenticated partner is production, explain the partner-wide configuration and test-record risks and obtain explicit approval to proceed.
* Stop for explicit human approval after presenting the proposed model and again before a full schema-mapping replacement when the approved mapping changed.
* Never ask the developer to paste database credentials, API keys, connection strings, or production records into the MCP conversation.
* Do not send a production backfill or production-scale batch through `execute_reach_write`. MCP writes are capped at 100 batch records and a 100 KB JSON body.

## 1. Establish the integration goal

Ask for the information needed to judge the model:

1. Which Reach products and workflows will use the data?
2. What source event represents a conversion or billable transaction?
3. Is an isolated Reach sandbox partner account available, and which tenant is approved for validation?
4. Is the integration real-time, scheduled batch, read-only database sync, or a hybrid?
5. What historical period must eventually be backfilled?
6. Which consent, lifecycle, and deletion states must remain synchronized?
7. What URL opens a contact in the partner's system, and which contact fields belong in that URL template?
8. What URL opens a transaction in the partner's system, and which transaction fields belong in that URL template?

Record unresolved choices. Do not invent business semantics from column names alone.

For Engage, ask the developer for concrete examples of the audience segmentation their users want. Phrase them as business questions, such as “customers with an appointment in the next 30 days” or “customers who have not purchased in six months.” For each question, identify the source entity, relationship to the contact, status and date semantics, and fields needed to answer it. Use this inventory to decide which contact attributes and related source models must be sent to Reach; do not limit discovery to the contact table when the desired segments depend on bookings, visits, orders, invoices, or other related records.

## 2. Inspect the source model safely

Start with artifacts already available to the developer's agent: ORM models, migrations, schema dumps, API types, and representative redacted payloads. Identify likely contact, transaction, location, and supporting records; their keys; and their relationships.

If live database inspection would materially improve the model, explain the exact metadata needed and ask for permission to use the agent client's database tooling. Request read-only, least-privilege access through that tooling—not through the Reach MCP. Default to catalog metadata and aggregate queries. Read raw rows only when the developer explicitly approves it, limit the result, and avoid copying sensitive values into chat or Reach.

For each source entity, capture:

* table or model name and business meaning
* tenant boundary and stable unique key
* foreign keys and cardinality
* required versus nullable fields
* timestamp semantics and timezone
* monetary unit and currency
* lifecycle, cancellation, and soft-delete states
* communication consent fields and their polarity
* the contact or transaction click-through URL template and every field used by it, if that record has a page in the partner's system

## 3. Inventory Reach

Use `execute_reach_api` to read:

* `GET /partner/tenants` and the intended validation tenant
* `GET /partner/schema-definitions`
* `GET /partner/schema-mappings`
* recent `GET /api/batches` for the validation tenant when resuming an interrupted run
* existing tenant resources or counts when the tenant may already contain data

Compare existing objects by immutable ID and case-insensitive schema name. Never blindly retry a create after a timeout or ambiguous response; read the collection first and continue from the observed state.

The tenant inventory proves ownership, not partner isolation. Ask whether the authenticated partner is a sandbox account. If it is production, explain the risks in the warning above and obtain explicit approval before continuing to writes.

## 4. Propose the Reach model

Model the source truthfully rather than reshaping it into a generic payload. Most onboarding models use these categories:

* `contacts_schema` for the primary customer or contact identity
* `transactions_schema` for conversions, invoices, orders, bookings, or other billable events
* `locations_schema` for business locations
* `custom_schema` for supporting entities that should remain queryable or referenced

Every schema needs an immutable, stable `externalIdField` (use canonical camelCase `externalIdField` and `pluralName`, never deprecated snake\_case variants). Schema `name` and `pluralName` must match `/^[a-zA-Z0-9_-]+$/` (letters, numbers, hyphens, and underscores only; no spaces). Include all fields required for approved product behavior, but expose only useful, well-described fields through `fieldsToExpose`. Mark PII fields with the supported `x-pii-type` annotations.

Do not place the reserved contact identity fields (`email`, `phone`, `firstName`, `lastName`) in `fieldsToExpose`; the API rejects those names. `fullName` and `externalId` are valid field names, but core identity fields are normally mapped through `contactsSchema` in schema mappings rather than exposed as custom segment fields.

Represent relationships with `reach:schemas/<SchemaName>` `$ref` fields. Build a dependency graph and create referenced schemas before schemas that depend on them. For example, if an `Order` references a `Customer`, the creation order is:

1. `Customer` (contacts\_schema, no external schema dependencies)
2. `Order` (transactions\_schema, referencing `reach:schemas/Customer` via its customer foreign key)

Transactions and related custom records should connect to the contact identity used by the mapping when the source relationship exists. In your proposal, explicitly list the planned schema creation sequence so the reviewer can verify dependency ordering upfront.

Present a review artifact before writing anything. It must include:

| Item                  | Required detail                                                                           |
| --------------------- | ----------------------------------------------------------------------------------------- |
| Source-to-Reach model | Source entity, Reach schema name, category, and purpose                                   |
| Identity              | External ID field, uniqueness evidence, and tenant scope                                  |
| Relationships         | Source foreign key, target schema, cardinality, and upload dependency                     |
| Canonical mappings    | Product-required contact, transaction, location, URL, consent, and event fields           |
| Exposure              | Segment and merge fields, display name, and URL patterns                                  |
| Sync behavior         | Create/update triggers, cancellation and deletion handling, backfill plan, and retry keys |
| Open questions        | Any semantic choice that still needs a human answer                                       |

Obtain explicit approval for this artifact before calling `execute_reach_write`.

## 5. Create or update schema definitions

Read the OpenAPI detail for the schema operation, then create missing definitions with `POST /partner/schema-definitions` in dependency order. Update an existing definition with `POST /partner/schema-definitions/{schemaIdOrName}` only after comparing it with the approved shape.

After every write, read the schema back by ID or name and verify its name, category, external ID field, JSON Schema, references, exposed fields, and version. Schema updates can take up to three minutes to take effect. If a resource write behaves as though the old schema is active, read the definition again and retry validation after that window instead of changing the payload to match stale behavior.

## 6. Install the complete schema mapping

`POST /partner/schema-mappings` replaces the partner's complete mapping configuration. It is not a partial merge.

Use the selected products and approved workflows to determine which mapping sections are required:

| Product    | Required partner schema mappings                                                                                                                                                                                                     |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Measure    | `contactsSchema.primarySource` plus at least one `transactionsSchema` entry. Map contact identity and the transaction ID, contact reference, event type, amount, currency, and applicable dates used for attribution and ROAS.       |
| Acquire    | `contactsSchema.primarySource` plus at least one `transactionsSchema` entry with the same identity, value, currency, and date fields required for conversion measurement and ad optimization. Attribution tracking is also required. |
| Engage     | `contactsSchema.primarySource`, including the addressable channel, name, and consent fields. Add transaction, custom, or location mappings only when the approved segments, automations, personalization, or reporting use them.     |
| Reputation | `contactsSchema.primarySource`, at least one `locationsSchema` entry, and the transaction or custom interaction mapping that identifies the completed event which triggers a review request.                                         |
| AI Voice   | `contactsSchema.primarySource` when synced caller identity or customer context is in scope. Add transaction or custom mappings only when the approved call experience or lookup tools need those related records.                    |

For every contact source and transaction entry, ask for the URL template that opens that record in the partner's application. Add it as `urlPattern`, using placeholders for fields present in that schema, and include those fields in the schema definition. If the partner has no click-through page for that record, record that explicitly and omit `urlPattern`; never invent a route.

1. Read the current mapping with `GET /partner/schema-mappings` and capture the returned `etag`.
2. Merge the approved changes locally while preserving every unrelated existing entry.
3. Show a complete before-and-after diff formatted clearly into three sections:
   * **Preserved**: List of existing mapped schemas and sections kept untouched.
   * **Added/Updated**: Exact JSON delta being introduced or modified.
   * **Removed**: Any mappings or fields being dropped (explicitly state "None" if nothing is removed).
4. Obtain explicit approval for that exact replacement.
5. Send the complete resulting mapping with `ifMatch` set to the captured `etag` unchanged.
6. Read it back and compare the persisted value with the approved value.

An HTTP `412` means the mapping changed after it was read. Do not retry the old replacement. Read the current mapping and its new `etag`, recompute and show the complete diff, obtain approval again, and submit the revised replacement with the new `ifMatch` value.

Treat an HTTP `409` as a signal to inspect active schema lookup tools or invalid mapped fields. Do not bypass or erase unrelated mappings to make the write pass.

## 7. Validate small synthetic records

Use a consistent namespaced synthetic external ID pattern, such as `test_<timestamp>_<entity>_<index>` (e.g., `test_20260908_contact_1`), so every probe is easily identifiable and isolated. Do not use real customer PII. Send only the minimum records needed to exercise required fields, mapped fields, and each relationship.

Maintain an inventory of all synthetic external IDs created during the session. Present this inventory to the developer at the end of validation so they have an exact audit trail of all test resources written to the tenant.

Test every schema through the synchronous single-resource endpoint first: `POST /api/resources/{schemaDefinitionNameOrId}` with one `{ "data": ... }` object. Do not use the batch endpoint until each required schema and reference has passed this single-record validation and the stored resource has been read back successfully.

For the approved validation tenant:

1. Send referenced parent records through the single-resource endpoint and read each one back by schema and external ID.
2. Send one contact, location, transaction, and relevant custom record through that same endpoint in dependency order.
3. Verify exact stored values with `GET /api/resources/{schemaDefinitionNameOrId}/{externalId}`.
4. Exercise an approved PATCH when ongoing sync must update records. Remember that omitted fields are preserved while explicit `null` values remove optional fields.
5. Correct the model or payload when validation fails; do not weaken the schema with `ignoreUnknownFields` unless dropping those fields is intentional and approved.

## 8. Then exercise and debug the batch path

After synchronous validation succeeds for every required schema, submit one small batch per schema. A `202` response means the batch was accepted, not that its records succeeded. Capture every `batchId` and poll `GET /api/batches/{batchId}` until its status is `success`, `partial_success`, or `failure`.

Use bounded backoff—for example 2, 4, 8, then 15 seconds between reads—and keep reporting progress. After an agreed deadline, report that processing is still underway and preserve the batch ID so the run can resume. Do not resubmit a batch merely because it is still `processing`.

For `partial_success` or `failure`, inspect `errors.summary`, `errors.details`, and record errors. Retry only corrected failed records with the same external IDs; successful records are already durable upserts.

By default, a missing `$ref` dependency is rejected because `dependencyWaitTimeout` is `0`. Prefer sending and verifying parent records first. When intentionally testing out-of-order delivery, set a positive timeout of at most 86,400 seconds and read batch status with `includePendingDetails=true` to see each missing dependency. There are no ordering guarantees across batches. Batch PATCH preserves the order of multiple patches for the same resource within one batch.

## 9. Reconcile what Reach stored

Use exact resource reads as the primary validation. Then compare source aggregate counts with:

* `GET /api/resources/counts` for the validation tenant
* `GET /partner/resources/counts` for partner-wide counts grouped by tenant and schema

These endpoints count raw partner resources only. They do **not** prove that denormalized contact, billable-event, or location rows were materialized correctly. Denormalized-resource validation is outside this workflow.

Explain expected count differences, including pre-existing tenant data, failed or pending batch rows, filters, and deliberately omitted records. Never claim alignment without stating the source query, Reach scope, schema, and time boundary used for the comparison.

## 10. Hand off the production integration

Produce a credential-free onboarding manifest in the developer's repository or ticket. Include:

* approved schema names, IDs, versions, categories, and source owners
* the complete approved schema mapping
* partner account and validation tenant, synthetic external IDs, batch IDs, and terminal results
* exact source aggregate queries or reconciliation definitions
* real-time and batch triggers, upsert keys, dependency order, and retry behavior
* historical backfill scope and direct-API implementation plan
* unresolved decisions and operational monitoring owners

Do not include credentials or sample PII. Before declaring onboarding complete, confirm all schema and mapping reads match the approved state, every required validation record is readable, every test batch reached an understood terminal state, and raw resource counts reconcile within explained differences.

After sandbox validation, schemas and mappings must be created again in the production partner account; there is no automatic promotion between accounts. Connect the MCP to production, read and diff its current definitions and mappings, use the sandbox-approved design as a proposal, and obtain new explicit approval before writing the production configuration.

Prefer validating synthetic resources in the sandbox account. If production-only validation is necessary, explain that those records can trigger product behavior and cannot be deleted through the MCP, then send only minimal namespaced records after explicit approval.
