icdsbs.com · API v1 · last updated 10 August 2026
You send a claim before submitting it to the payer. We answer with everything that would get it rejected — an invalid or unspecified diagnosis, a procedure code that is not in the CHI SBS list, a duplicate line, a drug the Saudi formulary does not license for that diagnosis, a missed filing deadline.
The check runs against the full CHI SBS V3 procedure list, the Saudi drug formulary (40,952 drug-to-diagnosis rules) and the diagnosis reference. Typical response time is under half a second.
Base URL https://icdsbs.com/api/v1
Everything lives under /api/v1. When a breaking change is ever
needed it will appear at /api/v2 and v1 will keep working — we
will not change the meaning of an existing field underneath you.
Send your key in the X-API-Key header on every request.
# check that your key works — start here curl -H "X-API-Key: sk_live_your_key_here" \ https://icdsbs.com/api/v1/scrub/rules
A key carries scopes. Most integrations get all three:
| Scope | Allows |
|---|---|
scrub:run | Submitting claims to be checked |
scrub:read | Reading back batches, findings and reports |
rules:read | Reading the rule catalogue |
Send the same Claim resource you are about to submit to NPHIES.
We return a standard OperationOutcome.
POST /api/v1/scrub/fhir/Claim/$scrub
curl -X POST "https://icdsbs.com/api/v1/scrub/fhir/Claim/\$scrub" \ -H "X-API-Key: sk_live_your_key_here" \ -H "Content-Type: application/fhir+json" \ -d @claim.json
Accepts a Claim on its own, or a Bundle containing
the Claim plus Patient, Coverage and
Organization. References resolve from bundle entries or from
contained. What we read:
| FHIR element | Used for |
|---|---|
Claim.identifier[0].value | Your claim reference, echoed back |
Claim.billablePeriod.start or Claim.created | Encounter date — filing deadline checks |
Patient.birthDate, Patient.gender | Age and sex consistency checks |
Coverage.subscriberId | Completeness only. Hashed on arrival, never stored |
Claim.diagnosis[].diagnosisCodeableConcept | Diagnosis checks. Use system http://hl7.org/fhir/sid/icd-10-am |
Claim.item[].productOrService | Procedure or drug. The system decides which |
Claim.item[].diagnosisSequence | Which diagnosis justifies the line |
Claim.item[].net, unitPrice, quantity | Amount at risk |
A coding system containing medication, drug,
atc, rxnorm, ndc, sfda or
scientific marks the line as a drug; anything else is treated as
a procedure and checked against SBS.
{
"resourceType": "OperationOutcome",
"issue": [{
"severity": "error",
"code": "business-rule",
"details": {
"coding": [{ "system": "https://icdsbs.com/fhir/CodeSystem/scrub-rules",
"code": "RX002" }],
"text": "IBUPROFEN is not licensed in the formulary for N41.0."
},
"diagnostics": "Add the diagnosis that justifies it, or switch to a licensed alternative.",
"expression": ["Claim.item[0].productOrService"]
}],
"extension": [{
"url": "https://icdsbs.com/fhir/StructureDefinition/scrub-summary",
"extension": [
{ "url": "verdict", "valueCode": "would_reject" },
{ "url": "amountAtRisk", "valueMoney": { "value": 24.0, "currency": "SAR" } },
{ "url": "findingCount", "valueInteger": 1 }
]
}]
}
expression is the field to build your UI on.
It is a FHIRPath pointer to the element that failed, so you can highlight the
offending line instead of showing the user a paragraph of text.
Read extension → verdict for the headline without walking the
issue list. It is one of:
| verdict | Meaning | Suggested behaviour |
|---|---|---|
clean | Nothing found | Submit |
review | Something a coder should look at | Warn, allow submit |
would_reject | A payer edit will catch this | Block submission until fixed |
Send Accept-Language: ar and every message and suggestion comes
back in Arabic. The rule codes do not change.
Add "_mode": "clinical" at the top level of the payload when the
check runs while a doctor is prescribing. It suppresses the structural and
money rules — a prescription has no payer, no price and no filing deadline yet,
and reporting those to a clinician trains them to ignore the warning.
For systems that would rather not change their submission code, and for the initial audit of historical claims. Export one row per claim line, repeating the claim-level fields on each row.
curl -X POST https://icdsbs.com/api/v1/scrub/batch \ -H "X-API-Key: sk_live_your_key_here" \ -F "[email protected]" \ -F "label=July claims"
Column names do not have to match anything — they are recognised by alias, including Arabic headers. These are understood:
| Field | Recognised headers include |
|---|---|
| Claim reference | claim ref, claim no, invoice no, bill no, رقم المطالبة |
| Payer | payer, insurer, insurance company, TPA, شركة التأمين |
| Member | member id, card no, policy no, رقم العضوية |
| Encounter date | visit date, service date, invoice date, تاريخ الزيارة |
| Age / Sex | age, gender, sex, العمر, الجنس |
| Diagnoses | diagnosis, ICD codes — separate several with ; |
| Line type | line type, item type — drug, lab, radiology, procedure… |
| Code | service code, procedure code, SBS code, رمز الخدمة |
| Amounts | quantity, unit price, net amount, المبلغ |
| Outcome (optional) | claim status, denial reason — see below |
The response gives you a batch id and the headline figures. Then:
| Endpoint | Returns |
|---|---|
GET /scrub/batches | Your batches, newest first |
GET /scrub/batches/{id} | Summary, by rule and by payer |
GET /scrub/batches/{id}/claims | Every claim with its findings |
GET /scrub/batches/{id}/findings.csv | A coder's worklist |
GET /scrub/batches/{id}/report.html | A one-page audit report |
Maximum upload 64 MB. Larger files should be split; a submit-and-collect mode for very large batches is on the roadmap.
Fetch the live catalogue — it is the authoritative list, in English and Arabic:
curl -H "X-API-Key: …" https://icdsbs.com/api/v1/scrub/rules
| Prefix | Covers |
|---|---|
STR | Missing header fields, empty claims, zero-priced lines, future dates, missed filing windows |
DX | Missing, malformed, unknown, unspecified, ICD-10-CM-instead-of-AM, sex and age conflicts |
PX | Non-SBS format, codes absent from SBS V3, lines with no diagnosis link, duplicates, dental without a tooth |
RX | Unknown drug, drug not licensed for the diagnosis, non-claimable products, prescribing edits needing documentation |
Severity:
error a payer edit catches this mechanically · warning commonly rejected, a coder should look · information worth knowing, not a defect
If a rule does not apply to your payers, tell us and we will switch it off for your account alone. Nothing is tuned globally to suit one customer.
| Status | Meaning | What to do |
|---|---|---|
400 | The payload could not be read. FHIR calls get a fatal OperationOutcome, not a different error shape | Read issue[0].details.text |
401 | Missing, unknown, expired or revoked key | Check the header; ask us to reissue |
402 | Monthly claim allowance reached | Contact your account manager |
403 | The key lacks the scope for this call | Ask for a key with the right scopes |
404 | No such batch for your account | Check the id — batches are private to the account that created them |
429 | Too many requests | Honour Retry-After and back off |
| Requests per minute | 600 by default, per account |
| Monthly claims | Agreed per contract; 402 when reached |
| Upload size | 64 MB |
| Typical response | Under 500 ms for a single claim |
| We keep | We never keep |
|---|---|
| Diagnosis and procedure codes, quantities, amounts, payer, dates, age and sex | Patient names, phone numbers, addresses, national identifiers |
Membership numbers are hashed the moment they arrive — enough to count the same member twice within one file, never enough to identify anyone. Identifying columns found in an uploaded file are read past and discarded, and the response tells you which ones were dropped.
Your data is visible only to your own account. Another customer asking for your batch by id receives "not found".
| 1 | Key stored server-side, never in a browser or mobile app |
| 2 | Timeout set to 3–5 seconds, with the check skipped on failure |
| 3 | "Not checked" displayed differently from "no problems found" |
| 4 | Workflow keyed on verdict and rule codes, not message text |
| 5 | 429 handled with back-off |
| 6 | A sample of findings reviewed by your coding lead before enforcement |
| 7 | Agreed which rules, if any, are switched off for your payers |