Embedded borrower self-service APIs.
Partner-authenticated APIs for embedding borrower self-service: profile, loans, repayments, savings, and documents, without staff JWT sessions.
Base URL
https://{host}/api/v1/{tenant_slug}/partner/v1
Header on every call:
X-API-Key: clfy_test_xxxxxxxx
Scopes: Portal write flows need * or scopes that include portal/client/loan access. A read-only key (e.g. loans:read only) will return 403 on POST /portal/loans/apply.
Borrower scope
Portal routes act on a specific borrower. In live mode pass either:
X-Client-Id: {client_uuid}
or ?client_id={client_uuid}.
In test mode the API uses deterministic mock borrower fixtures (Ada Okello); X-Client-Id is optional.
Core flows
Profile
curl -sS -H "X-API-Key: $API_KEY" -H "X-Client-Id: $CLIENT_ID" \
"$BASE/portal/profile"
Apply for a loan
With a test key, use sandbox product UUID 00000000-0000-4000-8000-000000000030.
With a live key, use a real loan product ID from your tenant (must be portal-visible if your tenant restricts portal products).
curl -sS -X POST -H "X-API-Key: $API_KEY" -H "X-Client-Id: $CLIENT_ID" \
-H "Content-Type: application/json" \
-d '{
"product_id": "00000000-0000-4000-8000-000000000030",
"applied_amount": 5000,
"term_days": 90,
"purpose": "Working capital"
}' \
"$BASE/portal/loans/apply"
Tenants with required loan custom fields may also need custom_field_values in the body.
My loans, repayments, savings, documents
curl -sS -H "X-API-Key: $API_KEY" -H "X-Client-Id: $CLIENT_ID" \
"$BASE/portal/loans"
curl -sS -H "X-API-Key: $API_KEY" -H "X-Client-Id: $CLIENT_ID" \
"$BASE/portal/repayments"
curl -sS -H "X-API-Key: $API_KEY" -H "X-Client-Id: $CLIENT_ID" \
"$BASE/portal/savings"
curl -sS -H "X-API-Key: $API_KEY" -H "X-Client-Id: $CLIENT_ID" \
"$BASE/portal/documents"
Repayments are read-only on the portal (GET /portal/repayments). Record repayments via POST /repayments on the platform API (staff workflow must disburse the loan first on live keys).
Postman
Import external/postman/02-client-portal.postman_collection.json and set baseUrl, tenantSlug, apiKey, productId, and (for live) clientId.
Integration lab
Run make partner-lab (external/sample-apps/) against a local tenant to exercise portal reads + apply with bootstrap keys that have * scopes.

