Developer Platform
v2.4.0 REST · JSON
Developer Platform REST API v2
All systems operational

Build on the
Sodlapp
Lending API

Full programmatic access to the Sodlapp loan management platform — create borrowers, book loans, post repayments, pull analytics, and automate your entire lending workflow.

Bearer Auth Rate Limiting Webhooks JSON Responses Pagination
POST /api/loans — Book a new loan LIVE
const response = await fetch('https://api.sodlapp.com/v2/loans', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_••••••••••••••',
    'Content-Type':  'application/json'
  },
  body: JSON.stringify({
    customer_id:   'cust_0kp4mB9zR',
    product_id:    'prod_civil_12m',
    amount:        500000,
    tenor_months:  12,
    disbursement:  'bank_transfer'
  })
});

const { data } = await response.json();
// → { loan_id: "ln_A8x4Rq7", status: "Approved",
//     emi: 46250, first_due: "2025-03-01" }
48endpoints
API Endpoints
99.98%
Uptime SLA
<80ms
Avg. Response
5SDKs
Official Libraries
Platform Capabilities

Everything the Sodlapp API exposes

Nine resource domains — each with full CRUD, filtering, pagination, and webhook support built in.

📋

Loan Origination

Create loan applications, run eligibility checks, trigger the multi-tier approval workflow, and receive approval/rejection webhooks.

👤

Customer Management

CRUD on customer records, KYC document uploads, BVN/NIN verification status, internal credit score retrieval, and communication logs.

💰

Repayments & Collections

Post single or bulk repayments, retrieve full EMI schedules, query overdue accounts by DPD bucket, and trigger receipt generation.

⚠️

Delinquency Engine

Query PAR 30/60/90/90+ buckets, flag accounts, apply penalty charges, waive fees with approval trail, and subscribe to overdue webhooks.

🏛️

MDA & Branch Data

Pull portfolio exposure by ministry, branch, or sector. Supports drill-down filtering, league table ordering, and Excel export links.

📊

Analytics & Reporting

Programmatic access to dashboards, disbursement vs collection charts, officer scorecards, and scheduled report configurations.

👥

Team Management

Create/update staff accounts, assign roles & privileges, manage branch assignments, and retrieve officer performance metrics.

🔔

Webhooks & Notifications

Subscribe to events — loan.approved, payment.received, loan.delinquent, kyc.expired — with HMAC-signed delivery and retry logic.

🔐

Roles & Audit Logs

Query the role manifest, manage privilege assignments, pull full tamper-evident audit logs with actor, timestamp, and IP filtering.

API Reference

Core Endpoints

All endpoints are prefixed with https://api.sodlapp.com/v2. All responses return {"success": bool, "data": ..., "meta": ...}.

Base URL All requests must include the Authorization: Bearer {api_key} header. Sandbox environment: https://sandbox.api.sodlapp.com/v2 — data does not affect production.

LOANS

GET/loansList loans w/ filters
POST/loansBook new loan
GET/loans/{loan_id}Retrieve single loan
PUT/loans/{loan_id}Update / restructure
POST/loans/{loan_id}/approveApprove & disburse
POST/loans/{loan_id}/closeClose / write-off
GET/loans/{loan_id}/scheduleEMI repayment schedule
GET/loans/{loan_id}/timelineFull audit timeline

REPAYMENTS

POST/repaymentsRecord single repayment
POST/repayments/bulkBulk CSV / payroll upload
GET/repayments/{id}/receiptDownload PDF receipt
POST/repayments/reconcileBank statement reconcile

CUSTOMERS

GET/customersList customers
POST/customersCreate customer
GET/customers/{id}Customer + loan summary
PUT/customers/{id}Update customer record
POST/customers/{id}/kycUpload KYC document
GET/customers/{id}/credit-scoreInternal credit score

ANALYTICS

GET/analytics/dashboardExecutive KPI overview
GET/analytics/parPAR 30/60/90/90+ ratios
GET/analytics/mdaMinistry portfolio view
GET/analytics/officers/{id}Officer scorecard

↓ Endpoint Detail — click to expand

POST /loans Book a new loan

Creates a new loan record in Draft status for the given customer and loan product. The response includes the computed EMI and the generated repayment schedule dates. Triggers an approval.pending webhook if auto-submit is enabled.

