Many systems.
One customer picture.
Bring trusted warehouse, CRM, billing and support data into Relasight automatically. Keep the source behind every observation, and turn the combined evidence into decisions.
A first Supabase backend and shared-workspace login are now live. This page describes the broader proposed contract; its .invalid examples do not transmit data. Read the live POC connection guide for the deployed endpoints, authentication and limits.
Connect through the pipeline you already operate
Start with an outbound push integration. A scheduled job inside your network reads an approved warehouse view, maps its columns, and sends changed records over HTTPS. Relasight does not need direct database credentials or inbound access to your warehouse. Any system that can emit the contract can contribute; vendor-specific connectors are not yet implemented.
Use a separate registered source for each independently versioned feed, for example warehouse-production, crm-production and support-production. If the warehouse already consolidates CRM data, choose one authoritative feed for those observations to avoid counting the same evidence twice.
A first successful sync
- An administrator provisions a workspace service token with the required permissions. Save it in your job's secret store.
- Register each source. Save the returned source ID in pipeline configuration.
- Send customer records first. Poll every batch until terminal, and reconcile each item before sending dependent observations.
- Send observations referencing that source's customer external ID. Link identities across systems using an approved crosswalk.
- Schedule incremental sync, check rejected rows, and verify the customer evidence and insight counts.
# Documentation only. This placeholder host does not resolve.
export RELASIGHT_BASE_URL="https://api.relasight.invalid/v1"
# Inject RELASIGHT_TOKEN from your secret store; never commit it.
curl --fail-with-body "$RELASIGHT_BASE_URL/sources" \
-H "Authorization: Bearer $RELASIGHT_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: register-warehouse-prod-v1" \
--data '{"name":"Warehouse production","kind":"warehouse"}'
# Replace source_id in the file with the returned ID.
curl --fail-with-body "$RELASIGHT_BASE_URL/ingestion/batches" \
-H "Authorization: Bearer $RELASIGHT_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: warehouse-run-20260912-batch-001" \
--data-binary @integration-batch.jsonCustomer and observation payload
This batch shows the two record types together. Production jobs should load customers and confirm success before their dependent observations. Items in one batch are processed in array order, but separate batches may finish out of order.
{
"source_id": "src_warehouse",
"items": [
{
"operation": "customer.upsert",
"external_id": "C-1042",
"source_version": 42,
"source_updated_at": "2026-09-12T10:00:00Z",
"customer": {
"name": "Cedar Works",
"type": "company",
"email": "hello@cedar.example",
"industry": "Professional services"
}
},
{
"operation": "observation.upsert",
"external_id": "contract-778-renewal",
"customer_external_id": "C-1042",
"source_version": 7,
"source_updated_at": "2026-09-12T10:00:00Z",
"observation": {
"attribute": "renewal_date",
"value": "2026-10-10",
"effective_at": "2026-09-12T09:00:00Z",
"confidence": "Verified",
"context": "Contract register, contract 778"
}
}
]
}One identity, many independent sources
A source record is keyed by (workspace, source_id, entity kind, external_id). External IDs must be stable, case-sensitive strings, never row numbers. Warehouse customer C-1042 and support organization org-882 remain separate until explicitly linked. Matching an email address or company name never automatically merges records.
Use your warehouse master customer key to build a reviewed crosswalk. Both source customers must exist before posting a link. Linking aliases preserves every source record, version and observation; it does not delete evidence. Repeating the same link returns the existing canonical customer. Contradictory identity operations return 409 for review. A future administrative unlink workflow must support audited correction; that endpoint is outside this draft.
{
"left": {
"source_id": "src_warehouse",
"external_id": "C-1042"
},
"right": {
"source_id": "src_support",
"external_id": "org-882"
},
"reason": "Approved warehouse-to-support identity crosswalk"
}
Keep source ownership visible
A customer upsert updates only that source's profile. It is a complete source profile: name and type are required; omitted optional fields clear that source's old optional values. A linked canonical profile uses an administrator's per-field source priority; an absent value falls back to the next source. Without configured priority, conflicting profile values require review. Cross-source arrival order never decides the winner.
Observations use stable event or fact IDs, such as contract-778-renewal. Higher source versions replace that source observation's current version while preserving its history. An observation's customer and attribute cannot be changed under the same external ID; retract it and create a new ID. Distinct events must receive distinct IDs. Retracting one source observation never retracts another source's evidence.
The proposed production resolver keeps effective time and ingestion time separate. It shows same-effective-time disagreements between sources and excludes disputed attributes from matching until resolved. Confidence is asserted by the source, not independently certified by Relasight. The current browser POC uses day-level dates; production timestamps retain UTC precision.
Warehouse mapping and incremental delivery
| Your field | API field | Rule |
|---|---|---|
| customer_key | external_id | Stable source business key, serialized as a string |
| customer_name / entity_type | customer.name / type | Company or person; no existing customer dimension required |
| change_sequence | source_version | Monotonically increasing positive integer per source entity |
| last_modified_utc | source_updated_at | Source modification timestamp, UTC |
| renewal_date | observation.value | YYYY-MM-DD, attribute renewal_date |
| fact_valid_from | observation.effective_at | When the fact became true, not when the sync ran |
The following is vendor-neutral pseudocode; adapt parameter binding, pagination and snapshot isolation to your warehouse. Do not use this as a literal connector implementation.
SELECT customer_key, customer_name, entity_type, email,
last_modified_utc, change_sequence
FROM approved_relasight_customer_view
WHERE (last_modified_utc > :last_time
OR (last_modified_utc = :last_time AND customer_key > :last_key))
AND last_modified_utc <= :run_upper_bound
ORDER BY last_modified_utc, customer_key;
For each bounded page:
map to API records; persist payload + idempotency key in a durable outbox
send batch; poll status; inspect every item result
retry transient failures with the identical key and payload
quarantine rejected records durably with their source keys and errors
checkpoint only after all items are applied, duplicate, stale,
or durably quarantined with an explicit repair/replay processUse a stable run upper bound and a tie-breaker key to avoid skipping rows sharing timestamps. Prefer a change log or CDC sequence when updates can arrive late or clocks can move backwards. For polling, replay a bounded overlap window using stable versions and perform periodic full reconciliation. Full snapshots must compare source keys explicitly; absence from a partial extract is never a delete.
Handle hard deletes using a change log/tombstone feed. customer.unlink removes only that source's alias from the active picture and excludes its contributions; history stays auditable. A linked customer with other sources remains. This is not a workspace-wide privacy erasure endpoint. Route full erasure to a separate authorized administrative process before production rollout.
For an initial load, create customer batches first, resolve errors, then load observations and cross-source links. For updates, coalesce versions for each entity and preserve stable source versions across retries. If a warehouse has only timestamps, persist your own per-entity sequence in the integration layer; do not derive versions from wall-clock time without collision handling.
Proposed endpoints
| Method & path | Permission | Response |
|---|---|---|
| POST /v1/sources | sources:write | 201 source ID |
| GET /v1/sources | sources:read | 200 items, next_cursor; default 50, maximum 100 |
| POST /v1/ingestion/batches | ingestion:write | 202 batch ID and relative status URL |
| GET /v1/ingestion/batches/{batch_id} | ingestion:read | 200 status and per-item results |
| POST /v1/identity-links | identity:write | 200 canonical customer ID and aliases |
Proposed defaults: UTF-8 JSON, at most 500 items and 1 MB uncompressed per batch, and 60 mutation requests per workspace per minute. These are design targets, not measured service limits. Source lists use an opaque cursor; follow next_cursor until null. Batches contain bounded results and do not paginate.
Operations and validation
customer.upsert: complete source profile; customer required.observation.upsert: observation and customer_external_id required; customer must already exist for this source. Renewal values must be valid ISO dates. Unknown attributes reject with unknown_attribute; schema extension requires explicit versioned registration in a future release.observation.retract: external_id identifies an existing source observation; higher source_version marks it retracted. Unknown identity rejects. No implicit restoration under an older version.customer.unlink: external_id identifies an existing source customer; higher source_version creates a source tombstone. Restoring requires a higher-version customer.upsert. Old observation revisions remain excluded until explicitly replayed at higher versions.
For all operations, timestamps use RFC 3339 UTC with a Z suffix. Positive versions increase per source entity, not per batch. Future-effective observations may be stored but do not enter today's picture. Unexpected fields, incompatible operation payloads, invalid dates and oversize values reject. No incoming field sets marketing consent or contact eligibility.
Reliable retries without duplicate facts
Every mutation requires an Idempotency-Key. The service scopes it to the workspace and route and stores the request digest and response for at least seven days. A retry with the same body returns the original result; reuse with a different body returns 409. After expiry, entity identity and source_version still prevent duplicate application.
Equal entity version and identical canonical payload returns duplicate. Equal version with different content returns version_conflict. A lower version returns stale without changing data. A higher version appends history and updates the source projection. Retrying rejected content with a corrected body requires a new batch key; if its version was never applied it can retain that entity version.
A 202 means queued, not imported. Poll with backoff until completed, completed_with_errors or failed. Results include zero-based input index, external_id, status and any error code/detail. Successful items are not rolled back when another item rejects. Treat a failed batch with incomplete results as uncertain: replay with the same key and reconcile; do not assume the whole batch was rolled back.
{
"id": "batch_123",
"status": "completed_with_errors",
"results": [
{
"index": 0,
"external_id": "C-1042",
"status": "applied",
"customer_id": "cust_901"
},
{
"index": 1,
"external_id": "contract-778-renewal",
"status": "rejected",
"code": "unknown_customer",
"detail": "The referenced source customer was not found."
}
]
}The result example illustrates partial success in a different batch with an unresolved reference. For transport failures or 5xx, retry the identical request with capped exponential backoff and jitter. On 429 honor Retry-After. Do not automatically retry 401/403, 409 or validation errors without correcting the cause. Store rejected rows, alert an owner, and make repair/replay visible in your pipeline dashboard.
Request-level errors use application/problem+json with type, title, status, detail and request_id. Envelope errors reject the batch before queuing; record-level errors appear in the batch result. Tokens, payload contents and personal data must not appear in operational error logs.
Access and deployment boundaries
Service tokens belong to one workspace and carry explicit permissions. Source-restricted tokens may write and read only their configured sources. Identity linking requires access to both sources and a separate privileged permission. The backend must enforce these checks on every resource, including batch polling; an inaccessible identifier returns 404. Client-supplied workspace IDs never select the authorization boundary.
Keep tokens in your server-side secret manager, rotate and revoke them, use TLS, and record actor/source/request ID in an audit log. An ingestion token should not grant customer-wide export access. Private-network warehouse jobs need outbound HTTPS only. The production service must define retention, erasure, encryption, tenant isolation and monitoring before accepting real data.
For the proposed Gold customer-managed deployment, run the same versioned contract inside the customer's network and configure a different base URL. A Silver private deployment remains a commercial option to evaluate. Neither hosting option nor a managed connector is implemented by this POC. These documentation examples do not transmit data. Signed-in workspaces store data in Supabase.
Acceptance checklist for the backend phase
- Provision tokens and prove workspace/source isolation with negative authorization tests.
- Import two sources, link a known crosswalk, and verify one canonical customer with separate evidence.
- Replay a batch, deliver older versions after newer ones, and demonstrate no duplicate or regressed facts.
- Exercise partial failures, rate limits, late arrivals, hard deletes, conflict review and repaired-row replay.
- Compare source counts and checksums with imported projections; establish freshness and rejection alerts.
- Verify source precedence, audit history, backups, restores and the separate privacy erasure process.
- Only then connect real customer data and add a server-side AI query layer over authorized evidence.
Standards used
The downloadable contract uses OpenAPI 3.1.1. Request-level errors follow RFC 9457 Problem Details. Relasight endpoint names, permissions, limits and sync semantics above are proposed product decisions, not claims about an existing service.