Credit Scoring

POST/v1/credit/scoresPOST/v1/credit/scores/batches

Get a credit score for a DRC citizen, computed from verified alternative and financial data — mobile money, telecom, banking and utility payment histories — linked to their RDCPASS identity. Each score comes with a risk band, a 12-month probability of default and the factors that drove it, so you can make fast, explainable lending decisions for customers with or without a banking history.

Every score requires the citizen’s explicit consent

RDCPASS never scores a citizen without their approval. Each request must carry a valid consent obtained from that citizen — through a consent request they approve in the RDCPASS app, or through Login with RDCPASS with the rdcpass:credit.score scope. A missing, expired, revoked or mismatched consent returns 403 consent_required, and nothing is computed or billed.

At a glance

SinglePOST /v1/credit/scores
BatchPOST /v1/credit/scores/batches — up to 50 items synchronously, 10,000 asynchronously
ConsentMandatory, per citizen — consent.method rdcpass_app
Score300 – 850, bands A to E, with probability_of_default
Identity dataaccount and kyc.basic only — additional KYC scopes never apply
Purposecredit_assessment
Webhookcredit_score.completed (asynchronous calls)
ProductionEnhanced due diligence — see Going to production

Obtaining consent

Consent is given by the citizen, on their own device, after seeing exactly who is asking and why. There are two ways to obtain it; both produce a consent identifier prefixed cns_ that you pass in consent.consent_id.

MethodHow it works
RDCPASS app consent requestYour application sends a consent request to the citizen. They receive it in the RDCPASS app, which shows your organization’s name, the product and the amount, and approve it with face confirmation. The approved request gives you the consent_id.
Login with RDCPASSInclude rdcpass:credit.score in the scope of your authorization request. The citizen approves it on the RDCPASS consent screen together with the other scopes, and the rdcpass:credit.consent claim returns method, consent_id and expires_at. See Login with RDCPASS.

In both cases the citizen approves inside the RDCPASS app, so consent.method is always rdcpass_app.

Consent rules

  • A consent is bound to one citizen and one application. It cannot be reused for another identifier or shared between applications.
  • It is valid for 30 days from approval (expires_at) and can be used for new scores during that period — for example to re-score before disbursement.
  • The citizen can revoke it at any time from the RDCPASS app. Revocation takes effect immediately; subsequent requests return consent_required.
  • Scores already delivered remain valid until their own valid_until, but you may only use them for the credit decision the citizen consented to.
403 consent_required
HTTP/1.1 403 Forbidden

{
  "error": "consent_required",
  "message": "Consent cns_5e8a2d71c4 has expired. Ask the citizen to approve a new consent request."
}

Request

The plaintext body below is encrypted and signed before it is sent, as described in Authentication. Every POST also accepts the optional Idempotency-Key header (24-hour window) and Prefer: respond-async.

FieldTypeRequiredDescription
identifierobjectYesThe citizen to score.
identifier.typestring enumYesrdcpass_id (recommended), passport, ceni, driving_licence or national_id.
identifier.valuestringYesThe identifier value, e.g. COD-2103-0214-4937.
consentobjectYesThe citizen’s consent for this score.
consent.methodstring enumYesrdcpass_app.
consent.consent_idstringYesThe consent identifier, prefixed cns_.
purposestring enumYesMust be credit_assessment, approved for your application.
productstring enumYesThe credit product being assessed — see Product types below.
amount_requestedobjectNoOptional { "value", "currency" } — the amount applied for, in CDF or USD. Improves the relevance of the probability of default.
referencestringNoYour own identifier for this application, echoed back in the response and webhooks.
Request body (plaintext, before encryption)
{
  "identifier": {
    "type": "rdcpass_id",
    "value": "COD-2103-0214-4937"
  },
  "consent": {
    "method": "rdcpass_app",
    "consent_id": "cns_5e8a2d71c4"
  },
  "purpose": "credit_assessment",
  "product": "microcredit",
  "amount_requested": { "value": 1500000, "currency": "CDF" },
  "reference": "loan-2026-0917"
}

Response

A successful call returns 200 OK with a credit_score object.

