Skip to main content

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.
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.

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: 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: 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.