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.Operating rules
- Use
reach://docs/openapito 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:- Which Reach products and workflows will use the data?
- What source event represents a conversion or billable transaction?
- Is an isolated Reach sandbox partner account available, and which tenant is approved for validation?
- Is the integration real-time, scheduled batch, read-only database sync, or a hybrid?
- What historical period must eventually be backfilled?
- Which consent, lifecycle, and deletion states must remain synchronized?
- What URL opens a contact in the partner’s system, and which contact fields belong in that URL template?
- What URL opens a transaction in the partner’s system, and which transaction fields belong in that URL template?
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
Useexecute_reach_api to read:
GET /partner/tenantsand the intended validation tenantGET /partner/schema-definitionsGET /partner/schema-mappings- recent
GET /api/batchesfor the validation tenant when resuming an interrupted run - existing tenant resources or counts when the tenant may already contain data
4. Propose the Reach model
Model the source truthfully rather than reshaping it into a generic payload. Most onboarding models use these categories:contacts_schemafor the primary customer or contact identitytransactions_schemafor conversions, invoices, orders, bookings, or other billable eventslocations_schemafor business locationscustom_schemafor supporting entities that should remain queryable or referenced
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:
Customer(contacts_schema, no external schema dependencies)Order(transactions_schema, referencingreach:schemas/Customervia its customer foreign key)
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 withPOST /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.
- Read the current mapping with
GET /partner/schema-mappingsand capture the returnedetag. - Merge the approved changes locally while preserving every unrelated existing entry.
- 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).
- Obtain explicit approval for that exact replacement.
- Send the complete resulting mapping with
ifMatchset to the capturedetagunchanged. - Read it back and compare the persisted value with the approved value.
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 astest_<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:
- Send referenced parent records through the single-resource endpoint and read each one back by schema and external ID.
- Send one contact, location, transaction, and relevant custom record through that same endpoint in dependency order.
- Verify exact stored values with
GET /api/resources/{schemaDefinitionNameOrId}/{externalId}. - Exercise an approved PATCH when ongoing sync must update records. Remember that omitted fields are preserved while explicit
nullvalues remove optional fields. - Correct the model or payload when validation fails; do not weaken the schema with
ignoreUnknownFieldsunless 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. A202 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/countsfor the validation tenantGET /partner/resources/countsfor partner-wide counts grouped by tenant and schema
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