FieldTypeDescription
idstringUnique identifier, prefixed crs_.
objectstringAlways credit_score.
livemodebooleantrue in production, false in the sandbox.
referencestring | nullThe reference you sent, or null.
statusstring enumAlways completed for a synchronous call. Asynchronous and batch items can be failed.
identifierobjectThe identifier you submitted.
consentobjectThe consent used: method, consent_id, granted_at, expires_at.
productstringThe product you declared.
amount_requestedobject | nullThe amount you declared, or null.
scoreintegerCredit score from 300 (highest risk) to 850 (lowest risk).
bandstring enumA to E — see Score bands below.
probability_of_defaultnumberEstimated probability, from 0 to 1, that the citizen defaults on a credit obligation within the next 12 months.
factorsobject[]The factors that most influenced the score, ordered by weight: code, impact (positive | negative), weight (0 – 1) and a human-readable description.
data_sourcesstring[]The data sources that contributed to this score.
valid_untilstring (RFC 3339)Until when the score may be relied on for a credit decision — 30 days after computation. Request a new score after this date.
accountobjectThe citizen’s RDCPASS account: rdcpass_id, status, certified, created_at, level_of_assurance.
kyc.basicobjectBasic KYC: full_name, first_name, last_name, date_of_birth, age, gender, nationality.
purposestringThe purpose you declared.
created_atstring (RFC 3339)When the score was computed.

Credit Scoring returns basic KYC only. Additional KYC scopes never apply to this service — use KYC Validation if your onboarding needs addresses, documents or other scoped data.

Score bands

Bands group scores into risk levels. Probability-of-default ranges are indicative, based on observed 12-month default rates across the RDCPASS scored population; always rely on the probability_of_default returned for the individual citizen.

BandScore rangeRisk levelIndicative 12-month default rate
A750 – 850Very low< 2 %
B670 – 749Low2 – 5 %
C580 – 669Moderate5 – 12 %
D500 – 579High12 – 25 %
E300 – 499Very high> 25 %

Factors

Each factor explains part of the score. Use them to give applicants the principal reasons for a decision and to guide them on how to improve their score.

codeWhat it measures
payment_historyTimeliness of repayments on loans, mobile credit and instalment plans.
mobile_money_activityRegularity and volume of mobile money inflows and outflows.
credit_utilizationShare of available credit currently in use.
income_stabilityStability of recurring income over time.
account_ageAge of the citizen’s financial and mobile money accounts.
telecom_tenureLength of use of the citizen’s primary phone number.
utility_paymentsPunctuality of electricity, water and other utility payments.
recent_inquiriesNumber of recent credit applications.

Data sources

data_sourcesOrigin
mobile_moneyMobile money operators — wallet activity, transfers and repayments.
telecomMobile network operators — tenure, top-up and airtime-credit behaviour.
bankingBanks and microfinance institutions — accounts, loans and repayments.
utilitiesUtility providers — electricity and water billing and payment history.

data_sources lists only the sources that contributed data for this citizen. A score built on fewer sources is still valid; its factors show what it is based on.

Product types

productDescription
personal_loanUnsecured personal loan.
microcreditMicrocredit, including group and micro-enterprise loans.
mobile_creditShort-term credit or overdraft on a mobile money wallet or airtime.
mortgageHome loan secured on real estate.
bnplBuy now, pay later — instalment purchase at a merchant.
otherAny other credit product.

Full response

200 OK (after decryption)
{
  "id": "crs_5a9e2c7b14",
  "object": "credit_score",
  "livemode": true,
  "reference": "loan-2026-0917",
  "status": "completed",
  "identifier": { "type": "rdcpass_id", "value": "COD-2103-0214-4937" },
  "consent": {
    "method": "rdcpass_app",
    "consent_id": "cns_5e8a2d71c4",
    "granted_at": "2026-09-26T10:12:40Z",
    "expires_at": "2026-10-26T10:12:40Z"
  },
  "product": "microcredit",
  "amount_requested": { "value": 1500000, "currency": "CDF" },
  "score": 712,
  "band": "B",
  "probability_of_default": 0.034,
  "factors": [
    {
      "code": "payment_history",
      "impact": "positive",
      "weight": 0.35,
      "description": "Mobile credit and loan instalments repaid on time over the last 24 months."
    },
    {
      "code": "mobile_money_activity",
      "impact": "positive",
      "weight": 0.25,
      "description": "Regular monthly inflows on the primary mobile money wallet."
    },
    {
      "code": "credit_utilization",
      "impact": "negative",
      "weight": 0.15,
      "description": "Outstanding balances use 68 % of available credit lines."
    },
    {
      "code": "telecom_tenure",
      "impact": "positive",
      "weight": 0.1,
      "description": "Same primary phone number for more than 6 years."
    },
    {
      "code": "utility_payments",
      "impact": "positive",
      "weight": 0.08,
      "description": "Electricity and water bills settled without arrears."
    },
    {
      "code": "recent_inquiries",
      "impact": "negative",
      "weight": 0.07,
      "description": "3 credit applications in the last 90 days."
    }
  ],
  "data_sources": ["mobile_money", "telecom", "banking", "utilities"],
  "valid_until": "2026-10-26T10:15:02Z",
  "account": {
    "rdcpass_id": "COD-2103-0214-4937",
    "status": "active",
    "certified": true,
    "created_at": "2025-03-14T09:22:41Z",
    "level_of_assurance": "LOA3"
  },
  "kyc": {
    "basic": {
      "full_name": "Kabeya Mwamba Tshisekedi",
      "first_name": "Kabeya",
      "last_name": "Tshisekedi",
      "date_of_birth": "1988-04-12",
      "age": 38,
      "gender": "male",
      "nationality": "COD"
    }
  },
  "purpose": "credit_assessment",
  "created_at": "2026-09-26T10:15:02Z"
}

