Raktify Developer API
Public REST webhook contract for blood-bank software vendors to sync donor and donation records into Raktify, India's district-wide blood-response platform.
Everything you need, in one place
Overview
Raktify is a not-for-profit blood-response platform built by Choudhari EduHealth India Foundation. It runs the matching pipeline between hospitals with urgent blood requests, blood banks holding tested inventory, and voluntary donors in the surrounding district.
Blood banks already run software — Safetrans (Strides), e-RaktKosh, BLIS, RAKT, or homegrown Excel/Access systems. Asking a technician to also type each donor and donation into Raktify is friction that will kill adoption. Instead we publish a single webhook contract: your software pushes an event, our platform mirrors it. Direction is vendor → Raktify (push) — you don't need to open any inbound ports or expose credentials.
Who this is for
- BB software vendors (Safetrans/Strides, e-RaktKosh, BLIS, RAKT, and any homegrown system) who want their hospital clients to appear in Raktify's matching pool without dual data entry.
- Hospital IT teams maintaining in-house BB software; you can implement the client yourself in ~1 day.
- Standards-based tools — we publish an OpenAPI 3.0 spec. Any language that can HTTP + HMAC-SHA256 can integrate.
Quickstart
- Request a partner key for each hospital installation you integrate.
- Every donor registration your operator completes: POST to
/webhooks/v1/donor-registration. - Every donation event (draw + TTI screening result): POST to
/webhooks/v1/donation. - Sign each request body with your partner key's HMAC-SHA256 secret; carry
X-Raktify-Partner-KeyandX-Raktify-Signatureheaders. - Include a
vendor_event_idin every payload. Retries with the same ID are safe (idempotent).
Authentication
HMAC-SHA256 request signing
Every request MUST carry two headers:
| Header | Value |
|---|---|
X-Raktify-Partner-Key | Your pk_... identifier — one per hospital installation. |
X-Raktify-Signature | sha256=<hex> — HMAC-SHA256 over the raw request body, keyed by your partner secret. |
Content-Type | application/json |
Signing example (Node)
const crypto = require('crypto');
const body = JSON.stringify(payload);
const signature = crypto
.createHmac('sha256', PARTNER_SECRET)
.update(body)
.digest('hex');
fetch('https://raktify-api.azurewebsites.net/webhooks/v1/donor-registration', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Raktify-Partner-Key': 'pk_your_key_here',
'X-Raktify-Signature': 'sha256=' + signature,
},
body,
});
Signing example (Python)
import hmac, hashlib, json, requests
body = json.dumps(payload).encode('utf-8')
sig = hmac.new(PARTNER_SECRET.encode('utf-8'), body, hashlib.sha256).hexdigest()
requests.post(
'https://raktify-api.azurewebsites.net/webhooks/v1/donor-registration',
data=body,
headers={
'Content-Type': 'application/json',
'X-Raktify-Partner-Key': 'pk_your_key_here',
'X-Raktify-Signature': 'sha256=' + sig,
},
)
Getting a partner key
Partner keys are for blood-bank software vendors only. This is a one-way push API for software that runs at a hospital or blood bank, and keys are not issued to individual developers or students. It has no endpoints to search donors, check availability or contact a donor; we do not expose donor data to third-party applications.
Partner keys are issued per hospital installation. If your software serves five hospitals, you get five distinct keys — that way we can revoke a single hospital's key without affecting the others.
To request a key, contact contact@choudhari.ngo with:
- Vendor / company name
- Hospital(s) currently using your software that want Raktify integration
- Technical contact for the integration engineer
We reply with the partner_key and the HMAC secret (revealed exactly once — save it into your credentials store immediately). Self-service issuance via an admin panel is on the roadmap.
Endpoints
Base URL: https://raktify-api.azurewebsites.net
All request and response bodies are JSON. Successful writes return 202 Accepted (the row is stored and the consent flow is enqueued asynchronously).
POST /webhooks/v1/donor-registration
Upsert a donor by mobile. A donor pushed for the first time is stored with consent_pending — we send them a WhatsApp with a magic link to accept on Raktify's own consent screen (DPDP §7). Matching and alerts don't reach unconsented donors.
Request body
| Field | Type | Required? | Notes |
|---|---|---|---|
vendor_event_id | string | Required | Your side's event ID; used for idempotency. Max 255 chars. |
event_time | ISO 8601 datetime | Required | When the operator completed the registration in your software. |
mobile | string | Required | Indian mobile, +91 prefix or 10-digit; we normalize. |
full_name | string | Required | 2–200 chars. Encrypted at rest. |
date_of_birth | YYYY-MM-DD | Required | Donor must be 18–65 (DB constraint). |
gender | enum | Required | M / F / O |
blood_group | string | Optional | A+, A-, B+, B-, AB+, AB-, O+, O-. Trusts your BB's attestation. |
pincode | string | Optional | Indian 6-digit. |
village_id | integer | Optional | LGD code — if you have it. Preferred over pincode. |
address_line | string | Optional | Encrypted at rest. |
abha_id | string(17) | Optional | ABHA ID if captured. |
aadhaar_last4 | string(4) | Optional | Never full Aadhaar. |
preferred_language | enum | Optional | mr / hi / en. Default mr. |
consent_captured_at | ISO 8601 datetime | Optional | Timestamp your software captured the donor's "share with Raktify" tick. Belt-and-braces — the primary consent is always captured on Raktify's own /consent screen. |
Response — 202 Accepted
{
"raktify_donor_id": "6fda231f-9e7e-4a1d-8761-87e15f83d1ee",
"action": "created", // "created" | "updated_pending" | "updated_consented"
"is_new": true,
"consent_status": "pending" // "pending" | "active"
}
Error responses
| Code | Body | Meaning |
|---|---|---|
| 401 | {"error":"signature_mismatch"} | HMAC did not verify. Check secret + body-bytes. |
| 401 | {"error":"unknown_partner_key"} | Partner key not recognized. |
| 403 | {"error":"partner_key_revoked"} | Key exists but is inactive. |
| 422 | {"error":"invalid_input", "details":{...}} | Zod validation error; details pinpoints the offending field. |
| 422 | {"error":"invalid_mobile"} | Not an Indian mobile. |
POST /webhooks/v1/donation
Record a donation event. The donor MUST already exist on Raktify — push /donor-registration first for a new donor and retry.
Request body
| Field | Type | Required? | Notes |
|---|---|---|---|
vendor_event_id | string | Required | Your side's event ID. |
event_time | ISO 8601 datetime | Required | When the operator recorded the donation. |
donor_mobile | string | Required | The join key back to the donor (same as the earlier registration). |
collection_date | YYYY-MM-DD | Required | Must not be in the future (DB constraint). |
component_code | string | Required | Matches Raktify's blood_components.code — WB, PRBC, FFP, PLT, CRYO. Case-insensitive. |
volume_ml | integer | Required | 1–1000. |
isbt_barcode | string | Required | Bag barcode. Must be unique across Raktify. |
hb_gdl | number | Optional | Donor Hb at draw (g/dL). |
Response — 202 Accepted
{
"raktify_donor_id": "6fda231f-9e7e-4a1d-8761-87e15f83d1ee",
"raktify_donation_id": "4ab05951-f222-4e14-9993-4ea38372b777",
"action": "created"
}
Error responses
| Code | Body | Meaning |
|---|---|---|
| 409 | {"error":"donor_not_found"} | Donor with that mobile hasn't been pushed yet. Retry after /donor-registration. |
| 422 | {"error":"unknown_component"} | component_code doesn't match blood_components.code. |
| 422 | {"error":"invalid_input"} | Field-level Zod error. |
Reliability
Idempotency
Every request MUST include vendor_event_id. If your delivery layer retries after a network blip, retries with the same (partner_key, vendor_event_id) pair return the original result cached from the first attempt — the same raktify_donor_id, the same status. This lets you use at-least-once delivery semantics safely.
Idempotency records are retained for 30 days. Beyond that, a repeat of an old vendor_event_id is treated as a fresh request.
Rate limits
Currently 100 requests / IP / minute globally. Your partner key isn't rate-limited separately — the global limit is generous enough for any normal BB workflow (a busy blood bank processes ~50 donations per day). If you need higher throughput for a batch backfill, contact us to arrange a temporary uplift.
Responses on rate-limit: 429 with {"error":"rate_limit_global"} and a Retry-After header. Back off + retry.
Error reference
| HTTP | Error code | Action |
|---|---|---|
| 202 | (success) | Row stored (or idempotent replay). |
| 401 | missing_partner_key, missing_signature, signature_mismatch, unknown_partner_key, invalid_partner_key_format | Fix auth headers. |
| 403 | partner_key_revoked | Contact us for a new key. |
| 409 | donor_not_found | Push /donor-registration first. |
| 422 | invalid_input, invalid_mobile, unknown_component | Fix payload; do NOT retry with same body. |
| 429 | rate_limit_global | Honor Retry-After, then retry. |
| 500 | internal_error | Transient — retry with backoff. |
Consent flow — what happens after your push
India's Digital Personal Data Protection Act (DPDP §7) requires explicit donor consent before we process their PII for platform purposes. Your push tells us the donor exists at a specific blood bank; consent is captured separately on Raktify's own screen.
- Your push lands. Donor row is created with
consent_data_use=falseandconsent_pending_since=NOW(). - Raktify sends the donor a WhatsApp (approved Meta template
donor_consent_invite) with a magic link tohttps://raktify.choudhari.ngo/consent/<token>. - The donor sees Raktify's own consent screen — what data we hold, what we'll do with it, their DPDP rights — and taps Accept, Decline, or defers.
- Accept:
consent_data_useflips to true; the donor becomes visible to matching for compatible requests in their district. - Decline: we run the donor-erasure scrub (mobile tombstoned, name and address wiped) within seconds.
- No response in 14 days: the same scrub runs automatically. We don't retain PII we have no lawful basis to process.
consent_captured_at as an audit signal. But Raktify's own consent step is the authoritative capture. Your push starts a conversation; the donor closes it on our side.
Interactive API browser
Browse the full OpenAPI 3.0 spec below — expand any endpoint to see the schema, examples, and error responses. Requests you fire from here hit the live production API; without a valid X-Raktify-Partner-Key + HMAC signature they'll return 401 signature_mismatch (that's the correct auth response). For real end-to-end testing use the Postman collection — it auto-signs with your partner secret.
Downloads & tooling
All artifacts for the vendor push webhook. Machine-readable and human-readable in one place.
/api/vendor-webhook-v1.yaml— OpenAPI 3.0.3, single source of truth. Import into openapi-generator, Insomnia, Postman./api/vendor-webhook-v1.postman_collection.json— Postman v2.1 collection with an HMAC-SHA256 pre-request script; import, setpartner_key+partner_secret, hit Send./developers.md— Markdown version of this whole page. Feed it to Claude / ChatGPT / any AI coding assistant as context and ask it to write the client for you in any language.
The spec is versioned in the URL (/webhooks/v1/). Adding an optional field is not a version bump; changing semantics, removing, or renaming fields would be v2 and would run alongside v1.
Contact + support
- Get a partner key / start integration (blood-bank software vendors only): contact@choudhari.ngo
- Report a bug or ask a question: same address — reply time is typically same day IST business hours.
- About the platform: How Raktify works · Home
- Legal: Terms · Privacy · Data deletion