Step 1
Request a workspace
Tell us what you are building and expected volume on the partners page. We reply from partners@saharix.com with a workspace for your team.
Developers
Create partner workspaces, mint scoped keys, and drive escrow through your own product. Webhooks keep your system in sync, and Saharix keeps custody of every naira.
Step 1
Tell us what you are building and expected volume on the partners page. We reply from partners@saharix.com with a workspace for your team.
Step 2
Generate a sandbox key in your Saharix partner workspace. The secret is shown once; only a SHA-256 hash is stored server-side. Keys carry scopes: escrows:read, escrows:write, webhooks:read, webhooks:write.
Step 3
Send the key as a Bearer token. Escrows you create appear in your dashboard, and every money movement stays inside Saharix ledger controls.
Every request is made against your workspace base URL. Use the sandbox while you build and the production host once your integration is live.
Sandbox
https://api-staging.saharix.com
Test keys (sk_test_...) and simulated funding. No real money moves.
Production
https://api.saharix.com
Live keys (sk_live_...) move real funds under Saharix ledger controls.
curl https://api-staging.saharix.com/v1/partner/escrows \
-H "Authorization: Bearer sk_test_9f2c1a40.<secret>"Every request carries your key as a Bearer token. The key format is keyPrefix.secret. Keys are hashed at rest and can be revoked at any time from your workspace; a revoked key fails with 401.
curl https://api-staging.saharix.com/v1/partner/escrows \
-H "Authorization: Bearer sk_test_9f2c1a40.<secret>"Money-moving creates require an x-idempotency-key header. Replaying the same key with the same body returns the original response instead of a duplicate escrow; reusing a key with a different body returns 409 idempotency_key_conflict. Amounts are in minor units (kobo for NGN).
curl -X POST https://api-staging.saharix.com/v1/partner/escrows \
-H "Authorization: Bearer sk_test_9f2c1a40.<secret>" \
-H "Content-Type: application/json" \
-H "x-idempotency-key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
-d '{
"title": "Website redesign",
"buyer_email": "buyer@acme.com",
"seller_email": "freelancer@studio.com",
"amount": 45000000,
"currency": "NGN",
"inspection_period_days": 3
}'
# 201 Created
# { "status": "success", "data": {
# "id": "0b6f...", "status": "PENDING",
# "total_amount": "45000000", "currency": "NGN",
# "partner_ref": null, "created_at": "..." } }List your escrows with pagination, or fetch a single escrow with its milestones. Both require the escrows:read scope.
{ "status": "success", "data": {
"items": [
{ "id": "0b6f...", "status": "FUNDED", "title": "Website redesign",
"total_amount": "45000000", "currency": "NGN",
"partner_ref": null, "milestone_count": 1, "created_at": "..." }
],
"total": 1, "limit": 20, "offset": 0 } }
# GET /v1/partner/escrows/:id adds the milestone list to the escrowRegister an HTTPS endpoint and choose the events you want. The response includes a signing secret (whsec_...) shown once. Each delivery is a POST with X-Webhook-Timestamp and X-Webhook-Signature: sha256=..., where the signature is HMAC-SHA256 over ${timestamp}.${rawBody}.
curl -X POST https://api-staging.saharix.com/v1/partner/webhooks \
-H "Authorization: Bearer sk_test_9f2c1a40.<secret>" \
-H "x-idempotency-key: 1b4e28ba-2fa1-11d2-883f-0016d3cca427" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-app.com/hooks/saharix",
"events": ["escrow.funded", "escrow.completed"] }'
# 201 Created
# { "status": "success", "data": {
# "id": "e2c1...", "url": "https://your-app.com/hooks/saharix",
# "events": ["escrow.funded", "escrow.completed"],
# "is_active": true, "secret": "whsec_..." } }const expected = crypto
.createHmac("sha256", webhookSecret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
const received = (req.headers["x-webhook-signature"] || "").replace("sha256=", "");
if (!crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(received, "hex"))) {
throw new Error("Invalid webhook signature");
}{ "event": "escrow.funded",
"created_at": "2026-10-02T12:00:00.000Z",
"data": { "escrow_id": "0b6f...", "partner_ref": null,
"status": "FUNDED", "title": "Website redesign",
"amount": 45000000, "currency": "NGN",
"milestone_id": null } }Failed deliveries retry up to 5 times with backoff (1m, 5m, 15m, 60m, 4h). Endpoints must be public HTTPS addresses; private, loopback, and link-local hosts are rejected. List endpoints with GET /v1/partner/webhooks and disable one with DELETE /v1/partner/webhooks/:id.
Errors use one envelope, with a stable machine-readable code:
{ "status": "error",
"code": "validation_error",
"message": "Invalid request data",
"details": [] }401 means a missing, malformed, or revoked key. 403 means the key lacks the scope for that endpoint. 404 means the escrow does not belong to your workspace. Throttled and abusive traffic can receive 429; retry after a short pause.
Request a workspace and we will set you up with sandbox keys, guidance, and a direct line to the team.