Example request

The header values are illustrative placeholders — see Authentication for how to compute a real X-RDCPASS-Signature and encrypt the body. Each sample handles consent_required.

credit-score.sh
# Plaintext body shown — it is AES-256-GCM encrypted (IV in X-RDCPASS-IV) and signed per /docs/authentication before sending.
curl https://api.rdcpass.cd/v1/credit/scores \
  -X POST \
  -H "X-RDCPASS-Key-Id: key_live_8f2a1c0e9b" \
  -H "X-RDCPASS-Timestamp: 1735689600" \
  -H "X-RDCPASS-Nonce: 2d7b4e91-6c3a-4f08-b5e2-8a1f0c9d3e67" \
  -H "X-RDCPASS-Signature: 8c1d4f...b62e" \
  -H "X-RDCPASS-IV: mX4p9Qz2Lr8sT1vB" \
  -H "Idempotency-Key: e4a9c2f7-1b3d-4e6a-9f05-7c2b8d1e0a53" \
  -H "Content-Type: application/json" \
  -d '{
    "identifier": { "type": "rdcpass_id", "value": "COD-2103-0214-4937" },
    "consent": { "method": "rdcpass_app", "consent_id": "cns_5e8a2d71c4" },
    "purpose": "credit_assessment",
    "product": "microcredit",
    "amount_requested": { "value": 1500000, "currency": "CDF" },
    "reference": "loan-2026-0917"
  }'

Responsible lending

A score informs a credit decision; it does not make it. Combine it with your own affordability assessment, tell applicants the principal reasons for an adverse decision (the factors are designed for this), never use a score for anything other than the credit decision the citizen consented to, and do not store scores beyond your documented retention period. Your lending practices must comply with the regulations of the Banque Centrale du Congo applicable to your institution.

Request modes

Credit Scoring supports all four request modes. See Single, batch & async for polling, pagination and cancellation.

Synchronous (default)Asynchronous (Prefer: respond-async)
Single200 with the credit_score object202 with a job; result via credit_score.completed or GET /v1/jobs/{job_id}
Batch200 with every result — up to 50 items202 with a batch — up to 10,000 items; results via webhook or GET /v1/batches/{batch_id}/results

Batch: pre-approval campaigns

Score a list of customers at once — for example to pre-approve mobile credit limits for wallet holders who opted in. Each item must carry its own valid consent: a batch never bypasses consent, and items without one fail individually with consent_required while the rest succeed. purpose and product set at batch level apply to every item unless the item overrides them.

cURL
curl https://api.rdcpass.cd/v1/credit/scores/batches \
  -X POST \
  -H "X-RDCPASS-Key-Id: key_live_8f2a1c0e9b" \
  -H "X-RDCPASS-Timestamp: 1735689600" \
  -H "X-RDCPASS-Nonce: 2d7b4e91-6c3a-4f08-b5e2-8a1f0c9d3e67" \
  -H "X-RDCPASS-Signature: 8c1d4f...b62e" \
  -H "X-RDCPASS-IV: mX4p9Qz2Lr8sT1vB" \
  -H "Idempotency-Key: e4a9c2f7-1b3d-4e6a-9f05-7c2b8d1e0a53" \
  -H "Prefer: respond-async" \
  -H "Content-Type: application/json" \
  -d @preapproval-campaign.json   # plaintext shown; encrypt per /docs/authentication before sending
preapproval-campaign.json (plaintext, before encryption)
{
  "purpose": "credit_assessment",
  "product": "mobile_credit",
  "items": [
    {
      "reference": "camp-0917-00001",
      "identifier": { "type": "rdcpass_id", "value": "COD-2103-0214-4937" },
      "consent": { "method": "rdcpass_app", "consent_id": "cns_5e8a2d71c4" },
      "amount_requested": { "value": 100, "currency": "USD" }
    },
    {
      "reference": "camp-0917-00002",
      "identifier": { "type": "rdcpass_id", "value": "COD-1907-5530-1186" },
      "consent": { "method": "rdcpass_app", "consent_id": "cns_91c3b7e0a2" },
      "amount_requested": { "value": 250, "currency": "USD" }
    },
    {
      "reference": "camp-0917-00003",
      "identifier": { "type": "rdcpass_id", "value": "COD-1512-8841-0273" },
      "consent": { "method": "rdcpass_app", "consent_id": "cns_0d4f6a8b17" }
    }
  ]
}
Response
HTTP/1.1 202 Accepted

