Deploy & Catch
Deploy — check for update
GET /api/deploy/check — SDK polls the engine for an OTA bundle update. Returns either `has_update: false` with a reason or full bundle metadata. Deterministic per-device rollout via stable hashing.
Every React Native app on Sankofa Deploy hits this endpoint at session start (and on resume, if checkOnResume: true) to check whether a new OTA bundle is available. The engine resolves the right bundle by joining the device's app version + platform + rollout bucket against the project's active releases.
For the surrounding lifecycle (notifyAppReady, downloadAndApply, auto-rollback), see Deploy product overview.
Authentication
Required header: x-api-key: sk_live_… or x-api-key: sk_test_…. See Authentication.
Request
GET with query-string parameters. No body.
app_versionstringRequireddistinct_idstringRequiredcurrent_bundle_labelstringplatformstringos_versionstringdevice_modelstringlocalestringThe engine also reads the request's IP for GeoIP-based country resolution — passed forward to telemetry but not used in routing today.
Example request
curl "https://api.sankofa.dev/api/deploy/check?app_version=1.2.0&distinct_id=device_abc&platform=ios&os_version=17.4" \
-H "x-api-key: sk_live_..."Response — no update available
{
"enabled": true,
"has_update": false,
"reason": "already_on_latest"
}The reason codes:
| Reason | Meaning |
|---|---|
no_matching_release | No active release for this app_version + platform. |
already_on_latest | The device's current_bundle_label matches the latest available release. |
not_in_rollout | A release exists but the device's stable bucket isn't in the rollout %. The device will get this release on a future check once rollout expands. |
global_pause | The release exists and the device is in the rollout, but the active schedule has paused it. |
below_floor | The device's app_version is below the minimum supported version for the latest release. |
Response — update available
{
"enabled": true,
"has_update": true,
"release_id": "rel_xyz789",
"label": "1.2.0-rc.1",
"download_url": "https://b2-bucket.s3.eu-west-1.amazonaws.com/deploy/proj_abc/rel_xyz789/ota.zip?X-Amz-Algorithm=...",
"sha256": "a8c2f...",
"size": 2048576,
"is_mandatory": false,
"force_apply": false,
"reason": "eligible"
}release_idstring (`rel_*`)labelstringdownload_urlstring (signed URL)sha256string (hex)sizenumberis_mandatorybooleanforce_applybooleanreasonstringRollout hashing
A device is in the rollout if:
hash(distinct_id + release_id) % 100 < release.rollout_percentageThe (distinct_id, release_id) tuple is the stable input — bumping release.rollout_percentage from 10 to 30 doesn't reshuffle the original 10%; the same devices stay in.
This is the same stable-hash pattern Switch uses for flag rollouts.
Kill-switch rollback path
If the device is currently on a release that's been disabled (via dashboard, halt webhook, or auto-rollback), the engine returns the next non-disabled release with force_apply: true and reason: "kill_switch_rollback". The SDK is expected to apply immediately, regardless of is_mandatory or checkOnResume.
Schedule-aware routing
If a release has an active DeployReleaseSchedule (a time-windowed rollout — e.g. "5% → 25% → 100% over 7 days"), the engine consults the schedule's current step before deciding whether the device qualifies. A paused schedule returns reason: "global_pause".
Country detection
Server-side GeoIP from the request IP populates a country code on the response telemetry. This is logged for analytics (per-country rollout breakdowns) but not used in routing — there's no per-country rollout gate today.
Response shape consistency with the unified handshake
The same response shape (the enabled + has_update + bundle metadata fields) is also returned inside modules.deploy of the unified handshake at GET /api/v1/handshake. SDKs that already call the handshake on session start can read the deploy decision from there without a separate request to /api/deploy/check.
For server-to-server custom integrations or deeply-customized SDKs, calling /api/deploy/check directly is the simpler path.