API Docs
OpenAPI

Lending API

Underwrite on your own book and run the loan on MyItura's rails. Push a credit decision, we produce the offer letter, take the borrower through checkout, collect on a mandate and settle your revenue.

What the API does

The API is for the parts a machine should do unattended: pushing decisions, reading loan state and recording collections. Two things are deliberately not here. Defining loan products sets the pricing every loan inherits, and funding your capital pool moves real money, so both are signed-in actions on your dashboard rather than calls an API key can make.

The shape of an integration

  • Your credit engine approves a borrower and pushes the decision to POST /v1/preapprovals.
  • We price the loan against your product, freeze an immutable pricing snapshot and render the offer letter.
  • The borrower completes hosted checkout: phone OTP, KYC, bank details, direct debit mandate, guarantors.
  • Funds leave your ring-fenced capital pool. A pool can never be overdrawn.
  • We collect on the mandate, or you record your own collections against the loan.
  • Settlement statements sweep your accrued fee and interest to your organisation wallet.

Permissions

Every route requires the Loan Tenant permission on your organisation. Pre-approval routes additionally require Pre-Approved Lending. MyItura enables both when your tenant is onboarded; a key without them gets 403.

Base URL
Productionhttps://api.myitura.com
Sandboxhttps://api.myitura.com (test-mode keys)
Versionv1 // in the path, never a header

Authentication

Authenticate with the key pair issued to your organisation. Send them as two headers, or fold them into one Authorization header. Both forms are equivalent; pick whichever your HTTP client handles better.

HeaderValue
X-API-Public-KeyYour public key. Safe to log.
X-API-Secret-KeyYour secret key. Server side only, never in a browser or a mobile app.
AuthorizationAlternative single header: ApiKey <public>:<secret>

Live and test keys

Keys carry their mode in the prefix. A pk_test_ pair reaches the sandbox, where KYC accepts magic values and no real money moves. Test keys are refused by the live stack and live keys are refused by the sandbox, so a misrouted key fails loudly instead of quietly transacting.

Where your keys live

Generate and rotate keys under Api Key in your organisation dashboard. Secrets are shown once at creation. If a secret is lost, rotate it rather than asking us to recover it.

curl https://api.myitura.com/v1/loans \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."

# or, as a single header
curl https://api.myitura.com/v1/loans \
  -H "Authorization: ApiKey pk_live_7dc2a1...:sk_live_9f4b83..."

Money and idempotency

Every amount is kobo

Money crosses the wire as an integer number of kobo, the minor unit of the naira. A field named approvedAmountKobo holding 45000000 is NGN 450,000.00. Kobo is what we store, post to the ledger and compute against, so it is the only value that is ever authoritative.

Some responses mirror a naira float alongside for display, such as balanceNaira. Read it, do not compute with it, and never send one back.

Idempotency

Send an Idempotency-Key header on every POST. Replaying the same key returns the original outcome instead of creating a second record, which makes a timeout safe to retry. Reusing a key across a different method or path returns 409.

POST /v1/preapprovals carries a second, stronger guarantee: it is idempotent on decision.metadata.assessment_id regardless of the header, so the same assessment can never become two pre-approvals.

Pagination

List endpoints take page and limit and return a meta block. The default limit is 20 and the ceiling is 100.

Response envelope
{
  "status": 200,
  "success": true,
  "message": "Loans retrieved",
  "data": [],
  "meta": { "total": 184, "page": 1, "limit": 20, "hasNext": true }
}

Errors and rate limits

Errors use the same envelope as successes, with success: false and a machine-readable error. Read the status code first and the error string second; message is for your logs and your support team, not for parsing.

StatusMeaningWhat to do
400Malformed body or an unparseable field.Fix and resend. Retrying unchanged will not help.
401Missing, unknown or revoked key pair.Check the header names and the key mode.
403Your organisation lacks Loan Tenant or Pre-Approved Lending, or the tenant switch for this feature is off.Talk to us. No amount of retrying clears it.
404The record does not exist, or belongs to another tenant.We answer 404 rather than 403 across tenants so ids cannot be probed.
409The loan is not in a state that allows this transition.Re-read the loan and act on its current status.
422Well-formed but invalid, such as a rate above your tenant cap.error names the offending field.
429Rate limited.Back off and honour Retry-After.

Rate limits

Limits are per API key, counted in a rolling window, and every authenticated call is metered into the usage feed you can read at GET /v1/usage. Burst headroom is generous for reads and tighter for writes. If you are planning a bulk push, tell us first and we will raise the ceiling rather than watch you get throttled.

{
  "status": 422,
  "success": false,
  "message": "Interest rate exceeds the cap on your tenant configuration",
  "error": "interest_rate_bps_above_tenant_cap"
}

Download the spec

The machine-readable contract for this page is an OpenAPI 3.0.3 document you can import into Postman, Insomnia, Bruno or a generator. It is a static file on this site, so it needs no key and no login.

/api-docs/lending-v1.json

The file matches this page exactly

The spec is generated from the same source as the reference you are reading, filtered to the public surface. If an operation is documented here it is in the file, and if it is not here it is not in the file. Nothing else on our platform is described by it.

In the file

The partner API a lending tenant calls with a key pair.

  • Providers, products
  • Pre-approvals and offers
  • Loan lifecycle and schedules
  • Mandates and repayments
  • Payouts, settlements, usage
  • Webhook endpoints and the event log
  • Sandbox helpers

Not in the file

Surfaces that are not yours to call.

  • Your dashboard's own routes, which use your login rather than a key
  • MyItura's internal operations routes
  • The hosted borrower checkout
  • Direct loan and borrower origination
Not the same thing as our Swagger

MyItura's full platform Swagger is not published. It is unreachable in production and behind HTTP basic auth everywhere else. This file is a separate, deliberately narrow artefact: only the endpoints on this page, only the schemas they reference.

Import into Postman
curl -O https://myitura.com/api-docs/lending-v1.json

# Postman: Import > File > lending-v1.json
# then set the collection variables
# publicKey and secretKey
GET/v1/products

List loan products

curl https://api.myitura.com/v1/products \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Products retrieved",
  "data": [
    {
      "approvalMode": "tenant",
      "capitalPoolCode": "string",
      "code": "LFC-IKJ",
      "createdAt": "2026-09-03T14:22:08Z",
      "currency": "NGN",
      "description": "Working capital for elective procedures",
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "insuranceMode": "automatic",
      "insurancePremiumBearer": "borrower",
      "insurancePremiumBps": 500,
      "interestModel": "flat",
      "interestRateBps": 500,
      "isActive": true,
      "kycTier": "delegated",
      "lateFeeBps": 500,
      "maxAmountKobo": 45000000,
      "maxTenorDays": 1,
      "minAmountKobo": 45000000,
      "minTenorDays": 1,
      "name": "Lifecenter Diagnostics, Ikeja",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "processingFeeBps": 500,
      "processingFeeFlatKobo": 45000000,
      "recoveryEnabled": true,
      "recoveryPolicyId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "settlementCatalogEnabled": true,
      "settlementDestination": "borrower_wallet",
      "updatedAt": "2026-09-03T14:22:08Z"
    }
  ]
}
GET/v1/products/{id}

Get a loan product

Path

ParameterDescription
idrequiredpath · string (uuid)Loan product id.

Response

FieldDescription
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
capitalPoolCodestringFunding pool this product draws from.
codestringUnique per organisation.
createdAtstring (date-time)
currencystring
descriptionstring
idstring (uuid)
insuranceModeInsuranceModeLoan-insurance behaviour for the product.
automaticmanualoff
insurancePremiumBearerInsurancePremiumBearerWho pays the insurance premium.
borrowertenant
insurancePremiumBpsintegerInsurance premium as basis points of principal.
interestModelInterestModelInterest calculation method.
flatreducing_balance
interestRateBpsintegerAnnual nominal interest rate in basis points (pro-rated by tenor at pricing time).
isActiveboolean
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
lateFeeBpsinteger
maxAmountKobointegerAmount in kobo (NGN minor unit).
maxTenorDaysinteger
minAmountKobointegerAmount in kobo (NGN minor unit).
minTenorDaysinteger
namestring
organisationIdstring (uuid)
processingFeeBpsintegerProcessing fee as basis points of principal.
processingFeeFlatKobointegerFixed processing fee in kobo.
recoveryEnabledboolean
recoveryPolicyIdstring (uuid)
settlementCatalogEnabledbooleanMerchant/service catalog step (only for merchant_wallet).
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
updatedAtstring (date-time)
curl https://api.myitura.com/v1/products/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183 \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Product retrieved",
  "data": {
    "approvalMode": "tenant",
    "capitalPoolCode": "string",
    "code": "LFC-IKJ",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "description": "Working capital for elective procedures",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "insuranceMode": "automatic",
    "insurancePremiumBearer": "borrower",
    "insurancePremiumBps": 500,
    "interestModel": "flat",
    "interestRateBps": 500,
    "isActive": true,
    "kycTier": "delegated",
    "lateFeeBps": 500,
    "maxAmountKobo": 45000000,
    "maxTenorDays": 1,
    "minAmountKobo": 45000000,
    "minTenorDays": 1,
    "name": "Lifecenter Diagnostics, Ikeja",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "processingFeeBps": 500,
    "processingFeeFlatKobo": 45000000,
    "recoveryEnabled": true,
    "recoveryPolicyId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "settlementCatalogEnabled": true,
    "settlementDestination": "borrower_wallet",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/borrowers/{id}

Get a borrower

Path

ParameterDescription
idrequiredpath · string (uuid)Borrower id.

Response

FieldDescription
clientReferencestringThe tenant's own identifier for this borrower.
createdAtstring (date-time)
emailstring (email)
firstNamestring
idstring (uuid)
identityStatusBorrowerIdentityStatusWhether the borrower has been claim-linked to a verified MyItura user.
unclaimedlinked
lastNamestring
linkedAtstring (date-time)
organisationIdstring (uuid)
phonestring
updatedAtstring (date-time)
userIdstring (uuid)Set only after a verified claim-link to a MyItura user.
curl https://api.myitura.com/v1/borrowers/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183 \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Borrower retrieved",
  "data": {
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "email": "adaeze.okonkwo@example.com",
    "firstName": "Adaeze",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "identityStatus": "unclaimed",
    "lastName": "Okonkwo",
    "linkedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "phone": "+2348031234567",
    "updatedAt": "2026-09-03T14:22:08Z",
    "userId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048"
  }
}
GET/v1/preapprovalsPre-Approved Lending

