An API you can read in one screen.
Cursor pagination, idempotency keys, structured errors with a request id, and rate-limit headers on every response. The OpenAPI document is published ahead of the SDKs, because the specification is the part that matters.
- Auth · bearer key, per environment
curl https://api.zentrixquark.com/v1/customers \
-H "Authorization: Bearer zx_sk_sandbox_…" \
-G -d limit=2{
"data": [
{
"id": "cus_8f21c9",
"first_name": "Aarav",
"email_address": "aarav.menon@example.com",
"created_at": "2026-09-24T05:34:00Z"
},
{
"id": "cus_8f21d0",
"first_name": "Meera",
"email_address": "meera.rao@example.com",
"created_at": "2026-09-24T06:02:11Z"
}
],
"has_more": true,
"next_cursor": "cus_8f21d0"
}Quickstart
Six calls from a key to your own data.
Every example uses a sandbox key, so nothing here can touch production.
01
Create a sandbox key
Keys carry their environment in the prefix. A sandbox key can never read production data.
bash # Developer → API keys → Create key (environment: sandbox)export ZX_KEY="zx_sk_sandbox_…"02
Declare a connection
A connection cannot be saved until a test succeeds, so a broken credential is caught here rather than at 02:00.
bash curl -X POST https://api.zentrixquark.com/v1/connections \ -H "Authorization: Bearer $ZX_KEY" \ -d '{ "name": "postgres-sandbox", "type": "postgres", "environment": "sandbox", "config": { "host": "db.internal", "database": "app" } }'03
Create a flow
The flow definition is JSON. Export it, commit it, and review a mapping change as a diff.
bash curl -X POST https://api.zentrixquark.com/v1/flows \ -H "Authorization: Bearer $ZX_KEY" \ -d @customer-sync.json04
Dry run
Every stage executes; nothing is written to the destination. The response tells you what would have happened.
bash curl -X POST https://api.zentrixquark.com/v1/flows/flw_2a19/run \ -H "Authorization: Bearer $ZX_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"mode":"dry_run","limit":50}'05
Read the run
A run with any quarantined record is PARTIAL, never SUCCESS — and the reason codes are structured, so you can alert on them.
bash curl https://api.zentrixquark.com/v1/runs/run_8f21b7e0 \ -H "Authorization: Bearer $ZX_KEY" # → { "status": "partial",# "records": { "in": 50, "out": 48, "quarantined": 2 } }06
Read your data back
The generated endpoint serves the validated output of the flow, with cursor pagination and rate-limit headers.
bash curl "https://api.zentrixquark.com/v1/customers?limit=50" \ -H "Authorization: Bearer $ZX_KEY"
Conventions
The same contract on every resource.
- Base URL
- https://api.zentrixquark.com/v1
- Authentication
- Authorization: Bearer zx_sk_{live|sandbox}_…
- Pagination
- Cursor-based: ?limit=50&starting_after=cus_… → { data, has_more, next_cursor }
- Idempotency
- Idempotency-Key header on every POST; a replay returns the original result
- Rate limits
- X-RateLimit-Limit / -Remaining / -Reset on every response; 429 carries Retry-After
- Errors
- { "error": { "type", "code", "message", "param", "request_id" } }
- Versioning
- Major version in the URL; dated minor changes announced in the changelog
- Timestamps
- RFC 3339, always UTC, always with an explicit offset
Connections
| GET | /v1/connections | List connections in an environment |
| POST | /v1/connections | Create a connection |
| GET | /v1/connections/:id | Read one connection, with health and schema metadata |
| PATCH | /v1/connections/:id | Update configuration or owner |
| POST | /v1/connections/:id/test | Test connectivity and refresh the cached schema |
| DELETE | /v1/connections/:id | Delete a connection not referenced by a flow |
Flows
| GET | /v1/flows | List flows |
| POST | /v1/flows | Create a flow from a definition |
| GET | /v1/flows/:id | Read a flow and its current version |
| PATCH | /v1/flows/:id | Update the draft definition |
| GET | /v1/flows/:id/versions | List immutable versions |
| POST | /v1/flows/:id/deploy | Promote the draft to a new version |
| POST | /v1/flows/:id/run | Trigger a run (dry_run or live) |
Runs
| GET | /v1/runs | List runs, filtered by flow, status, environment or time |
| GET | /v1/runs/:id | Read one run with its record counts |
| GET | /v1/runs/:id/records | Per-record results, filterable to failures |
| POST | /v1/runs/:id/retry | Re-run the whole run, or only the failed records |
Webhooks
| GET | /v1/webhook_endpoints | List endpoints |
| POST | /v1/webhook_endpoints | Subscribe an endpoint to events |
| GET | /v1/webhook_deliveries | Delivery log with response codes and latency |
| POST | /v1/webhook_deliveries/:id/replay | Replay one delivery |
Platform
| GET | /v1/{flow_slug} | The generated read API for a flow output |
| GET | /v1/logs | Structured logs, filtered by flow, run, record or severity |
| GET | /v1/usage | Metered usage for the current period |
Errors
Every error names the thing that is wrong.
A type for branching, a machine-readable code, the offending parameter, and a request_id that appears in your logs and in ours.
{ "error": { "type": "validation_error", "code": "field_required", "message": "email_address is required by rule email_required", "param": "email_address", "request_id": "req_7c31a9" }}- authentication_error
- The key is missing, malformed, revoked, or scoped to another environment.
- permission_error
- The key or user lacks the role required for this action.
- validation_error
- The request or a record failed a declared rule; param names the field.
- rate_limit_error
- 429 with Retry-After; the response still carries the rate-limit headers.
- connection_error
- The upstream system was unreachable or rejected the credential.
- conflict_error
- A concurrent change; the response includes the current version.
Webhooks
Verify the signature before you trust the payload.
Zentrix-Signature carries a timestamp and an HMAC-SHA256 over t.body. Compare in constant time and reject anything outside the tolerance window.
import crypto from 'node:crypto'; export function verify(rawBody, header, secret, toleranceSec = 300) { const parts = Object.fromEntries( header.split(',').map((kv) => kv.split('=')), ); const age = Math.abs(Date.now() / 1000 - Number(parts.t)); if (age > toleranceSec) return false; const expected = crypto .createHmac('sha256', secret) .update(parts.t + '.' + rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(parts.v1), );}Event catalogue
- flow.run.succeeded
- A run completed with no quarantined or failed records.
- flow.run.partial
- A run completed with at least one quarantined record.
- flow.run.failed
- A run stopped before completing.
- record.quarantined
- A single record failed a rule with severity reject.
- connection.unhealthy
- A connection failed its health check or a run reported connection errors.
- connection.auth_required
- A credential expired or was revoked upstream.
- usage.limit_approaching
- A metered dimension crossed 80% of its plan limit.
Five attempts · exponential backoff · replay from the delivery log
SDKs
None of these exist yet.
The honest, high-value deliverable is the specification, not a wrapper around it. The OpenAPI 3.1 document is published first; the SDKs below are generated from it when they ship.
- TypeScript / NodePlanned
Generated from the OpenAPI document; first SDK planned.
- PythonPlanned
Generated from the same document, shipping alongside TypeScript.
- GoPlanned
After the first two, driven by demand.
- PHPPlanned
After the first two, driven by demand.
- CLI (zx)Planned
Flow export, import and CI validation. Roadmap only.
- Terraform providerPlanned
Connections and flows as infrastructure. Roadmap only.
Build log
What actually shipped, and when.
Zentrix has no customers to quote and no certifications to display. A dated record of what was built is the credibility an early-stage company can legitimately offer.
2026-09-26
- ADDEDFlow versioning with rollback by promotion; versions are immutable once deployed.
- ADDEDPer-record execution records, with source, transformed and destination payload references.
- CHANGEDA run containing any quarantined record is now reported as PARTIAL rather than SUCCESS.
2026-09-12
- ADDEDEnvironment scoping across connections, keys, webhook endpoints and runs.
- ADDEDCredential rotation with an overlap window so a rotation cannot fail a run.
- APIIdempotency-Key accepted on all POST endpoints.
2026-08-28
- ADDEDTyped field mapping with a transform function library and sample-record preview.
- ADDEDValidation rules with reject and warn severities and structured reason codes.
- FIXEDCursor persistence now happens only after a stage succeeds, so an interrupted run resumes.
2026-08-14
- ADDEDCursor-based incremental reads for REST and database sources.
- ADDEDDry-run mode that executes every stage without writing to a destination.
- APIPublished the first draft of the OpenAPI 3.1 document.