Sync ingest API
The endpoint the gateway calls to push ECG records to the cloud
This endpoint is the only API surface the gateway needs. It's authenticated by license key (not JWT), so the gateway never holds a user session.
Request
POST /v1/sync/ingest
Host: api.offinhealthcare.com
X-License-Key: ECG-A1B2C3D4...
X-Gateway-Fingerprint: 7f3a9b2e...
Content-Type: application/json
{
"records": [
{
"file_hash": "sha256:9c3a…",
"patient_mrn": "12345",
"recorded_at": "2026-04-26T08:14:33Z",
"device": "GE_MAC_5500",
"format": "xml",
"leads": 12,
"duration_s": 10,
"measurements": { "hr": 78, "pr": 156, "qrs": 92, "qt": 380 },
"raw_payload": "<base64-encoded-original-file>"
}
]
}
Response
{
"success": true,
"data": {
"accepted": [{ "file_hash": "sha256:9c3a…", "id": "uuid-…" }],
"duplicate": [],
"rejected": []
}
}
| Field | When it appears |
|---|---|
accepted |
New record stored. Use the returned id for follow-up reads. |
duplicate |
Same file_hash already in DB. Returns the existing id. Safe to mark synced. |
rejected |
Validation failed (reason field included). Don't retry these — they'll fail again. |
Headers the cloud may set on the response
X-License-Status: ok/bound_to_other_device/subscription_past_dueX-Subscription-Status: trialing/activeX-Plan-Slug: basic
The gateway should log these and surface to the local dashboard so the facility admin sees the cause without combing logs.
Errors
| HTTP | Meaning |
|---|---|
| 401 | Missing / malformed X-License-Key |
| 402 | Subscription past due — pay outstanding invoice |
| 403 | Key revoked, suspended, or bound to another device |
| 413 | Batch too large — split into ≤ 50 records |
| 429 | Rate limited — back off per Retry-After header |
| 503 | Cloud temporarily unavailable — back off and retry |