List pre-approvals

Query

ParameterDescription
statusquery · PreapprovalStatus
limitquery · integerDefaults to 50.

Response

FieldDescription
preapprovalsarray of Preapproval
curl -G https://api.myitura.com/v1/preapprovals \
  -d status=received \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Your organisation's pre-approvals, newest first",
  "data": {
    "preapprovals": [
      {
        "approvedAmountKobo": 45000000,
        "assessmentId": "cx_9f2a71c4e8",
        "borrowerId": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
        "clientReference": "CRDCHK-2026-0001",
        "confidence": "high",
        "createdAt": "2026-09-03T14:22:08Z",
        "expiresAt": "2026-09-03T14:22:08Z",
        "id": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
        "interestRateBps": 500,
        "loanId": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
        "organisationId": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
        "providerOrgId": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
        "recommendation": "approve",
        "repaymentFrequency": "monthly",
        "riskBand": "B",
        "status": "received",
        "tenorDays": 90,
        "trustScore": 742,
        "updatedAt": "2026-09-03T14:22:08Z"
      }
    ]
  }
}
POST/v1/preapprovalsPre-Approved Lending

Push a pre-approved credit decision

Idempotent on decision.metadata.assessment_idEmits preapproval.received202 on first push, 200 on replay

Push every decision, declines included. A declined push is stored, counted in your funnel and never becomes a loan, which gives you one reconcilable view of what you sent us.

Status lifecycle

receivedoffer_issuedaccepteddeclinedexpireddisbursed

Records a Cortex credit decision (approvals AND declines) against your tenant. Requires the Pre-Approved Lending permission and the tenant-config preapproval switch. Idempotent on the decision's metadata.assessment_id: a replay returns the existing record (200) instead of creating a new one (202). Emits the `preapproval.received` webhook on first ingest.

Body

FieldDescription
borrowerrequiredobject
decisionrequiredobjectYour Cortex decision payload, verbatim. Must carry metadata.assessment_id, metadata.bvn and decision.recommendation; decision.approved_amount and decision.conditions {interest_rate, tenor_days, repayment_frequency} are summarised when present.
clientReferencestringYour reference for this push.
enrichedobjectYour Cortex enriched payload, verbatim (optional).
providerIdstring (uuid)Optional healthcare provider id from GET /v1/providers (record-only).

Response

FieldDescription
approvedAmountKobointeger
assessmentIdstring
borrowerIdstring (uuid)
expiresAtstring (date-time)
preapprovalIdstring (uuid)
recommendationstring
statusPreapprovalStatusLifecycle of a pushed pre-approval: received → offer_issued → accepted | declined | expired → disbursed. A pushed decline lands directly as declined and never becomes a loan.
receivedoffer_issuedaccepteddeclinedexpireddisbursed

What we read out of the decision

YoursBecomesConversion
approved_amountapprovedAmountKoboNaira to kobo at ingest.
conditions.interest_rateinterestRateBpsPercent to basis points. Checked against your tenant rate cap.
metadata.assessment_idassessmentIdThe idempotency key for this push.
metadata.bvnIdentity match onlyHashed, then scrubbed. We never store it in the clear.
Pricing follows your decision, within your caps

The rate you push overrides the product's own rate for that one loan, so the borrower gets the price you underwrote. It is still checked against the caps on your tenant configuration when the pricing snapshot is frozen, and a rate above them is refused with 422 rather than quietly clamped.

curl -X POST https://api.myitura.com/v1/preapprovals \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: createPreapproval-01" \
  -H "Content-Type: application/json" \
  -d '{
    "borrower": {
      "email": "adaeze.okonkwo@example.com",
      "firstName": "Adaeze",
      "lastName": "Okonkwo",
      "phone": "+2348031234567"
    },
    "clientReference": "CRDCHK-2026-0001",
    "decision": {
      "approved_amount": 450000,
      "conditions": {
        "interest_rate": 5,
        "repayment_frequency": "monthly",
        "tenor_days": 90
      },
      "confidence": "high",
      "metadata": {
        "assessment_id": "cx_9f2a71c4e8",
        "bvn": "22200000001"
      },
      "recommendation": "approve",
      "risk_band": "B",
      "trust_score": 742
    },
    "providerId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c"
  }'
{
  "status": 200,
  "success": true,
  "message": "Idempotent replay, this assessment was already recorded",
  "data": {
    "approvedAmountKobo": 45000000,
    "assessmentId": "cx_9f2a71c4e8",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "expiresAt": "2026-09-03T14:22:08Z",
    "preapprovalId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "recommendation": "approve",
    "status": "received"
  }
}
GET/v1/preapprovals/{id}Pre-Approved Lending

Get a pre-approval

Path

ParameterDescription
idrequiredpath · string (uuid)

Response

FieldDescription
approvedAmountKobointegerdecision.approved_amount (naira) converted to kobo at ingest.
assessmentIdstringYour assessment identifier (decision metadata.assessment_id). It is the idempotency key: replaying the same assessment returns the existing record.
borrowerIdstring (uuid)
clientReferencestring
confidencestring
createdAtstring (date-time)
expiresAtstring (date-time)When the unconsumed pre-approval lapses (tenant-configured; not set on declines).
idstring (uuid)
interestRateBpsintegerdecision.conditions.interest_rate (percent) converted to basis points.
loanIdstring (uuid)Set once the pre-approval is carried into a loan.
organisationIdstring (uuid)
providerOrgIdstring (uuid)Healthcare provider referenced in the push (record-only).
recommendationstringdecision.recommendation as pushed (lower-cased), e.g. approve | decline.
repaymentFrequencystring
riskBandstring
statusPreapprovalStatusLifecycle of a pushed pre-approval: received → offer_issued → accepted | declined | expired → disbursed. A pushed decline lands directly as declined and never becomes a loan.
receivedoffer_issuedaccepteddeclinedexpireddisbursed
tenorDaysinteger
trustScoreinteger
updatedAtstring (date-time)
curl https://api.myitura.com/v1/preapprovals/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183 \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "The pre-approval",
  "data": {
    "approvedAmountKobo": 45000000,
    "assessmentId": "cx_9f2a71c4e8",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "confidence": "high",
    "createdAt": "2026-09-03T14:22:08Z",
    "expiresAt": "2026-09-03T14:22:08Z",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "interestRateBps": 500,
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "providerOrgId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "recommendation": "approve",
    "repaymentFrequency": "monthly",
    "riskBand": "B",
    "status": "received",
    "tenorDays": 90,
    "trustScore": 742,
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/preapprovals/{id}/issue-offerPre-Approved Lending

Issue the offer for a pre-approval

Creates the loan for a stored pre-approval and issues its offer letter, moving the pre-approval to `offer_issued` and emitting `loan.offer.issued` with a signed link to the PDF. Idempotent: if the pre-approval already has a loan, that loan is returned. The pushed decision's `approved_amount`, `conditions.interest_rate` and `conditions.tenor_days` become the loan's frozen economics (still validated against your tenant caps), and the pushed evidence is recorded as the Tier A KYC attestation. MyItura's own AML screen still gates approval, so a screen hit leaves the loan under review and issues no offer. Tenants with `preapprovalAutoIssueOffer` enabled do not need this call: a valid pushed approval issues its offer automatically.

Path

ParameterDescription
idrequiredpath · string (uuid)

Body

FieldDescription
productIdstring (uuid)Loan product to issue against. Defaults to the tenant's configured preapprovalDefaultProductId. The product's approval mode must be partner_pushed.

Response

FieldDescription
activeMandateIdstring (uuid)
amountPaidKobointegerAmount in kobo (NGN minor unit).
amountRequestedKobointegerRequested amount in kobo.
applicationUrlstringHosted borrower checkout URL, when applicable.
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
approvalNotesstring
approvedAtstring (date-time)
borrowerIdstring (uuid)
clientReferencestringTenant free-form reference, echoed in webhooks.
createdAtstring (date-time)
currencystring
disbursedAmountKobointegerAmount in kobo (NGN minor unit).
disbursedAtstring (date-time)
disbursementReferencestring
hasActiveMandateboolean
idstring (uuid)
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
loanProductIdstring (uuid)
metadataobjectTenant free-form metadata, echoed in webhooks.
offerLetterIssuedAtstring (date-time)When the offer letter PDF was last rendered and stored (re-rendered on acceptance to carry the signature block). Fetch the document via GET /v1/loans/{id}/offer-letter.
organisationIdstring (uuid)
outstandingKobointegerTotal still owed (principal + cost of credit - paid).
pricingSnapshotIdstring (uuid)Immutable pricing snapshot reference; null until approval.
principalBalanceKobointegerAmount in kobo (NGN minor unit).
principalKobointegerApproved principal in kobo (== requested unless re-priced).
rejectionReasonstring
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
statusLoanStatusLoan lifecycle state. `cancelled` is a pre-disbursement call-off by either side; cancelledBy on the loan says which.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
tenorDaysinteger
termsAcceptedAtstring (date-time)
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/preapprovals/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/issue-offer \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: issuePreapprovalOffer-01" \
  -H "Content-Type: application/json" \
  -d '{
    "productId": "3f0b8c11-5a2d-4e77-9f31-6c0e2ab54d90"
  }'
{
  "status": 200,
  "success": true,
  "message": "The loan, with its offer issued",
  "data": {
    "activeMandateId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "amountPaidKobo": 45000000,
    "amountRequestedKobo": 45000000,
    "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "approvalMode": "tenant",
    "approvalNotes": "string",
    "approvedAt": "2026-09-03T14:22:08Z",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "disbursedAmountKobo": 45000000,
    "disbursedAt": "2026-09-03T14:22:08Z",
    "disbursementReference": "CRDCHK-2026-0001",
    "hasActiveMandate": true,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "kycTier": "delegated",
    "loanProductId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "metadata": {},
    "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "outstandingKobo": 45000000,
    "pricingSnapshotId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalBalanceKobo": 45000000,
    "principalKobo": 45000000,
    "rejectionReason": "string",
    "settlementDestination": "borrower_wallet",
    "status": "pending",
    "tenorDays": 90,
    "termsAcceptedAt": "2026-09-03T14:22:08Z",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/preapprovals/funnelPre-Approved Lending

Pre-approval funnel + reconciliation

Your whole program in one call: what you pushed, what converted, and what the money is doing. Per-loan detail stays on `GET /v1/loans`; your capital position is on `GET /v1/pools/balance`.

Response

FieldDescription
acceptedByBorrowerinteger
approvedAmountKobointegerTotal credit pushed as approved.
awaitingOfferintegerApproved and stored, offer not yet issued.
declinedByBorrowerintegerBorrower turned the issued offer down.
declinedByPartnerintegerPushed as a decline; never became a loan.
disbursedinteger
disbursedAmountKobointegerTotal principal actually released.
expiredintegerLapsed before being taken up.
offerIssuedintegerOffer letter out, awaiting the borrower.
outstandingKobointegerStill owed on those loans.
pushedintegerEvery decision received, declines included.
repaidAmountKobointegerTotal collected against those loans.

Use it as the daily check that your side and ours agree. If pushed is short of what your engine sent, the gap is deliveries you should replay, not decisions we silently dropped.

curl https://api.myitura.com/v1/preapprovals/funnel \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "The funnel",
  "data": {
    "acceptedByBorrower": 1,
    "approvedAmountKobo": 45000000,
    "awaitingOffer": 1,
    "declinedByBorrower": 1,
    "declinedByPartner": 1,
    "disbursed": 1,
    "disbursedAmountKobo": 45000000,
    "expired": 1,
    "offerIssued": 1,
    "outstandingKobo": 45000000,
    "pushed": 1,
    "repaidAmountKobo": 45000000
  }
}
GET/v1/providers

List healthcare providers

This is the one deliberately cross-tenant read on the API. It serves the same contract as the public patient-facing directory, so it holds no tenant data and returns the same rows for every partner.

Paginated read-only directory of active MyItura healthcare providers (laboratories and pharmacies), serving exactly the public directory contract. Use a provider's id as providerId when pushing pre-approvals.

Query

ParameterDescription
receiveTestquery · booleanNarrow to laboratories (only true is honoured).
receiveDrugquery · booleanNarrow to pharmacies (only true is honoured).
namequery · stringFilter by provider name (partial match).
locationquery · stringFilter by state, LGA, city or address (partial match).
sort_byquery · stringDefaults to name.
namecodecreated_atupdated_at
sort_orderquery · stringDefaults to asc.
ascdesc
pagequery · integerDefaults to 1.
limitquery · integerDefaults to 20.

Response

FieldDescription
paginationobject
providersarray of ProviderDirectoryItem
curl -G https://api.myitura.com/v1/providers \
  -d sort_by=name \
  -d sort_order=asc \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "The provider directory page",
  "data": {
    "pagination": {},
    "providers": [
      {
        "address": "12 Awolowo Road, Ikeja",
        "city": "Ikeja",
        "code": "LFC-IKJ",
        "country": "Nigeria",
        "createdAt": "2026-09-03T14:22:08Z",
        "description": "Working capital for elective procedures",
        "id": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
        "isActive": true,
        "localGovernment": "Ikeja",
        "name": "Lifecenter Diagnostics, Ikeja",
        "organisationLogoUrl": "https://storage.myitura.com/offers/7c4e.pdf",
        "organisationType": "laboratory",
        "providerType": "laboratory",
        "receivesDrugs": true,
        "receivesTests": true,
        "slug": "lifecenter-diagnostics-ikeja",
        "state": "Lagos"
      }
    ]
  }
}
GET/v1/loans