customer_idstringRequiredSodlapp customer ID (prefix cust_). Borrower must have valid KYC status.
product_idstringRequiredLoan product template ID. Sets default interest rate and max tenor.
amountnumberRequiredPrincipal amount in Naira (kobo-free integer). Must be within product min/max bounds.
tenor_monthsnumberRequiredLoan tenor in months. Cannot exceed product's max_tenor.
disbursementstringOptionalbank_transfer | cash | cheque. Defaults to bank_transfer.
officer_idstringOptionalAssign to a specific loan officer. Defaults to the authenticated user's team ID.
POST /loans — responseJSON
{
  "success": true,
  "data": {
    "loan_id":    "ln_A8x4Rq7mZ",
    "status":     "Draft",
    "amount":     500000,
    "emi":        46250,
    "first_due":  "2025-03-01",
    "schedule_url": "https://api.sodlapp.com/v2/loans/ln_A8x4Rq7mZ/schedule"
  }
}
POST /repayments/bulk Bulk payroll upload

Upload a payroll deduction CSV and post multiple repayments in a single batch. The API auto-matches each row to a loan by IPPS number, previews matched/unmatched rows, and returns a reconciliation summary. No payments are posted until confirm: true is passed.

filemultipartRequiredCSV file. Required columns: ipps_number, amount, payment_date.
confirmbooleanOptionalDefault false (preview mode). Pass true to commit and post all matched rows.
branch_idstringOptionalRestrict matching to loans belonging to this branch only.
POST /repayments/bulk — preview responseJSON
{
  "success": true,
  "data": {
    "rows_total":     142,
    "rows_matched":   138,
    "rows_unmatched": 4,
    "total_amount":   6450000,
    "confirmed":      false,
    "preview_id":     "prev_8Kx2mB9z"
  }
}
GET /analytics/par Portfolio at Risk ratios

Returns PAR ratios across all DPD buckets for the authenticated institution (or a specific branch). Includes total outstanding, count of delinquent loans, and the PAR percentage for each bucket. Computed in real-time from the current loan book.

branch_idstringOptionalFilter to a specific branch. Omit for institution-wide totals.
as_ofstringOptionalDate string YYYY-MM-DD. Compute PAR as of a historical date. Defaults to today.
GET /analytics/par — responseJSON
{
  "success": true,
  "data": {
    "as_of":            "2025-02-28",
    "portfolio_total":   148600000,
    "par_30":   { "ratio": 0.112, "outstanding": 16643200, "count": 24 },
    "par_60":   { "ratio": 0.068, "outstanding": 10104800, "count": 14 },
    "par_90":   { "ratio": 0.031, "outstanding": 4606600,  "count": 6 },
    "par_90plus":{ "ratio": 0.009, "outstanding": 1337400,  "count": 2 }
  }
}
Authentication

API Keys & Bearer Auth

Sodlapp uses API key authentication via the standard Authorization: Bearer header. Keys are scoped by environment and permission level.

1Generate API Key
2Add to request header
3Server validates key
4Permissions checked
5Response returned
Authorization headerHTTP
GET /v2/loans HTTP/1.1
Host: api.sodlapp.com
Authorization: Bearer sk_live_4Bk9mNzRxP2qYwVcD7aLtJ0eH
Content-Type: application/json
Accept: application/json
Key TypePrefixScopePermissions
Live Keysk_live_ProductionFull read/write on all permitted endpoints
Sandbox Keysk_test_SandboxFull read/write, isolated test data, no real transactions
Read-Only Keysk_ro_ProductionGET requests only. No create/update/delete. Safe for analytics pipelines.
Webhook Secretwhsec_WebhookUsed only for HMAC signature verification of incoming webhook payloads.
Never expose live keys client-side API keys grant full account access. Use environment variables and server-side request proxying. If a key is compromised, rotate it immediately from the Sodlapp admin panel — old keys are invalidated within 60 seconds.

Rate Limits

PlanRequests / minBurst limitBulk endpoint
Starter60 / min80 burst500 rows/batch
Growth300 / min400 burst2,000 rows/batch
EnterpriseCustomNegotiatedUnlimited
Rate limit headers Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. When the limit is exceeded, a 429 Too Many Requests is returned with a Retry-After value in seconds.
Webhooks

Real-time Event Delivery

Subscribe to platform events and receive signed HTTP POST payloads to your endpoint within milliseconds of event occurrence.

loan.created loan.approved loan.disbursed loan.closed loan.delinquent payment.received payment.bulk_posted kyc.submitted kyc.verified kyc.expired team.created report.ready
Webhook payload — loan.approvedJSON
{
  "event":     "loan.approved",
  "id":        "evt_7Xk2pQ4nM",
  "created":   "2025-02-28T14:32:11Z",
  "livemode":  true,
  "data": {
    "loan_id":    "ln_A8x4Rq7mZ",
    "customer_id":"cust_0kp4mB9zR",
    "amount":     500000,
    "status":     "Approved",
    "approved_by":"team_4Jx9kR"
  }
}
Webhook signature verification (Node.js)JavaScript
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return `sha256=${expected}` === signature;
}