{
  "id": "bat_7c2e91f04a",
  "object": "batch",
  "service": "credit_scoring",
  "status": "pending",
  "total_items": 3,
  "processed_items": 0,
  "succeeded_items": 0,
  "failed_items": 0,
  "created_at": "2026-09-26T10:15:00Z",
  "completed_at": null,
  "results_url": "/v1/batches/bat_7c2e91f04a/results"
}
GET /v1/batches/bat_7c2e91f04a/results (abridged)
{
  "object": "list",
  "data": [
    {
      "reference": "camp-0917-00001",
      "status": "succeeded",
      "result": {
        "id": "crs_5a9e2c7b14",
        "object": "credit_score",
        "score": 712,
        "band": "B",
        "probability_of_default": 0.034,
        "valid_until": "2026-10-26T10:15:02Z",
        "...": "..."
      }
    },
    {
      "reference": "camp-0917-00002",
      "status": "succeeded",
      "result": {
        "id": "crs_b82f1d6e03",
        "object": "credit_score",
        "score": 598,
        "band": "C",
        "probability_of_default": 0.091,
        "valid_until": "2026-10-26T10:15:03Z",
        "...": "..."
      }
    },
    {
      "reference": "camp-0917-00003",
      "status": "failed",
      "error": {
        "code": "consent_required",
        "message": "Consent cns_0d4f6a8b17 was revoked by the citizen."
      }
    }
  ],
  "next_cursor": null
}

Synchronous batches over 50 items return 413 batch_too_large. Asynchronous batches accept up to 10,000 items; you receive batch.completed or batch.completed_with_errors when processing ends. Each succeeded item is billed individually; items rejected for consent_required are not billed.

Asynchronous scoring

Send Prefer: respond-async with a single request to get a job back immediately. When the score is ready, RDCPASS delivers a credit_score.completed event to your webhook URL; its data is the completed job, with the same object a synchronous call returns embedded in result. You can also poll GET /v1/jobs/{job_id}.

Response
HTTP/1.1 202 Accepted

{
  "id": "job_9e3c5a1f7d",
  "object": "job",
  "service": "credit_scoring",
  "status": "pending",
  "created_at": "2026-09-26T10:15:00Z",
  "result_url": "/v1/jobs/job_9e3c5a1f7d"
}
Webhook event: credit_score.completed
{
  "id": "evt_5d1a8f3c7e2b9a40",
  "object": "event",
  "type": "credit_score.completed",
  "livemode": true,
  "created_at": "2026-09-26T10:15:03Z",
  "data": {
    "object": {
      "id": "job_9e3c5a1f7d",
      "object": "job",
      "service": "credit_scoring",
      "status": "completed",
      "created_at": "2026-09-26T10:15:00Z",
      "result_url": "/v1/jobs/job_9e3c5a1f7d",
      "result": {
        "id": "crs_5a9e2c7b14",
        "reference": "loan-2026-0917",
        "object": "credit_score",
        "status": "completed",
        "score": 712,
        "band": "B",
        "probability_of_default": 0.034,
        "...": "..."
      }
    }
  }
}

Verify the webhook signature before trusting the payload — see Webhooks.

Errors

Errors use the standard format described in Errors. Codes specific to this service:

CodeHTTPWhen
invalid_identifier400identifier.value does not match the format of identifier.type, or no certified RDCPASS account exists for it.
unsupported_identifier_type400The identifier type is not accepted by this service (for example a business identifier).
insufficient_balance402Prepaid wallet balance is exhausted.
credit_limit_reached402Postpaid usage has reached your credit limit.
consent_required403Consent missing, expired, revoked, or issued for another citizen or application.
purpose_not_approved403purpose is not credit_assessment, or it is not approved for this application.
service_not_enabled403Credit Scoring is not enabled on this application.
production_access_required403A production key was used before the application passed enhanced due diligence.
job_not_found404The job ID does not exist for this application.
batch_not_found404The batch ID does not exist for this application.
batch_too_large413More than 50 items in a synchronous batch.
quota_exceeded429Your plan’s quota for the period is exhausted.
rate_limited429Too many requests — retry after the indicated delay.

Next steps

Questions about your integration? Contact developer support