List loans

Query

ParameterDescription
statusquery · stringFilter by loan status.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
limitquery · integerMaximum rows to return. Defaults to 100.
curl -G https://api.myitura.com/v1/loans \
  -d status=pending \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Loans retrieved",
  "data": [
    {
      "activeMandateId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "amountPaidKobo": 45000000,
      "amountRequestedKobo": 45000000,
      "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
      "approvalMode": "tenant",
      "approvalNotes": "string",
      "approvedAt": "2026-09-03T14:22:08Z",
      "borrowerId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "clientReference": "CRDCHK-2026-0001",
      "createdAt": "2026-09-03T14:22:08Z",
      "currency": "NGN",
      "disbursedAmountKobo": 45000000,
      "disbursedAt": "2026-09-03T14:22:08Z",
      "disbursementReference": "CRDCHK-2026-0001",
      "hasActiveMandate": true,
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "kycTier": "delegated",
      "loanProductId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "metadata": {},
      "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "outstandingKobo": 45000000,
      "pricingSnapshotId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "principalBalanceKobo": 45000000,
      "principalKobo": 45000000,
      "rejectionReason": "string",
      "settlementDestination": "borrower_wallet",
      "status": "pending",
      "tenorDays": 90,
      "termsAcceptedAt": "2026-09-03T14:22:08Z",
      "updatedAt": "2026-09-03T14:22:08Z"
    }
  ]
}
GET/v1/loans/{id}

Get a loan

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Response