// In your handler:
const sig = req.headers['x-sodlapp-signature'];
if (!verifyWebhook(req.rawBody, sig, process.env.WEBHOOK_SECRET)) {
  return res.status(401).send('Unauthorized');
}
Official Libraries

SDKs & Client Libraries

Drop-in libraries for the most popular runtimes. All SDKs are open-source, actively maintained, and automatically generated from the OpenAPI spec.

JS
JavaScript / Node.js
v2.4.0 · MIT License
Works in Node.js 16+ and all modern browsers. TypeScript typings included. Promise-based with full async/await support.
Py
Python
v2.4.0 · MIT License
Python 3.8+ compatible. Sync and async clients available. Full type hints throughout. Works with FastAPI and Django.
Java / Kotlin
v2.3.1 · Apache 2.0
Maven and Gradle compatible. Works with Spring Boot. Kotlin extensions included for idiomatic usage.
PHP
PHP
v2.4.0 · MIT License
PHP 8.0+ with PSR-4 autoloading. Composer-installable. Works out of the box with Laravel and Symfony.
Go
Go
v2.4.0 · MIT License
Idiomatic Go SDK with context support, automatic retries, and zero external dependencies beyond the standard library.
+
More coming soon
Ruby · Swift · .NET
Ruby, Swift, and .NET SDKs are currently in development. All generated from the OpenAPI 3.1 specification.
Quick start — Node.js SDKJavaScript
import { Sodlapp } from '@sodlapp/sdk';

const client = new Sodlapp({
  apiKey: process.env.SODLAPP_API_KEY,
  env: 'live' // or 'sandbox'
});

// Book a loan
const loan = await client.loans.create({
  customer_id:  'cust_0kp4mB9zR',
  product_id:   'prod_civil_12m',
  amount:       500_000,
  tenor_months: 12
});

// Post a repayment
await client.repayments.create({
  loan_id: loan.data.loan_id,
  amount:  46_250
});

// Pull PAR analytics
const par = await client.analytics.par.get();
console.log(`PAR30: ${(par.data.par_30.ratio * 100).toFixed(1)}%`);
Error Handling

Error Codes & Responses

All errors follow a consistent structure with machine-readable error codes and human-readable messages.

Error response envelopeJSON
{
  "success": false,
  "error": {
    "code":    "LOAN_AMOUNT_EXCEEDS_LIMIT",
    "message": "Requested amount ₦800,000 exceeds product maximum of ₦600,000",
    "field":   "amount",     // present on validation errors
    "status":  422
  }
}
HTTP StatusError CodeDescription
400INVALID_REQUESTMalformed JSON or missing required fields
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENKey lacks permission for this action
404NOT_FOUNDResource with given ID does not exist
409CONFLICTDuplicate resource (e.g. email already exists)
422VALIDATION_ERRORField-level validation failure — see field in response
429RATE_LIMITEDToo many requests. Check Retry-After header.
500INTERNAL_ERRORServer error — automatically logged and alerted to our team
Changelog

API Version History

All breaking changes are announced 90 days in advance. Non-breaking additions are added without versioning.

v2
v2.4.0 — Latest
28 February 2025
NewAdded GET /analytics/par with historical as_of parameter for trend analysis
NewWebhook events: loan.delinquent, kyc.expired, report.ready
NewBulk repayment preview mode — confirm: false returns reconciliation summary without posting
FixFixed race condition in concurrent bulk upload + reconcile requests
v2
v2.3.0
15 January 2025
NewGET /customers/{id}/credit-score — programmatic access to internal risk scoring
NewBranch-level rate limit overrides for Enterprise plans
FixPagination cursor now stable across concurrent inserts on GET /loans
Deploan_type field deprecated — use product_id instead. Removed in v3.
v2
v2.0.0
1 October 2024
BreakResource ID format changed from integer to prefixed string (cust_, ln_, team_)
BreakAll money values now in Naira integer (no kobo decimals) — affects all amount fields
NewWebhook system launched with HMAC signature verification
NewSandbox environment with isolated test data and free-tier access
v1
v1.x (Legacy)
Deprecated — EOL 1 July 2025
Depv1 API is in maintenance mode. No new features will be added. Migrate to v2.
DepMigration guide available at docs.sodlapp.com/migrate-v1-v2.