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.
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.
| Header | Value |
|---|---|
| X-API-Public-Key | Your public key. Safe to log. |
| X-API-Secret-Key | Your secret key. Server side only, never in a browser or a mobile app. |
| Authorization | Alternative 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.
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.
{
"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.
| Status | Meaning | What to do |
|---|---|---|
| 400 | Malformed body or an unparseable field. | Fix and resend. Retrying unchanged will not help. |
| 401 | Missing, unknown or revoked key pair. | Check the header names and the key mode. |
| 403 | Your 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. |
| 404 | The record does not exist, or belongs to another tenant. | We answer 404 rather than 403 across tenants so ids cannot be probed. |
| 409 | The loan is not in a state that allows this transition. | Re-read the loan and act on its current status. |
| 422 | Well-formed but invalid, such as a rate above your tenant cap. | error names the offending field. |
| 429 | Rate 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.
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
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.
curl -O https://myitura.com/api-docs/lending-v1.json
# Postman: Import > File > lending-v1.json
# then set the collection variables
# publicKey and secretKeyList 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 a loan product
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan product id. |
Response
| Field | Description |
|---|---|
| approvalModeApprovalMode | Who 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 |
| capitalPoolCodestring | Funding pool this product draws from. |
| codestring | Unique per organisation. |
| createdAtstring (date-time) | |
| currencystring | |
| descriptionstring | |
| idstring (uuid) | |
| insuranceModeInsuranceMode | Loan-insurance behaviour for the product. automaticmanualoff |
| insurancePremiumBearerInsurancePremiumBearer | Who pays the insurance premium. borrowertenant |
| insurancePremiumBpsinteger | Insurance premium as basis points of principal. |
| interestModelInterestModel | Interest calculation method. flatreducing_balance |
| interestRateBpsinteger | Annual nominal interest rate in basis points (pro-rated by tenor at pricing time). |
| isActiveboolean | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| lateFeeBpsinteger | |
| maxAmountKobointeger | Amount in kobo (NGN minor unit). |
| maxTenorDaysinteger | |
| minAmountKobointeger | Amount in kobo (NGN minor unit). |
| minTenorDaysinteger | |
| namestring | |
| organisationIdstring (uuid) | |
| processingFeeBpsinteger | Processing fee as basis points of principal. |
| processingFeeFlatKobointeger | Fixed processing fee in kobo. |
| recoveryEnabledboolean | |
| recoveryPolicyIdstring (uuid) | |
| settlementCatalogEnabledboolean | Merchant/service catalog step (only for merchant_wallet). |
| settlementDestinationSettlementDestination | Where 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 a borrower
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Borrower id. |
Response
| Field | Description |
|---|---|
| clientReferencestring | The tenant's own identifier for this borrower. |
| createdAtstring (date-time) | |
| emailstring (email) | |
| firstNamestring | |
| idstring (uuid) | |
| identityStatusBorrowerIdentityStatus | Whether 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"
}
}List pre-approvals
Query
| Parameter | Description |
|---|---|
| statusquery · PreapprovalStatus | |
| limitquery · integer | Defaults to 50. |
Response
| Field | Description |
|---|---|
| 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"
}
]
}
}Push a pre-approved credit decision
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
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
| Field | Description |
|---|---|
| borrowerrequiredobject | |
| decisionrequiredobject | Your 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. |
| clientReferencestring | Your reference for this push. |
| enrichedobject | Your Cortex enriched payload, verbatim (optional). |
| providerIdstring (uuid) | Optional healthcare provider id from GET /v1/providers (record-only). |
Response
| Field | Description |
|---|---|
| approvedAmountKobointeger | |
| assessmentIdstring | |
| borrowerIdstring (uuid) | |
| expiresAtstring (date-time) | |
| preapprovalIdstring (uuid) | |
| recommendationstring | |
| statusPreapprovalStatus | Lifecycle 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
| Yours | Becomes | Conversion |
|---|---|---|
| approved_amount | approvedAmountKobo | Naira to kobo at ingest. |
| conditions.interest_rate | interestRateBps | Percent to basis points. Checked against your tenant rate cap. |
| metadata.assessment_id | assessmentId | The idempotency key for this push. |
| metadata.bvn | Identity match only | Hashed, then scrubbed. We never store it in the clear. |
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 a pre-approval
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) |
Response
| Field | Description |
|---|---|
| approvedAmountKobointeger | decision.approved_amount (naira) converted to kobo at ingest. |
| assessmentIdstring | Your 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) | |
| interestRateBpsinteger | decision.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). |
| recommendationstring | decision.recommendation as pushed (lower-cased), e.g. approve | decline. |
| repaymentFrequencystring | |
| riskBandstring | |
| statusPreapprovalStatus | Lifecycle 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"
}
}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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) |
Body
| Field | Description |
|---|---|
| productIdstring (uuid) | Loan product to issue against. Defaults to the tenant's configured preapprovalDefaultProductId. The product's approval mode must be partner_pushed. |
Response
| Field | Description |
|---|---|
| activeMandateIdstring (uuid) | |
| amountPaidKobointeger | Amount in kobo (NGN minor unit). |
| amountRequestedKobointeger | Requested amount in kobo. |
| applicationUrlstring | Hosted borrower checkout URL, when applicable. |
| approvalModeApprovalMode | Who 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) | |
| clientReferencestring | Tenant free-form reference, echoed in webhooks. |
| createdAtstring (date-time) | |
| currencystring | |
| disbursedAmountKobointeger | Amount in kobo (NGN minor unit). |
| disbursedAtstring (date-time) | |
| disbursementReferencestring | |
| hasActiveMandateboolean | |
| idstring (uuid) | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| loanProductIdstring (uuid) | |
| metadataobject | Tenant 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) | |
| outstandingKobointeger | Total still owed (principal + cost of credit - paid). |
| pricingSnapshotIdstring (uuid) | Immutable pricing snapshot reference; null until approval. |
| principalBalanceKobointeger | Amount in kobo (NGN minor unit). |
| principalKobointeger | Approved principal in kobo (== requested unless re-priced). |
| rejectionReasonstring | |
| settlementDestinationSettlementDestination | Where disbursed funds go. borrower_walletborrower_bank_accountmerchant_wallettenant_wallet |
| statusLoanStatus | Loan 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"
}
}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
| Field | Description |
|---|---|
| acceptedByBorrowerinteger | |
| approvedAmountKobointeger | Total credit pushed as approved. |
| awaitingOfferinteger | Approved and stored, offer not yet issued. |
| declinedByBorrowerinteger | Borrower turned the issued offer down. |
| declinedByPartnerinteger | Pushed as a decline; never became a loan. |
| disbursedinteger | |
| disbursedAmountKobointeger | Total principal actually released. |
| expiredinteger | Lapsed before being taken up. |
| offerIssuedinteger | Offer letter out, awaiting the borrower. |
| outstandingKobointeger | Still owed on those loans. |
| pushedinteger | Every decision received, declines included. |
| repaidAmountKobointeger | Total 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
}
}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
| Parameter | Description |
|---|---|
| receiveTestquery · boolean | Narrow to laboratories (only true is honoured). |
| receiveDrugquery · boolean | Narrow to pharmacies (only true is honoured). |
| namequery · string | Filter by provider name (partial match). |
| locationquery · string | Filter by state, LGA, city or address (partial match). |
| sort_byquery · string | Defaults to name.namecodecreated_atupdated_at |
| sort_orderquery · string | Defaults to asc.ascdesc |
| pagequery · integer | Defaults to 1. |
| limitquery · integer | Defaults to 20. |
Response
| Field | Description |
|---|---|
| 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"
}
]
}
}List loans
Query
| Parameter | Description |
|---|---|
| statusquery · string | Filter by loan status. pendingkyc_requiredkyc_pendingkyc_completedattestedunder_reviewapprovedrejectedawaiting_acceptanceterms_acceptedterms_declineddisbursedactivecompleteddefaultedcancelled |
| limitquery · integer | Maximum 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 a loan
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Response
| Field | Description |
|---|---|
| activeMandateIdstring (uuid) | |
| amountPaidKobointeger | Amount in kobo (NGN minor unit). |
| amountRequestedKobointeger | Requested amount in kobo. |
| applicationUrlstring | Hosted borrower checkout URL, when applicable. |
| approvalModeApprovalMode | Who 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) | |
| clientReferencestring | Tenant free-form reference, echoed in webhooks. |
| createdAtstring (date-time) | |
| currencystring | |
| disbursedAmountKobointeger | Amount in kobo (NGN minor unit). |
| disbursedAtstring (date-time) | |
| disbursementReferencestring | |
| hasActiveMandateboolean | |
| idstring (uuid) | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| loanProductIdstring (uuid) | |
| metadataobject | Tenant 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) | |
| outstandingKobointeger | Total still owed (principal + cost of credit - paid). |
| pricingSnapshotIdstring (uuid) | Immutable pricing snapshot reference; null until approval. |
| principalBalanceKobointeger | Amount in kobo (NGN minor unit). |
| principalKobointeger | Approved principal in kobo (== requested unless re-priced). |
| rejectionReasonstring | |
| settlementDestinationSettlementDestination | Where disbursed funds go. borrower_walletborrower_bank_accountmerchant_wallettenant_wallet |
| statusLoanStatus | Loan 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"
}
}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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| consentrequiredBorrowerConsent | What 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
| Field | Description |
|---|---|
| activeMandateIdstring (uuid) | |
| amountPaidKobointeger | Amount in kobo (NGN minor unit). |
| amountRequestedKobointeger | Requested amount in kobo. |
| applicationUrlstring | Hosted borrower checkout URL, when applicable. |
| approvalModeApprovalMode | Who 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) | |
| clientReferencestring | Tenant free-form reference, echoed in webhooks. |
| createdAtstring (date-time) | |
| currencystring | |
| disbursedAmountKobointeger | Amount in kobo (NGN minor unit). |
| disbursedAtstring (date-time) | |
| disbursementReferencestring | |
| hasActiveMandateboolean | |
| idstring (uuid) | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| loanProductIdstring (uuid) | |
| metadataobject | Tenant 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) | |
| outstandingKobointeger | Total still owed (principal + cost of credit - paid). |
| pricingSnapshotIdstring (uuid) | Immutable pricing snapshot reference; null until approval. |
| principalBalanceKobointeger | Amount in kobo (NGN minor unit). |
| principalKobointeger | Approved principal in kobo (== requested unless re-priced). |
| rejectionReasonstring | |
| settlementDestinationSettlementDestination | Where disbursed funds go. borrower_walletborrower_bank_accountmerchant_wallettenant_wallet |
| statusLoanStatus | Loan 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"
}
}Approve a loan
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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| notesstring | Optional approval notes (approve). |
| reasonstring | Rejection reason (reject). |
Response
| Field | Description |
|---|---|
| activeMandateIdstring (uuid) | |
| amountPaidKobointeger | Amount in kobo (NGN minor unit). |
| amountRequestedKobointeger | Requested amount in kobo. |
| applicationUrlstring | Hosted borrower checkout URL, when applicable. |
| approvalModeApprovalMode | Who 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) | |
| clientReferencestring | Tenant free-form reference, echoed in webhooks. |
| createdAtstring (date-time) | |
| currencystring | |
| disbursedAmountKobointeger | Amount in kobo (NGN minor unit). |
| disbursedAtstring (date-time) | |
| disbursementReferencestring | |
| hasActiveMandateboolean | |
| idstring (uuid) | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| loanProductIdstring (uuid) | |
| metadataobject | Tenant 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) | |
| outstandingKobointeger | Total still owed (principal + cost of credit - paid). |
| pricingSnapshotIdstring (uuid) | Immutable pricing snapshot reference; null until approval. |
| principalBalanceKobointeger | Amount in kobo (NGN minor unit). |
| principalKobointeger | Approved principal in kobo (== requested unless re-priced). |
| rejectionReasonstring | |
| settlementDestinationSettlementDestination | Where disbursed funds go. borrower_walletborrower_bank_accountmerchant_wallettenant_wallet |
| statusLoanStatus | Loan 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) |
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.
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"
}
}Submit a KYC attestation
Records a delegated-KYC (Tier A) attestation for the loan's borrower and triggers MyItura's independent AML screen.
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| attestedChecksobject | The checks performed, e.g. {"bvn_verified": true, "id_type": "nin", "id_last4": "1234", "credit_check": {...}}. |
| schemaVersioninteger | Defaults to 1. |
Response
| Field | Description |
|---|---|
| amlScreenDetailstring | |
| amlScreenStatusAMLScreenStatus | Outcome of MyItura's independent AML/sanctions screen. pendingclearhit |
| amlScreenedAtstring (date-time) | |
| attestedAtstring (date-time) | |
| attestedByKeystring | Masked public key of the attesting credential. |
| attestedChecksobject | The attested checks payload, e.g. {"bvn_verified": true, "id_type": "nin", "id_last4": "1234", "credit_check": {...}}. |
| auditOutcomestring | pending | 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"
}
}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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| reasonstring | Why 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"
}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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) |
Body
| Field | Description |
|---|---|
| consentrequiredBorrowerConsent | What 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. |
| reasonstring | Optional reason the borrower gave. |
Response
| Field | Description |
|---|---|
| activeMandateIdstring (uuid) | |
| amountPaidKobointeger | Amount in kobo (NGN minor unit). |
| amountRequestedKobointeger | Requested amount in kobo. |
| applicationUrlstring | Hosted borrower checkout URL, when applicable. |
| approvalModeApprovalMode | Who 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) | |
| clientReferencestring | Tenant free-form reference, echoed in webhooks. |
| createdAtstring (date-time) | |
| currencystring | |
| disbursedAmountKobointeger | Amount in kobo (NGN minor unit). |
| disbursedAtstring (date-time) | |
| disbursementReferencestring | |
| hasActiveMandateboolean | |
| idstring (uuid) | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| loanProductIdstring (uuid) | |
| metadataobject | Tenant 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) | |
| outstandingKobointeger | Total still owed (principal + cost of credit - paid). |
| pricingSnapshotIdstring (uuid) | Immutable pricing snapshot reference; null until approval. |
| principalBalanceKobointeger | Amount in kobo (NGN minor unit). |
| principalKobointeger | Approved principal in kobo (== requested unless re-priced). |
| rejectionReasonstring | |
| settlementDestinationSettlementDestination | Where disbursed funds go. borrower_walletborrower_bank_accountmerchant_wallettenant_wallet |
| statusLoanStatus | Loan 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"
}
}Disburse a loan
Releases funds from your capital pool to the product's settlement destination and generates the repayment schedule.
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Response
| Field | Description |
|---|---|
| activeMandateIdstring (uuid) | |
| amountPaidKobointeger | Amount in kobo (NGN minor unit). |
| amountRequestedKobointeger | Requested amount in kobo. |
| applicationUrlstring | Hosted borrower checkout URL, when applicable. |
| approvalModeApprovalMode | Who 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) | |
| clientReferencestring | Tenant free-form reference, echoed in webhooks. |
| createdAtstring (date-time) | |
| currencystring | |
| disbursedAmountKobointeger | Amount in kobo (NGN minor unit). |
| disbursedAtstring (date-time) | |
| disbursementReferencestring | |
| hasActiveMandateboolean | |
| idstring (uuid) | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| loanProductIdstring (uuid) | |
| metadataobject | Tenant 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) | |
| outstandingKobointeger | Total still owed (principal + cost of credit - paid). |
| pricingSnapshotIdstring (uuid) | Immutable pricing snapshot reference; null until approval. |
| principalBalanceKobointeger | Amount in kobo (NGN minor unit). |
| principalKobointeger | Approved principal in kobo (== requested unless re-priced). |
| rejectionReasonstring | |
| settlementDestinationSettlementDestination | Where disbursed funds go. borrower_walletborrower_bank_accountmerchant_wallettenant_wallet |
| statusLoanStatus | Loan 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"
}
}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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| bvnrequiredstring | Bank Verification Number, exactly 11 digits. Required: it is what ties the borrower to bureau data, so a NIN does not substitute for it. |
| addressstring | |
| dateOfBirthstring | The borrower's date of birth, passed to the provider as part of the check. |
| ninstring | National Identification Number, if the borrower has one. Length-ranged rather than pinned at 11 because a NIN may carry a suffix. |
Response
| Field | Description |
|---|---|
| documentsarray of object | |
| loanStatusstring | The 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 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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) |
Response
| Field | Description |
|---|---|
| documentReferencestring | Identifies 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"
}
}Reject a loan
Rejects the loan (terminal).
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| notesstring | Optional approval notes (approve). |
| reasonstring | Rejection reason (reject). |
Response
| Field | Description |
|---|---|
| activeMandateIdstring (uuid) | |
| amountPaidKobointeger | Amount in kobo (NGN minor unit). |
| amountRequestedKobointeger | Requested amount in kobo. |
| applicationUrlstring | Hosted borrower checkout URL, when applicable. |
| approvalModeApprovalMode | Who 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) | |
| clientReferencestring | Tenant free-form reference, echoed in webhooks. |
| createdAtstring (date-time) | |
| currencystring | |
| disbursedAmountKobointeger | Amount in kobo (NGN minor unit). |
| disbursedAtstring (date-time) | |
| disbursementReferencestring | |
| hasActiveMandateboolean | |
| idstring (uuid) | |
| kycTierKYCTier | Who performs KYC: delegated (tenant attests, Tier A) or managed (MyItura runs KYC, Tier B). delegatedmanaged |
| loanProductIdstring (uuid) | |
| metadataobject | Tenant 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) | |
| outstandingKobointeger | Total still owed (principal + cost of credit - paid). |
| pricingSnapshotIdstring (uuid) | Immutable pricing snapshot reference; null until approval. |
| principalBalanceKobointeger | Amount in kobo (NGN minor unit). |
| principalKobointeger | Approved principal in kobo (== requested unless re-priced). |
| rejectionReasonstring | |
| settlementDestinationSettlementDestination | Where disbursed funds go. borrower_walletborrower_bank_accountmerchant_wallettenant_wallet |
| statusLoanStatus | Loan 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 the loan's repayment schedule
Path
| Parameter | Description |
|---|---|
| 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?
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.
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.
# 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" }{
"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"
}
}Create a direct-debit mandate
Initiates a direct-debit mandate for the loan's borrower. The borrower authorises via the returned authorizationUrl.
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| emailrequiredstring (email) | Borrower email used for the provider authorisation. |
| accountNumberstring | |
| bankCodestring | |
| callbackUrlstring (uri) | Where the borrower is redirected after authorising. |
| providerstring | The 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
| Field | Description |
|---|---|
| accountNumberstring | |
| activatedAtstring (date-time) | |
| amountKobointeger | Amount in kobo (NGN minor unit). |
| authorizationUrlstring | Borrower authorisation URL (hosted by the provider). |
| bankCodestring | |
| borrowerIdstring (uuid) | |
| createdAtstring (date-time) | |
| emailstring (email) | |
| idstring (uuid) | |
| loanIdstring (uuid) | |
| organisationIdstring (uuid) | |
| providerMandateProvider | The 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 a mandate
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Mandate id. |
Response
| Field | Description |
|---|---|
| accountNumberstring | |
| activatedAtstring (date-time) | |
| amountKobointeger | Amount in kobo (NGN minor unit). |
| authorizationUrlstring | Borrower authorisation URL (hosted by the provider). |
| bankCodestring | |
| borrowerIdstring (uuid) | |
| createdAtstring (date-time) | |
| emailstring (email) | |
| idstring (uuid) | |
| loanIdstring (uuid) | |
| organisationIdstring (uuid) | |
| providerMandateProvider | The 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"
}
}Activate a mandate
Verifies the borrower's authorisation with the provider and activates the mandate. Supplying authorizationCode uses the sandbox/test path.
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Mandate id. |
Response
| Field | Description |
|---|---|
| accountNumberstring | |
| activatedAtstring (date-time) | |
| amountKobointeger | Amount in kobo (NGN minor unit). |
| authorizationUrlstring | Borrower authorisation URL (hosted by the provider). |
| bankCodestring | |
| borrowerIdstring (uuid) | |
| createdAtstring (date-time) | |
| emailstring (email) | |
| idstring (uuid) | |
| loanIdstring (uuid) | |
| organisationIdstring (uuid) | |
| providerMandateProvider | The 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) |
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"
}
}List the loan's repayments
Path
| Parameter | Description |
|---|---|
| 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"
}
]
}Record a repayment
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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Body
| Field | Description |
|---|---|
| amountKoborequiredinteger | Amount in kobo (NGN minor unit). |
| methodrequiredRepaymentMethod | How 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 |
| externalReferencestring | Your collection reference (method=external). |
Response
| Field | Description |
|---|---|
| amountKobointeger | Amount in kobo (NGN minor unit). |
| borrowerIdstring (uuid) | |
| completedAtstring (date-time) | |
| createdAtstring (date-time) | |
| externalReferencestring | Tenant's off-platform collection reference (method=external). |
| feePortionKobointeger | Amount in kobo (NGN minor unit). |
| idstring (uuid) | |
| interestPortionKobointeger | Amount in kobo (NGN minor unit). |
| ledgerTransactionRefstring | |
| loanIdstring (uuid) | |
| methodRepaymentMethod | How 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) | |
| principalPortionKobointeger | Amount in kobo (NGN minor unit). |
| referencestring | System-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.
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 the loan's insurance policy
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Loan id. |
Response
| Field | Description |
|---|---|
| commissionKobointeger | The platform's share of the premium. |
| createdAtstring (date-time) | |
| errorMessagestring | |
| idstring (uuid) | |
| loanIdstring (uuid) | |
| organisationIdstring (uuid) | |
| policyReferencestring | |
| premiumBearerInsurancePremiumBearer | Who pays the insurance premium. borrowertenant |
| premiumKobointeger | Amount 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"
}
}List payout requests
Query
| Parameter | Description |
|---|---|
| statusquery · string | Filter 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"
}
]
}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
| Field | Description |
|---|---|
| accountNumberrequiredstring | |
| amountKoborequiredinteger | Amount in kobo (NGN minor unit). |
| bankCoderequiredstring | |
| bankNamerequiredstring | |
| borrowerIdrequiredstring (uuid) | |
| accountNamestring | |
| loanIdstring (uuid) |
Response
| Field | Description |
|---|---|
| accountNamestring | |
| accountNumberstring | |
| amountKobointeger | Amount 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 a payout request
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Payout request id. |
Response
| Field | Description |
|---|---|
| accountNamestring | |
| accountNumberstring | |
| amountKobointeger | Amount 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"
}
}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 a settlement statement
Path
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Settlement statement id. |
Response
| Field | Description |
|---|---|
| createdAtstring (date-time) | |
| failureReasonstring | |
| feeSweptKobointeger | Amount in kobo (NGN minor unit). |
| idstring (uuid) | |
| interestSweptKobointeger | Amount in kobo (NGN minor unit). |
| linesarray of SettlementLine | |
| organisationIdstring (uuid) | |
| periodEndstring (date-time) | |
| periodStartstring (date-time) | |
| statusSettlementStatementStatus | completedskippedfailed |
| totalSweptKobointeger | Amount 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"
}
}Download a settlement statement as CSV
Path
| Parameter | Description |
|---|---|
| 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 your API usage rollup
Your organisation's daily API-usage rollup (the metering/billing feed).
Query
| Parameter | Description |
|---|---|
| daysquery · integer | How 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.
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
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.
{
"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.List webhook deliveries
Your organisation's recent webhook delivery log, newest first.
Query
| Parameter | Description |
|---|---|
| limitquery · integer | Maximum 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"
}
]
}Redeliver a webhook event
Requeues a delivery for another attempt (e.g. after fixing your receiver).
Path
| Parameter | Description |
|---|---|
| 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"
}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"
}
]
}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
| Field | Description |
|---|---|
| urlrequiredstring (uri) | |
| descriptionstring | |
| eventsarray of string | Event names to subscribe to; omit or send empty for all events. |
| modestring | Defaults to live.livetest |
Response
| Field | Description |
|---|---|
| endpointWebhookEndpoint | A registered webhook destination. The signing secret is returned once on creation and never serialised again. |
| signingSecretstring | The 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_..."
}
}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
| Parameter | Description |
|---|---|
| idrequiredpath · string (uuid) | Mandate id. |
Response
| Field | Description |
|---|---|
| accountNumberstring | |
| activatedAtstring (date-time) | |
| amountKobointeger | Amount in kobo (NGN minor unit). |
| authorizationUrlstring | Borrower authorisation URL (hosted by the provider). |
| bankCodestring | |
| borrowerIdstring (uuid) | |
| createdAtstring (date-time) | |
| emailstring (email) | |
| idstring (uuid) | |
| loanIdstring (uuid) | |
| organisationIdstring (uuid) | |
| providerMandateProvider | The 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) |
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"
}
}