FieldDescription
activeMandateIdstring (uuid)
amountPaidKobointegerAmount in kobo (NGN minor unit).
amountRequestedKobointegerRequested amount in kobo.
applicationUrlstringHosted borrower checkout URL, when applicable.
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
approvalNotesstring
approvedAtstring (date-time)
borrowerIdstring (uuid)
clientReferencestringTenant free-form reference, echoed in webhooks.
createdAtstring (date-time)
currencystring
disbursedAmountKobointegerAmount in kobo (NGN minor unit).
disbursedAtstring (date-time)
disbursementReferencestring
hasActiveMandateboolean
idstring (uuid)
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
loanProductIdstring (uuid)
metadataobjectTenant free-form metadata, echoed in webhooks.
offerLetterIssuedAtstring (date-time)When the offer letter PDF was last rendered and stored (re-rendered on acceptance to carry the signature block). Fetch the document via GET /v1/loans/{id}/offer-letter.
organisationIdstring (uuid)
outstandingKobointegerTotal still owed (principal + cost of credit - paid).
pricingSnapshotIdstring (uuid)Immutable pricing snapshot reference; null until approval.
principalBalanceKobointegerAmount in kobo (NGN minor unit).
principalKobointegerApproved principal in kobo (== requested unless re-priced).
rejectionReasonstring
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
statusLoanStatusLoan lifecycle state. `cancelled` is a pre-disbursement call-off by either side; cancelledBy on the loan says which.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
tenorDaysinteger
termsAcceptedAtstring (date-time)
updatedAtstring (date-time)
curl https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183 \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Loan retrieved",
  "data": {
    "activeMandateId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "amountPaidKobo": 45000000,
    "amountRequestedKobo": 45000000,
    "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "approvalMode": "tenant",
    "approvalNotes": "string",
    "approvedAt": "2026-09-03T14:22:08Z",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "disbursedAmountKobo": 45000000,
    "disbursedAt": "2026-09-03T14:22:08Z",
    "disbursementReference": "CRDCHK-2026-0001",
    "hasActiveMandate": true,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "kycTier": "delegated",
    "loanProductId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "metadata": {},
    "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "outstandingKobo": 45000000,
    "pricingSnapshotId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalBalanceKobo": 45000000,
    "principalKobo": 45000000,
    "rejectionReason": "string",
    "settlementDestination": "borrower_wallet",
    "status": "pending",
    "tenorDays": 90,
    "termsAcceptedAt": "2026-09-03T14:22:08Z",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/loans/{id}/accept-terms

Accept the loan terms

Records the borrower's acceptance of the offered terms; the loan becomes ready to disburse. The consent object is required: it is the evidence that this borrower agreed to this offer, so it carries what you observed when they signed and the `documentReference` of the offer they were shown.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
consentrequiredBorrowerConsentWhat you observed when your borrower signed. Relaying an acceptance is not the same as observing one, so these are the borrower's details as your surface saw them, not your server's. Every field is required.

Response

FieldDescription
activeMandateIdstring (uuid)
amountPaidKobointegerAmount in kobo (NGN minor unit).
amountRequestedKobointegerRequested amount in kobo.
applicationUrlstringHosted borrower checkout URL, when applicable.
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
approvalNotesstring
approvedAtstring (date-time)
borrowerIdstring (uuid)
clientReferencestringTenant free-form reference, echoed in webhooks.
createdAtstring (date-time)
currencystring
disbursedAmountKobointegerAmount in kobo (NGN minor unit).
disbursedAtstring (date-time)
disbursementReferencestring
hasActiveMandateboolean
idstring (uuid)
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
loanProductIdstring (uuid)
metadataobjectTenant free-form metadata, echoed in webhooks.
offerLetterIssuedAtstring (date-time)When the offer letter PDF was last rendered and stored (re-rendered on acceptance to carry the signature block). Fetch the document via GET /v1/loans/{id}/offer-letter.
organisationIdstring (uuid)
outstandingKobointegerTotal still owed (principal + cost of credit - paid).
pricingSnapshotIdstring (uuid)Immutable pricing snapshot reference; null until approval.
principalBalanceKobointegerAmount in kobo (NGN minor unit).
principalKobointegerApproved principal in kobo (== requested unless re-priced).
rejectionReasonstring
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
statusLoanStatusLoan lifecycle state. `cancelled` is a pre-disbursement call-off by either side; cancelledBy on the loan says which.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
tenorDaysinteger
termsAcceptedAtstring (date-time)
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/accept-terms \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: acceptLoanTerms-01" \
  -H "Content-Type: application/json" \
  -d '{
    "consent": {
      "documentReference": "offer_2f1c8f0a-6b2e-4a55-9d3c-0f5a1b2c3d4e",
      "ipAddress": "102.89.23.14",
      "signatureEmail": "string",
      "signatureFullName": "Ada Obi",
      "signedAt": "2026-09-03T14:22:08Z",
      "userAgent": "string"
    }
  }'
{
  "status": 200,
  "success": true,
  "message": "Accept the loan terms succeeded",
  "data": {
    "activeMandateId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "amountPaidKobo": 45000000,
    "amountRequestedKobo": 45000000,
    "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "approvalMode": "tenant",
    "approvalNotes": "string",
    "approvedAt": "2026-09-03T14:22:08Z",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "disbursedAmountKobo": 45000000,
    "disbursedAt": "2026-09-03T14:22:08Z",
    "disbursementReference": "CRDCHK-2026-0001",
    "hasActiveMandate": true,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "kycTier": "delegated",
    "loanProductId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "metadata": {},
    "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "outstandingKobo": 45000000,
    "pricingSnapshotId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalBalanceKobo": 45000000,
    "principalKobo": 45000000,
    "rejectionReason": "string",
    "settlementDestination": "borrower_wallet",
    "status": "pending",
    "tenorDays": 90,
    "termsAcceptedAt": "2026-09-03T14:22:08Z",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/loans/{id}/approve

Approve a loan

Emits loan.approved, loan.offer.issued

Approving freezes an immutable pricing snapshot, renders the offer letter and moves the loan to awaiting_acceptance. Every ledger posting for the life of the loan derives from that snapshot, so the price the borrower sees is the price that is charged.

Approves the loan (tenant approval mode). Freezes the immutable pricing snapshot and moves the loan to awaiting_acceptance.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
notesstringOptional approval notes (approve).
reasonstringRejection reason (reject).

Response

FieldDescription
activeMandateIdstring (uuid)
amountPaidKobointegerAmount in kobo (NGN minor unit).
amountRequestedKobointegerRequested amount in kobo.
applicationUrlstringHosted borrower checkout URL, when applicable.
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
approvalNotesstring
approvedAtstring (date-time)
borrowerIdstring (uuid)
clientReferencestringTenant free-form reference, echoed in webhooks.
createdAtstring (date-time)
currencystring
disbursedAmountKobointegerAmount in kobo (NGN minor unit).
disbursedAtstring (date-time)
disbursementReferencestring
hasActiveMandateboolean
idstring (uuid)
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
loanProductIdstring (uuid)
metadataobjectTenant free-form metadata, echoed in webhooks.
offerLetterIssuedAtstring (date-time)When the offer letter PDF was last rendered and stored (re-rendered on acceptance to carry the signature block). Fetch the document via GET /v1/loans/{id}/offer-letter.
organisationIdstring (uuid)
outstandingKobointegerTotal still owed (principal + cost of credit - paid).
pricingSnapshotIdstring (uuid)Immutable pricing snapshot reference; null until approval.
principalBalanceKobointegerAmount in kobo (NGN minor unit).
principalKobointegerApproved principal in kobo (== requested unless re-priced).
rejectionReasonstring
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
statusLoanStatusLoan lifecycle state. `cancelled` is a pre-disbursement call-off by either side; cancelledBy on the loan says which.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
tenorDaysinteger
termsAcceptedAtstring (date-time)
updatedAtstring (date-time)
The offer letter comes back on the event

loan.approved carries offerLetterUrl and offerLetterExpiresAt alongside assessmentId. The link is signed and short-lived. Webhook filters match exact event names, so subscribe to loan.approved if you want the letter without also handling loan.offer.issued.

An AML hit is a decision, not an error

When an attestation trips the AML screen the call answers 200 with approved: false. It needs a human, so treat it as a queue item rather than a retry. The verdict is on loan.kyc.attested.

curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/approve \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: approveLoan-01" \
  -H "Content-Type: application/json" \
  -d '{
    "notes": "Within policy, salaried, DTI 0.28",
    "reason": "Within policy, salaried, DTI 0.28"
  }'
{
  "status": 200,
  "success": true,
  "message": "Approve a loan succeeded",
  "data": {
    "activeMandateId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "amountPaidKobo": 45000000,
    "amountRequestedKobo": 45000000,
    "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "approvalMode": "tenant",
    "approvalNotes": "string",
    "approvedAt": "2026-09-03T14:22:08Z",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "disbursedAmountKobo": 45000000,
    "disbursedAt": "2026-09-03T14:22:08Z",
    "disbursementReference": "CRDCHK-2026-0001",
    "hasActiveMandate": true,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "kycTier": "delegated",
    "loanProductId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "metadata": {},
    "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "outstandingKobo": 45000000,
    "pricingSnapshotId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalBalanceKobo": 45000000,
    "principalKobo": 45000000,
    "rejectionReason": "string",
    "settlementDestination": "borrower_wallet",
    "status": "pending",
    "tenorDays": 90,
    "termsAcceptedAt": "2026-09-03T14:22:08Z",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/loans/{id}/attestation

Submit a KYC attestation

Records a delegated-KYC (Tier A) attestation for the loan's borrower and triggers MyItura's independent AML screen.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
attestedChecksobjectThe checks performed, e.g. {"bvn_verified": true, "id_type": "nin", "id_last4": "1234", "credit_check": {...}}.
schemaVersionintegerDefaults to 1.

Response

FieldDescription
amlScreenDetailstring
amlScreenStatusAMLScreenStatusOutcome of MyItura's independent AML/sanctions screen.
pendingclearhit
amlScreenedAtstring (date-time)
attestedAtstring (date-time)
attestedByKeystringMasked public key of the attesting credential.
attestedChecksobjectThe attested checks payload, e.g. {"bvn_verified": true, "id_type": "nin", "id_last4": "1234", "credit_check": {...}}.
auditOutcomestringpending | pass | fail (set by a reviewer).
borrowerIdstring (uuid)
createdAtstring (date-time)
idstring (uuid)
loanIdstring (uuid)
organisationIdstring (uuid)
sampledForAuditboolean
schemaVersioninteger
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/attestation \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: submitLoanAttestation-01" \
  -H "Content-Type: application/json" \
  -d '{
    "attestedChecks": {},
    "schemaVersion": 1
  }'
{
  "status": 201,
  "success": true,
  "message": "Attestation recorded",
  "data": {
    "amlScreenDetail": "string",
    "amlScreenStatus": "pending",
    "amlScreenedAt": "2026-09-03T14:22:08Z",
    "attestedAt": "2026-09-03T14:22:08Z",
    "attestedByKey": "string",
    "attestedChecks": {},
    "auditOutcome": "string",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "createdAt": "2026-09-03T14:22:08Z",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "sampledForAudit": true,
    "schemaVersion": 1,
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/loans/{id}/cancel

Cancel a loan

Call a loan off before any money has moved. Allowed from creation right up to disbursement, offer or no offer, and refused once disbursed: past that point the loan can only complete, default or go to recovery. Idempotent. The borrower's equivalent is the hosted checkout. Emits loan.cancelled carrying cancelledBy.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
reasonstringWhy the loan is being called off. Recorded and echoed on the loan and the loan.cancelled event.

Cancellation is allowed from creation right up to and including terms_accepted, and is refused once money has moved. The borrower's half of this is on the hosted checkout, so a loan can be called off from either side.

curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/cancel \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: cancelLoan-01" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Within policy, salaried, DTI 0.28"
  }'
{
  "status": 401,
  "success": false,
  "message": "Missing or invalid API key credentials",
  "error": "invalid_request",
  "data": "string"
}
POST/v1/loans/{id}/decline-terms

Decline the offer

Records your borrower declining an issued offer (`awaiting_acceptance` → `terms_declined`, terminal) and emits `loan.offer.declined`. Idempotent. A declined loan cannot be revived. Push a fresh decision instead. The same consent object as acceptance is required: walking away from an offer is a decision the borrower made, and the record has to say who made it and against which document.

Path

ParameterDescription
idrequiredpath · string (uuid)

Body

FieldDescription
consentrequiredBorrowerConsentWhat you observed when your borrower signed. Relaying an acceptance is not the same as observing one, so these are the borrower's details as your surface saw them, not your server's. Every field is required.
reasonstringOptional reason the borrower gave.

Response

FieldDescription
activeMandateIdstring (uuid)
amountPaidKobointegerAmount in kobo (NGN minor unit).
amountRequestedKobointegerRequested amount in kobo.
applicationUrlstringHosted borrower checkout URL, when applicable.
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
approvalNotesstring
approvedAtstring (date-time)
borrowerIdstring (uuid)
clientReferencestringTenant free-form reference, echoed in webhooks.
createdAtstring (date-time)
currencystring
disbursedAmountKobointegerAmount in kobo (NGN minor unit).
disbursedAtstring (date-time)
disbursementReferencestring
hasActiveMandateboolean
idstring (uuid)
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
loanProductIdstring (uuid)
metadataobjectTenant free-form metadata, echoed in webhooks.
offerLetterIssuedAtstring (date-time)When the offer letter PDF was last rendered and stored (re-rendered on acceptance to carry the signature block). Fetch the document via GET /v1/loans/{id}/offer-letter.
organisationIdstring (uuid)
outstandingKobointegerTotal still owed (principal + cost of credit - paid).
pricingSnapshotIdstring (uuid)Immutable pricing snapshot reference; null until approval.
principalBalanceKobointegerAmount in kobo (NGN minor unit).
principalKobointegerApproved principal in kobo (== requested unless re-priced).
rejectionReasonstring
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
statusLoanStatusLoan lifecycle state. `cancelled` is a pre-disbursement call-off by either side; cancelledBy on the loan says which.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
tenorDaysinteger
termsAcceptedAtstring (date-time)
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/decline-terms \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: declineTerms-01" \
  -H "Content-Type: application/json" \
  -d '{
    "consent": {
      "documentReference": "offer_2f1c8f0a-6b2e-4a55-9d3c-0f5a1b2c3d4e",
      "ipAddress": "102.89.23.14",
      "signatureEmail": "string",
      "signatureFullName": "Ada Obi",
      "signedAt": "2026-09-03T14:22:08Z",
      "userAgent": "string"
    },
    "reason": "Within policy, salaried, DTI 0.28"
  }'
{
  "status": 200,
  "success": true,
  "message": "Terms declined",
  "data": {
    "activeMandateId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "amountPaidKobo": 45000000,
    "amountRequestedKobo": 45000000,
    "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "approvalMode": "tenant",
    "approvalNotes": "string",
    "approvedAt": "2026-09-03T14:22:08Z",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "disbursedAmountKobo": 45000000,
    "disbursedAt": "2026-09-03T14:22:08Z",
    "disbursementReference": "CRDCHK-2026-0001",
    "hasActiveMandate": true,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "kycTier": "delegated",
    "loanProductId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "metadata": {},
    "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "outstandingKobo": 45000000,
    "pricingSnapshotId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalBalanceKobo": 45000000,
    "principalKobo": 45000000,
    "rejectionReason": "string",
    "settlementDestination": "borrower_wallet",
    "status": "pending",
    "tenorDays": 90,
    "termsAcceptedAt": "2026-09-03T14:22:08Z",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/loans/{id}/disburse

Disburse a loan

Releases funds from your capital pool to the product's settlement destination and generates the repayment schedule.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Response

FieldDescription
activeMandateIdstring (uuid)
amountPaidKobointegerAmount in kobo (NGN minor unit).
amountRequestedKobointegerRequested amount in kobo.
applicationUrlstringHosted borrower checkout URL, when applicable.
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
approvalNotesstring
approvedAtstring (date-time)
borrowerIdstring (uuid)
clientReferencestringTenant free-form reference, echoed in webhooks.
createdAtstring (date-time)
currencystring
disbursedAmountKobointegerAmount in kobo (NGN minor unit).
disbursedAtstring (date-time)
disbursementReferencestring
hasActiveMandateboolean
idstring (uuid)
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
loanProductIdstring (uuid)
metadataobjectTenant free-form metadata, echoed in webhooks.
offerLetterIssuedAtstring (date-time)When the offer letter PDF was last rendered and stored (re-rendered on acceptance to carry the signature block). Fetch the document via GET /v1/loans/{id}/offer-letter.
organisationIdstring (uuid)
outstandingKobointegerTotal still owed (principal + cost of credit - paid).
pricingSnapshotIdstring (uuid)Immutable pricing snapshot reference; null until approval.
principalBalanceKobointegerAmount in kobo (NGN minor unit).
principalKobointegerApproved principal in kobo (== requested unless re-priced).
rejectionReasonstring
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
statusLoanStatusLoan lifecycle state. `cancelled` is a pre-disbursement call-off by either side; cancelledBy on the loan says which.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
tenorDaysinteger
termsAcceptedAtstring (date-time)
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/disburse \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: disburseLoan-01"
{
  "status": 200,
  "success": true,
  "message": "Disburse a loan succeeded",
  "data": {
    "activeMandateId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "amountPaidKobo": 45000000,
    "amountRequestedKobo": 45000000,
    "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "approvalMode": "tenant",
    "approvalNotes": "string",
    "approvedAt": "2026-09-03T14:22:08Z",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "disbursedAmountKobo": 45000000,
    "disbursedAt": "2026-09-03T14:22:08Z",
    "disbursementReference": "CRDCHK-2026-0001",
    "hasActiveMandate": true,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "kycTier": "delegated",
    "loanProductId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "metadata": {},
    "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "outstandingKobo": 45000000,
    "pricingSnapshotId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalBalanceKobo": 45000000,
    "principalKobo": 45000000,
    "rejectionReason": "string",
    "settlementDestination": "borrower_wallet",
    "status": "pending",
    "tenorDays": 90,
    "termsAcceptedAt": "2026-09-03T14:22:08Z",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/loans/{id}/kyc

Submit the borrower's identity

Managed-tier identity, collected by you and verified by us. This is the tenant-driven equivalent of the identity step in the hosted checkout: the same providers, the same encrypted retention, the same transition from `kyc_required` to `kyc_completed`. Use it when you drive your own interface rather than sending the borrower to the hosted page.\n\nOnly managed-tier loans reach it. On a delegated-tier loan you attest identity yourself, so a submission here is refused with 400 and you should post to /v1/loans/{id}/attestation instead.\n\nA provider refusing the identity is a 200 with `outcome: failed`, not an error: the loan's state is the answer either way.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
bvnrequiredstringBank Verification Number, exactly 11 digits. Required: it is what ties the borrower to bureau data, so a NIN does not substitute for it.
addressstring
dateOfBirthstringThe borrower's date of birth, passed to the provider as part of the check.
ninstringNational Identification Number, if the borrower has one. Length-ranged rather than pinned at 11 because a NIN may carry a suffix.

Response

FieldDescription
documentsarray of object
loanStatusstringThe loan's status after this submission.
outcomestring`verified` advances the loan to `kyc_completed`. `failed` means a provider refused the identity. `pending` means the provider has not answered yet; submit again or poll the loan.
verifiedfailedpending
curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/kyc \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: submitLoanKYC-01" \
  -H "Content-Type: application/json" \
  -d '{
    "address": "12 Marina Road, Lagos",
    "bvn": "22200000001",
    "dateOfBirth": "1990-01-31",
    "nin": "12345678901"
  }'
{
  "status": 200,
  "success": true,
  "message": "Identity submitted",
  "data": {
    "documents": [
      {
        "status": "verified",
        "type": "bvn"
      }
    ],
    "loanStatus": "string",
    "outcome": "verified"
  }
}
GET/v1/loans/{id}/offer-letter

Get a link to the offer letter PDF

Mints a fresh short-lived signed link to the loan's offer letter PDF (rendered at approval, re-rendered with the signature block once accepted). The document is stored privately and is never public, so links expire. Request a new one rather than caching.

Path

ParameterDescription
idrequiredpath · string (uuid)

Response

FieldDescription
documentReferencestringIdentifies the offer in this letter. Send it back on accept-terms or decline-terms so the acceptance names what was accepted.
expiresAtstring (date-time)
urlstring (uri)
curl https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/offer-letter \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "A signed link to the PDF",
  "data": {
    "documentReference": "offer_2f1c8f0a-6b2e-4a55-9d3c-0f5a1b2c3d4e",
    "expiresAt": "2026-09-03T14:22:08Z",
    "url": "https://storage.myitura.com/offers/7c4e.pdf"
  }
}
POST/v1/loans/{id}/reject

Reject a loan

Rejects the loan (terminal).

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
notesstringOptional approval notes (approve).
reasonstringRejection reason (reject).

Response

FieldDescription
activeMandateIdstring (uuid)
amountPaidKobointegerAmount in kobo (NGN minor unit).
amountRequestedKobointegerRequested amount in kobo.
applicationUrlstringHosted borrower checkout URL, when applicable.
approvalModeApprovalModeWho approves loans on the product. `partner_pushed`: the decision is made on the partner's side and pushed via POST /v1/preapprovals; the loan's economics come from the pushed decision rather than the product's own pricing.
tenantauto_credit_scoremyitura_analystpartner_pushed
approvalNotesstring
approvedAtstring (date-time)
borrowerIdstring (uuid)
clientReferencestringTenant free-form reference, echoed in webhooks.
createdAtstring (date-time)
currencystring
disbursedAmountKobointegerAmount in kobo (NGN minor unit).
disbursedAtstring (date-time)
disbursementReferencestring
hasActiveMandateboolean
idstring (uuid)
kycTierKYCTierWho performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B).
delegatedmanaged
loanProductIdstring (uuid)
metadataobjectTenant free-form metadata, echoed in webhooks.
offerLetterIssuedAtstring (date-time)When the offer letter PDF was last rendered and stored (re-rendered on acceptance to carry the signature block). Fetch the document via GET /v1/loans/{id}/offer-letter.
organisationIdstring (uuid)
outstandingKobointegerTotal still owed (principal + cost of credit - paid).
pricingSnapshotIdstring (uuid)Immutable pricing snapshot reference; null until approval.
principalBalanceKobointegerAmount in kobo (NGN minor unit).
principalKobointegerApproved principal in kobo (== requested unless re-priced).
rejectionReasonstring
settlementDestinationSettlementDestinationWhere disbursed funds go.
borrower_walletborrower_bank_accountmerchant_wallettenant_wallet
statusLoanStatusLoan lifecycle state. `cancelled` is a pre-disbursement call-off by either side; cancelledBy on the loan says which.
pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled
tenorDaysinteger
termsAcceptedAtstring (date-time)
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/reject \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: rejectLoan-01" \
  -H "Content-Type: application/json" \
  -d '{
    "notes": "Within policy, salaried, DTI 0.28",
    "reason": "Within policy, salaried, DTI 0.28"
  }'
{
  "status": 200,
  "success": true,
  "message": "Reject a loan succeeded",
  "data": {
    "activeMandateId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "amountPaidKobo": 45000000,
    "amountRequestedKobo": 45000000,
    "applicationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "approvalMode": "tenant",
    "approvalNotes": "string",
    "approvedAt": "2026-09-03T14:22:08Z",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "clientReference": "CRDCHK-2026-0001",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "disbursedAmountKobo": 45000000,
    "disbursedAt": "2026-09-03T14:22:08Z",
    "disbursementReference": "CRDCHK-2026-0001",
    "hasActiveMandate": true,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "kycTier": "delegated",
    "loanProductId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "metadata": {},
    "offerLetterIssuedAt": "2026-09-03T14:22:08Z",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "outstandingKobo": 45000000,
    "pricingSnapshotId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalBalanceKobo": 45000000,
    "principalKobo": 45000000,
    "rejectionReason": "string",
    "settlementDestination": "borrower_wallet",
    "status": "pending",
    "tenorDays": 90,
    "termsAcceptedAt": "2026-09-03T14:22:08Z",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/loans/{id}/schedule

Get the loan's repayment schedule

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.
curl https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/schedule \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Schedule retrieved",
  "data": [
    {
      "amountPaidKobo": 45000000,
      "createdAt": "2026-09-03T14:22:08Z",
      "dueDate": "2026-09-03T14:22:08Z",
      "feeKobo": 45000000,
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "installmentNumber": 1,
      "interestKobo": 45000000,
      "loanId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "paidAt": "2026-09-03T14:22:08Z",
      "principalKobo": 45000000,
      "status": "pending",
      "totalKobo": 45000000,
      "updatedAt": "2026-09-03T14:22:08Z"
    }
  ]
}

How a mandate completes

A mandate is the only automated way a loan is ever collected, so the whole flow exists to answer one question with evidence rather than assumption: can we debit this borrower when the instalment falls due?

initiatedpendingapprovedactive

You create the mandate, we open an authorisation with the provider and hand you back an authorizationUrl. Send the borrower there. When they have authorised, confirm it with POST /v1/mandates/{id}/activate.

Finishing the page is not the same as being live

The borrower returning from the provider tells you they completed a form. It does not tell you the mandate is chargeable, and the gap between the two is not instant. Treat the mandate as pending until you have confirmed it, either by calling activate or by handling mandate.active.

What chargeable means

Status alone is not the test. A mandate is chargeable only when it is active, the provider has confirmed the authorisation, and there is an authorisation code to charge against. A mandate sitting at approved has been accepted but not yet authorised by the borrower, and cannot be debited.

Activate takes no body

It deliberately does not accept an authorisation code from you. A code is proof that one specific customer authorised us to debit one specific account, so accepting one over the wire would let a caller present a stranger's authorisation and debit them. The only authorisation we trust is the one we read back from the provider ourselves. Activate is a verification, never an assertion.

Testing without a borrower

With a test key, POST /v1/test/mandates/{id}/simulate-activation stands in for the authorisation step so you can drive the full lifecycle in sandbox. It refuses live keys.

The sequence
# 1. open the authorisation
POST /v1/loans/{id}/mandates
{ "email": "ada@example.com",
  "bankCode": "058",
  "accountNumber": "0123456789" }

# -> 201
{ "id": "b2f1...", "status": "pending",
  "authorizationUrl": "https://checkout.paystack.com/..." }

# 2. send the borrower to authorizationUrl

# 3. confirm what they actually authorised
POST /v1/mandates/b2f1.../activate     # no body

# -> 200
{ "id": "b2f1...", "status": "active" }
Completion event
{
  "id": "evt_2c8d41f60ba97e13",
  "event": "mandate.active",
  "mode": "live",
  "createdAt": "2026-09-04T09:41:12Z",
  "data": {
    "mandateId": "b2f10c73-4d81-4a02-9f6e-8b7d5c1e2a40",
    "loanId": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
    "status": "active"
  }
}
POST/v1/loans/{id}/mandates

Create a direct-debit mandate

Initiates a direct-debit mandate for the loan's borrower. The borrower authorises via the returned authorizationUrl.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
emailrequiredstring (email)Borrower email used for the provider authorisation.
accountNumberstring
bankCodestring
callbackUrlstring (uri)Where the borrower is redirected after authorising.
providerstringThe rail. Omit for the default Paystack flow. Set `creditcheck` to register a mandate YOU operate: nothing is initialised with Paystack, the mandate goes straight to active as a status marker, and we never debit it.
paystackmonocreditcheck

Response

FieldDescription
accountNumberstring
activatedAtstring (date-time)
amountKobointegerAmount in kobo (NGN minor unit).
authorizationUrlstringBorrower authorisation URL (hosted by the provider).
bankCodestring
borrowerIdstring (uuid)
createdAtstring (date-time)
emailstring (email)
idstring (uuid)
loanIdstring (uuid)
organisationIdstring (uuid)
providerMandateProviderThe auto-debit rail. `paystack` (live) and `mono` are charged BY MyItura. `creditcheck` is PARTNER-OPERATED: you hold the mandate and debit on your own side, we never hold an authorisation for it and never charge it, so it is a status marker only. Record what you collect with `method: "external"`.
paystackmonocreditcheck
referencestring
statusMandateStatus
initiatedpendingactivefailedcancelledexpired
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/mandates \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: createLoanMandate-01" \
  -H "Content-Type: application/json" \
  -d '{
    "accountNumber": "string",
    "bankCode": "string",
    "callbackUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "email": "adaeze.okonkwo@example.com",
    "provider": "paystack"
  }'
{
  "status": 201,
  "success": true,
  "message": "Mandate created",
  "data": {
    "accountNumber": "string",
    "activatedAt": "2026-09-03T14:22:08Z",
    "amountKobo": 45000000,
    "authorizationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "bankCode": "string",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "createdAt": "2026-09-03T14:22:08Z",
    "email": "adaeze.okonkwo@example.com",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "provider": "paystack",
    "reference": "string",
    "status": "initiated",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/mandates/{id}

Get a mandate

Path

ParameterDescription
idrequiredpath · string (uuid)Mandate id.

Response

FieldDescription
accountNumberstring
activatedAtstring (date-time)
amountKobointegerAmount in kobo (NGN minor unit).
authorizationUrlstringBorrower authorisation URL (hosted by the provider).
bankCodestring
borrowerIdstring (uuid)
createdAtstring (date-time)
emailstring (email)
idstring (uuid)
loanIdstring (uuid)
organisationIdstring (uuid)
providerMandateProviderThe auto-debit rail. `paystack` (live) and `mono` are charged BY MyItura. `creditcheck` is PARTNER-OPERATED: you hold the mandate and debit on your own side, we never hold an authorisation for it and never charge it, so it is a status marker only. Record what you collect with `method: "external"`.
paystackmonocreditcheck
referencestring
statusMandateStatus
initiatedpendingactivefailedcancelledexpired
updatedAtstring (date-time)
curl https://api.myitura.com/v1/mandates/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183 \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Mandate retrieved",
  "data": {
    "accountNumber": "string",
    "activatedAt": "2026-09-03T14:22:08Z",
    "amountKobo": 45000000,
    "authorizationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "bankCode": "string",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "createdAt": "2026-09-03T14:22:08Z",
    "email": "adaeze.okonkwo@example.com",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "provider": "paystack",
    "reference": "string",
    "status": "initiated",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
POST/v1/mandates/{id}/activate

Activate a mandate

Verifies the borrower's authorisation with the provider and activates the mandate. Supplying authorizationCode uses the sandbox/test path.

Path

ParameterDescription
idrequiredpath · string (uuid)Mandate id.

Response

FieldDescription
accountNumberstring
activatedAtstring (date-time)
amountKobointegerAmount in kobo (NGN minor unit).
authorizationUrlstringBorrower authorisation URL (hosted by the provider).
bankCodestring
borrowerIdstring (uuid)
createdAtstring (date-time)
emailstring (email)
idstring (uuid)
loanIdstring (uuid)
organisationIdstring (uuid)
providerMandateProviderThe auto-debit rail. `paystack` (live) and `mono` are charged BY MyItura. `creditcheck` is PARTNER-OPERATED: you hold the mandate and debit on your own side, we never hold an authorisation for it and never charge it, so it is a status marker only. Record what you collect with `method: "external"`.
paystackmonocreditcheck
referencestring
statusMandateStatus
initiatedpendingactivefailedcancelledexpired
updatedAtstring (date-time)
Activation verifies, it does not authorise

The borrower authorises at the authorizationUrl the create call returned. This endpoint confirms what they authorised; it takes no authorisation code from you, so a mandate can never be attached to an instrument its owner did not approve.

curl -X POST https://api.myitura.com/v1/mandates/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/activate \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: activateLoanMandate-01"
{
  "status": 200,
  "success": true,
  "message": "Mandate activated",
  "data": {
    "accountNumber": "string",
    "activatedAt": "2026-09-03T14:22:08Z",
    "amountKobo": 45000000,
    "authorizationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "bankCode": "string",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "createdAt": "2026-09-03T14:22:08Z",
    "email": "adaeze.okonkwo@example.com",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "provider": "paystack",
    "reference": "string",
    "status": "initiated",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/loans/{id}/repayments

List the loan's repayments

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.
curl https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/repayments \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Repayments retrieved",
  "data": [
    {
      "amountKobo": 45000000,
      "borrowerId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "completedAt": "2026-09-03T14:22:08Z",
      "createdAt": "2026-09-03T14:22:08Z",
      "externalReference": "CRDCHK-COLL-88213",
      "feePortionKobo": 45000000,
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "interestPortionKobo": 45000000,
      "ledgerTransactionRef": "string",
      "loanId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "method": "wallet",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "principalPortionKobo": 45000000,
      "reference": "string",
      "status": "pending",
      "updatedAt": "2026-09-03T14:22:08Z"
    }
  ]
}
POST/v1/loans/{id}/repayments

Record a repayment

Idempotent on externalReferenceEmits loan.repayment.completed

Use this when you run collection yourself. When we collect on a mandate the repayment is written for you and this call is unnecessary.

Collects a repayment via wallet, mandate charge, or records an external (off-platform) collection. The amount is allocated fee -> interest -> principal.

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Body

FieldDescription
amountKoborequiredintegerAmount in kobo (NGN minor unit).
methodrequiredRepaymentMethodHow the repayment's funds were collected. - `external`: you collected on your own rail and are recording it (idempotent on `externalReference`). This is the default for partner-run direct debit. - `cash_wallet`: debit the borrower's OWN MyItura cash wallet, which is what their bank transfer pays into. Requires a claimed MyItura account with sufficient balance. - `wallet`: sweep the borrower's UNDRAWN credit back to your pool, not a collection from the borrower. - `mandate`: charge a MyItura-operated Paystack mandate. Not available for partner-operated rails.
walletmandateexternalcash_wallet
externalReferencestringYour collection reference (method=external).

Response

FieldDescription
amountKobointegerAmount in kobo (NGN minor unit).
borrowerIdstring (uuid)
completedAtstring (date-time)
createdAtstring (date-time)
externalReferencestringTenant's off-platform collection reference (method=external).
feePortionKobointegerAmount in kobo (NGN minor unit).
idstring (uuid)
interestPortionKobointegerAmount in kobo (NGN minor unit).
ledgerTransactionRefstring
loanIdstring (uuid)
methodRepaymentMethodHow the repayment's funds were collected. - `external`: you collected on your own rail and are recording it (idempotent on `externalReference`). This is the default for partner-run direct debit. - `cash_wallet`: debit the borrower's OWN MyItura cash wallet, which is what their bank transfer pays into. Requires a claimed MyItura account with sufficient balance. - `wallet`: sweep the borrower's UNDRAWN credit back to your pool, not a collection from the borrower. - `mandate`: charge a MyItura-operated Paystack mandate. Not available for partner-operated rails.
walletmandateexternalcash_wallet
organisationIdstring (uuid)
principalPortionKobointegerAmount in kobo (NGN minor unit).
referencestringSystem-generated unique repayment reference.
statusRepaymentStatus
pendingcompletedfailed
updatedAtstring (date-time)

How the money is applied

A repayment is allocated in a fixed order, never proportionally: fees first, then interest, then principal. Nothing is allocated beyond what is outstanding in each bucket, and any remainder above the total outstanding comes back to you unallocated rather than being absorbed.

A reference is a promise

Reuse a reference and you get the original movement back, not a second one. Never generate a fresh reference on retry, and never reuse one across two genuinely different collections: both mistakes look identical in a log and only one of them loses money.

curl -X POST https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/repayments \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: recordLoanRepayment-01" \
  -H "Content-Type: application/json" \
  -d '{
    "amountKobo": 45000000,
    "externalReference": "CRDCHK-COLL-88213",
    "method": "wallet"
  }'
{
  "status": 201,
  "success": true,
  "message": "Repayment recorded",
  "data": {
    "amountKobo": 45000000,
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "completedAt": "2026-09-03T14:22:08Z",
    "createdAt": "2026-09-03T14:22:08Z",
    "externalReference": "CRDCHK-COLL-88213",
    "feePortionKobo": 45000000,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "interestPortionKobo": 45000000,
    "ledgerTransactionRef": "string",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "method": "wallet",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "principalPortionKobo": 45000000,
    "reference": "string",
    "status": "pending",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/loans/{id}/insurance

Get the loan's insurance policy

Path

ParameterDescription
idrequiredpath · string (uuid)Loan id.

Response

FieldDescription
commissionKobointegerThe platform's share of the premium.
createdAtstring (date-time)
errorMessagestring
idstring (uuid)
loanIdstring (uuid)
organisationIdstring (uuid)
policyReferencestring
premiumBearerInsurancePremiumBearerWho pays the insurance premium.
borrowertenant
premiumKobointegerAmount in kobo (NGN minor unit).
providerstring
statusInsurancePolicyStatus
pendingactivefailed
triggeredBystring
automaticmanual
updatedAtstring (date-time)
curl https://api.myitura.com/v1/loans/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/insurance \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Insurance policy retrieved",
  "data": {
    "commissionKobo": 45000000,
    "createdAt": "2026-09-03T14:22:08Z",
    "errorMessage": "string",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "policyReference": "CRDCHK-2026-0001",
    "premiumBearer": "borrower",
    "premiumKobo": 45000000,
    "provider": "mycover",
    "status": "pending",
    "triggeredBy": "automatic",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/payouts

List payout requests

Query

ParameterDescription
statusquery · stringFilter by payout status.
requestedsettlingcompletedrejected
curl -G https://api.myitura.com/v1/payouts \
  -d status=requested \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Payouts retrieved",
  "data": [
    {
      "accountName": "string",
      "accountNumber": "string",
      "amountKobo": 45000000,
      "bankCode": "string",
      "bankName": "string",
      "borrowerId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "createdAt": "2026-09-03T14:22:08Z",
      "currency": "NGN",
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "ledgerTransactionRef": "string",
      "loanId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "rejectionReason": "string",
      "settledAt": "2026-09-03T14:22:08Z",
      "settledByUserId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "settlementReference": "CRDCHK-2026-0001",
      "status": "requested",
      "updatedAt": "2026-09-03T14:22:08Z"
    }
  ]
}
POST/v1/payouts

Request a payout

Raises a manual bank payout against the borrower's ledger balance. Settlement happens off-platform; mark it settled (or rejected) afterwards.

Body

FieldDescription
accountNumberrequiredstring
amountKoborequiredintegerAmount in kobo (NGN minor unit).
bankCoderequiredstring
bankNamerequiredstring
borrowerIdrequiredstring (uuid)
accountNamestring
loanIdstring (uuid)

Response

FieldDescription
accountNamestring
accountNumberstring
amountKobointegerAmount in kobo (NGN minor unit).
bankCodestring
bankNamestring
borrowerIdstring (uuid)
createdAtstring (date-time)
currencystring
idstring (uuid)
ledgerTransactionRefstring
loanIdstring (uuid)
organisationIdstring (uuid)
rejectionReasonstring
settledAtstring (date-time)
settledByUserIdstring (uuid)
settlementReferencestring
statusPayoutStatus
requestedsettlingcompletedrejected
updatedAtstring (date-time)
curl -X POST https://api.myitura.com/v1/payouts \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: requestPayout-01" \
  -H "Content-Type: application/json" \
  -d '{
    "accountName": "string",
    "accountNumber": "string",
    "amountKobo": 45000000,
    "bankCode": "string",
    "bankName": "string",
    "borrowerId": "3f0b8c11-5a2d-4e77-9f31-6c0e2ab54d90",
    "loanId": "3f0b8c11-5a2d-4e77-9f31-6c0e2ab54d90"
  }'
{
  "status": 201,
  "success": true,
  "message": "Payout requested",
  "data": {
    "accountName": "string",
    "accountNumber": "string",
    "amountKobo": 45000000,
    "bankCode": "string",
    "bankName": "string",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "ledgerTransactionRef": "string",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "rejectionReason": "string",
    "settledAt": "2026-09-03T14:22:08Z",
    "settledByUserId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "settlementReference": "CRDCHK-2026-0001",
    "status": "requested",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/payouts/{id}

Get a payout request

Path

ParameterDescription
idrequiredpath · string (uuid)Payout request id.

Response

FieldDescription
accountNamestring
accountNumberstring
amountKobointegerAmount in kobo (NGN minor unit).
bankCodestring
bankNamestring
borrowerIdstring (uuid)
createdAtstring (date-time)
currencystring
idstring (uuid)
ledgerTransactionRefstring
loanIdstring (uuid)
organisationIdstring (uuid)
rejectionReasonstring
settledAtstring (date-time)
settledByUserIdstring (uuid)
settlementReferencestring
statusPayoutStatus
requestedsettlingcompletedrejected
updatedAtstring (date-time)
curl https://api.myitura.com/v1/payouts/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183 \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Payout retrieved",
  "data": {
    "accountName": "string",
    "accountNumber": "string",
    "amountKobo": 45000000,
    "bankCode": "string",
    "bankName": "string",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "createdAt": "2026-09-03T14:22:08Z",
    "currency": "NGN",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "ledgerTransactionRef": "string",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "rejectionReason": "string",
    "settledAt": "2026-09-03T14:22:08Z",
    "settledByUserId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "settlementReference": "CRDCHK-2026-0001",
    "status": "requested",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/settlements

List settlement statements

curl https://api.myitura.com/v1/settlements \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Settlement statements retrieved",
  "data": [
    {
      "createdAt": "2026-09-03T14:22:08Z",
      "failureReason": "string",
      "feeSweptKobo": 45000000,
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "interestSweptKobo": 45000000,
      "lines": [
        {
          "feeKobo": 45000000,
          "interestKobo": 45000000,
          "loanId": "3f0b8c11-5a2d-4e77-9f31-6c0e2ab54d90",
          "repayments": 1
        }
      ],
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "periodEnd": "2026-09-03T14:22:08Z",
      "periodStart": "2026-09-03T14:22:08Z",
      "status": "completed",
      "totalSweptKobo": 45000000,
      "transferReference": "CRDCHK-2026-0001",
      "updatedAt": "2026-09-03T14:22:08Z"
    }
  ]
}
GET/v1/settlements/{id}

Get a settlement statement

Path

ParameterDescription
idrequiredpath · string (uuid)Settlement statement id.

Response

FieldDescription
createdAtstring (date-time)
failureReasonstring
feeSweptKobointegerAmount in kobo (NGN minor unit).
idstring (uuid)
interestSweptKobointegerAmount in kobo (NGN minor unit).
linesarray of SettlementLine
organisationIdstring (uuid)
periodEndstring (date-time)
periodStartstring (date-time)
statusSettlementStatementStatus
completedskippedfailed
totalSweptKobointegerAmount in kobo (NGN minor unit).
transferReferencestring
updatedAtstring (date-time)
curl https://api.myitura.com/v1/settlements/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183 \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Settlement statement retrieved",
  "data": {
    "createdAt": "2026-09-03T14:22:08Z",
    "failureReason": "string",
    "feeSweptKobo": 45000000,
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "interestSweptKobo": 45000000,
    "lines": [
      {
        "feeKobo": 45000000,
        "interestKobo": 45000000,
        "loanId": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
        "repayments": 1
      }
    ],
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "periodEnd": "2026-09-03T14:22:08Z",
    "periodStart": "2026-09-03T14:22:08Z",
    "status": "completed",
    "totalSweptKobo": 45000000,
    "transferReference": "CRDCHK-2026-0001",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}
GET/v1/settlements/{id}/csv

Download a settlement statement as CSV

Path

ParameterDescription
idrequiredpath · string (uuid)Settlement statement id.
curl https://api.myitura.com/v1/settlements/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/csv \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
"string"
GET/v1/usage

Get your API usage rollup

Your organisation's daily API-usage rollup (the metering/billing feed).

Query

ParameterDescription
daysquery · integerHow many days back to include. Defaults to 30.
curl https://api.myitura.com/v1/usage \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Usage retrieved",
  "data": [
    {
      "day": "2026-09-03T14:22:08Z",
      "errorCount": 1,
      "requestCount": 1
    }
  ]
}

Events and signatures

Register an HTTPS endpoint and pick the events you want. Delivery goes through a durable outbox: a failed delivery is retried on a backoff, survives a restart on our side, and can be replayed by hand from the event log.

Filters match exact names

There is no wildcard. loan.* subscribes to nothing. List every event you want by name, and add new ones as we publish them.

Event catalogue

loan.application.submittedA loan record was created
loan.kyc.attestedAttestation recorded, AML verdict attached
loan.approvedCarries the signed offer letter URL
loan.rejectedTerminal
loan.offer.issuedOffer letter out to the borrower
loan.offer.acceptedTerms accepted, ready to disburse
loan.offer.declinedBorrower turned the offer down
loan.cancelledCalled off before disbursement
loan.disbursedPrincipal left your capital pool
loan.repayment.upcomingPre-due reminder
loan.repayment.overdueAn instalment passed its due date
loan.repayment.completedA repayment posted
loan.completedFully repaid
loan.defaultedPast the default threshold
loan.insurance.pendingPolicy requested from the insurer
loan.insurance.activatedPolicy live
preapproval.receivedYour push was stored
preapproval.expiredLapsed unconsumed
mandate.createdAuthorisation URL issued
mandate.activatedBorrower authorised the debit
payout.requestedBorrower raised a bank payout
payout.approval.recordedSecond approver signed off
payout.completedFunds left to the bank account
payout.rejectedRequest refused
settlement.createdA statement is ready to read

Verifying a delivery

Every request carries X-MyItura-Signature and X-MyItura-Timestamp. The signature is an HMAC-SHA256 over timestamp + "." + rawBody, keyed with the secret shown once when you registered the endpoint.

Compare in constant time, reject anything older than five minutes, and sign against the raw body. Re-serialising the JSON before you verify will change a byte somewhere and every delivery will fail.

Answer 2xx as soon as you have stored the event and do the work afterwards. An endpoint that keeps failing is disabled automatically and we email you, so a slow handler eventually looks like a broken one.

Delivery
{
  "id": "evt_5b1f9a3c7d204e88",
  "event": "loan.approved",
  "mode": "live",
  "createdAt": "2026-09-03T14:22:08Z",
  "data": {
    "loanId": "7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183",
    "assessmentId": "cx_9f2a71c4e8",
    "status": "awaiting_acceptance",
    "principalKobo": 45000000,
    "offerLetterUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "offerLetterExpiresAt": "2026-09-03T20:15:00Z"
  }
}
# Every delivery carries both headers. Sign the RAW body:
#   X-MyItura-Timestamp: 1788451328
#   X-MyItura-Signature: 6f1c...c204
#
# signature = HMAC_SHA256(secret, timestamp + "." + rawBody)
#
# Re-serialising the JSON before you verify changes a byte
# somewhere and every delivery fails.
GET/v1/events

List webhook deliveries

Your organisation's recent webhook delivery log, newest first.

Query

ParameterDescription
limitquery · integerMaximum rows to return. Defaults to 100.
curl https://api.myitura.com/v1/events \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Events retrieved",
  "data": [
    {
      "attemptCount": 1,
      "createdAt": "2026-09-03T14:22:08Z",
      "deliveredAt": "2026-09-03T14:22:08Z",
      "endpointId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "event": "loan.approved",
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "lastError": "string",
      "maxAttempts": 1,
      "nextAttemptAt": "2026-09-03T14:22:08Z",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "payload": {},
      "responseStatus": 1,
      "status": "pending",
      "targetUrl": "https://storage.myitura.com/offers/7c4e.pdf",
      "updatedAt": "2026-09-03T14:22:08Z"
    }
  ]
}
POST/v1/events/{id}/redeliver

Redeliver a webhook event

Requeues a delivery for another attempt (e.g. after fixing your receiver).

Path

ParameterDescription
idrequiredpath · string (uuid)Webhook delivery id.
curl -X POST https://api.myitura.com/v1/events/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/redeliver \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: redeliverEvent-01"
{
  "status": 200,
  "success": true,
  "message": "Event requeued for delivery",
  "data": "string"
}
GET/v1/webhook-endpoints

List webhook endpoints

Signing secrets are never included; they are shown once at registration only.

curl https://api.myitura.com/v1/webhook-endpoints \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..."
{
  "status": 200,
  "success": true,
  "message": "Endpoints retrieved",
  "data": [
    {
      "consecutiveFails": 1,
      "createdAt": "2026-09-03T14:22:08Z",
      "description": "Working capital for elective procedures",
      "events": [
        "string"
      ],
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "lastFailureAt": "2026-09-03T14:22:08Z",
      "lastSuccessAt": "2026-09-03T14:22:08Z",
      "mode": "live",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "status": "active",
      "updatedAt": "2026-09-03T14:22:08Z",
      "url": "https://storage.myitura.com/offers/7c4e.pdf"
    }
  ]
}
POST/v1/webhook-endpoints

Register a webhook endpoint

Registers a delivery destination. The response contains the endpoint's HMAC-SHA256 signing secret exactly once. Store it securely, because it cannot be retrieved again.

Body

FieldDescription
urlrequiredstring (uri)
descriptionstring
eventsarray of stringEvent names to subscribe to; omit or send empty for all events.
modestringDefaults to live.
livetest

Response

FieldDescription
endpointWebhookEndpointA registered webhook destination. The signing secret is returned once on creation and never serialised again.
signingSecretstringThe whsec_ HMAC-SHA256 signing secret for this endpoint. Returned only in this response.
curl -X POST https://api.myitura.com/v1/webhook-endpoints \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: registerWebhookEndpoint-01" \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Working capital for elective procedures",
    "events": [
      "loan.approved",
      "loan.disbursed",
      "repayment.completed"
    ],
    "mode": "live",
    "url": "https://storage.myitura.com/offers/7c4e.pdf"
  }'
{
  "status": 201,
  "success": true,
  "message": "Webhook endpoint registered; signingSecret shown once",
  "data": {
    "endpoint": {
      "consecutiveFails": 1,
      "createdAt": "2026-09-03T14:22:08Z",
      "description": "Working capital for elective procedures",
      "events": [
        "string"
      ],
      "id": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "lastFailureAt": "2026-09-03T14:22:08Z",
      "lastSuccessAt": "2026-09-03T14:22:08Z",
      "mode": "live",
      "organisationId": "9f1c2b64-0f1a-4c3e-9b8a-2d5e7f0a1b2c",
      "status": "active",
      "updatedAt": "2026-09-03T14:22:08Z",
      "url": "https://storage.myitura.com/offers/7c4e.pdf"
    },
    "signingSecret": "whsec_..."
  }
}
POST/v1/test/mandates/{id}/simulate-activation

Simulate mandate activation (sandbox only)

Test-mode helper that marks a mandate active without a real provider authorisation. Refused (403) for live-mode keys.

Path

ParameterDescription
idrequiredpath · string (uuid)Mandate id.

Response

FieldDescription
accountNumberstring
activatedAtstring (date-time)
amountKobointegerAmount in kobo (NGN minor unit).
authorizationUrlstringBorrower authorisation URL (hosted by the provider).
bankCodestring
borrowerIdstring (uuid)
createdAtstring (date-time)
emailstring (email)
idstring (uuid)
loanIdstring (uuid)
organisationIdstring (uuid)
providerMandateProviderThe auto-debit rail. `paystack` (live) and `mono` are charged BY MyItura. `creditcheck` is PARTNER-OPERATED: you hold the mandate and debit on your own side, we never hold an authorisation for it and never charge it, so it is a status marker only. Record what you collect with `method: "external"`.
paystackmonocreditcheck
referencestring
statusMandateStatus
initiatedpendingactivefailedcancelledexpired
updatedAtstring (date-time)
Test keys only

Live keys are refused here. There is no way to mark a real mandate active without the borrower authorising it, which is the point.

curl -X POST https://api.myitura.com/v1/test/mandates/7c4e1a52-9b06-4d3f-8a71-25c0e9f4b183/simulate-activation \
  -H "X-API-Public-Key: pk_live_7dc2a1..." \
  -H "X-API-Secret-Key: sk_live_9f4b83..." \
  -H "Idempotency-Key: simulateMandateActivation-01"
{
  "status": 200,
  "success": true,
  "message": "Mandate activated (simulated)",
  "data": {
    "accountNumber": "string",
    "activatedAt": "2026-09-03T14:22:08Z",
    "amountKobo": 45000000,
    "authorizationUrl": "https://storage.myitura.com/offers/7c4e.pdf",
    "bankCode": "string",
    "borrowerId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "createdAt": "2026-09-03T14:22:08Z",
    "email": "adaeze.okonkwo@example.com",
    "id": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "loanId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "organisationId": "b1d7e0a4-2c93-4f18-a6b5-7e1c9d3f2048",
    "provider": "paystack",
    "reference": "string",
    "status": "initiated",
    "updatedAt": "2026-09-03T14:22:08Z"
  }
}