Integrating with Wynk Systems

One versioned HTTP API over the same domain packages the portals use. There is no second, weaker path into the core for integrations.

Credentials are issued during onboarding, per tenant and per environment. There is no public sandbox key on this page: a sandbox that anyone can reach is a sandbox that has to be defended, and we would rather give you a real one with your own tenant boundary.

Six rules that hold everywhere

Authentication is per request, and authority is never client-asserted

A caller presents a credential; the server resolves the tenant and the roles. A client cannot assert a role, a tenant, or a user id — those are derived server-side and any request that tries to supply them is refused.

Every money POST carries Idempotency-Key

A replay with the same key returns the ORIGINAL outcome marked already-processed. A replay with the same key and a different body is a conflict, not a second movement. Non-money writes accept the header and honour it the same way.

Amounts are integer minor units, always

Every amount field is named *_cents and carries an integer. There is no decimal amount and no implied scale. A currency travels with the amount; a bare number is refused.

Errors are a closed taxonomy

Every failure is one of a fixed set of wynk.* codes with a stable shape: code, message, and structured details. An integrator can exhaustively switch on the code, and a new failure mode does not invent a new string.

Reads are keyset-paginated

Collection endpoints return a cursor, not an offset. A page boundary is stable while the collection is being written to, which offset pagination cannot promise.

Webhooks are signed, ordered and replayable

Deliveries carry a signature over the canonical body, a delivery audit chain and a dead-letter queue. A consumer that was down replays from the last acknowledged delivery rather than losing the window.

The endpoints

Read surfaces are keyset-paginated. Every endpoint that moves money is marked, and every one of those requires an idempotency key.

Wynk Systems ecosystem API
EndpointWhat it doesClassReplay protection
GET /v1/dashboardTenant-scoped portfolio summaryRead or configuration
GET /v1/loansLoan facilities, keyset-paginatedRead or configuration
GET /v1/loans/:facilityIdOne facility with its schedule and arrears stateRead or configuration
POST /v1/loans/unsecuredOriginate an unsecured facility (NCA affordability enforced)Moves moneyIdempotency-Key required
POST /v1/loans/:facilityId/disburseDisburse a facility (two-eyes)Moves moneyIdempotency-Key required
GET /v1/walletsWallets and balances in minor unitsRead or configuration
GET /v1/wallets/:walletIdOne wallet with its holds and pocketsRead or configuration
POST /v1/walletsOpen a wallet against a ledger accountRead or configurationIdempotency-Key required
POST /v1/wallets/:walletId/depositCredit a wallet from a settled inboundMoves moneyIdempotency-Key required
POST /v1/wallets/:walletId/transferMove value between walletsMoves moneyIdempotency-Key required
GET /v1/vasVAS catalogue and transaction historyRead or configuration
POST /v1/vas/purchaseBuy airtime, data, electricity or a bill paymentMoves moneyIdempotency-Key required
POST /v1/payments/instructInstruct an outbound payment onto a railMoves moneyIdempotency-Key required
GET /v1/ledger/factsAccounting facts with their legsRead or configuration
GET /v1/accounting/factsFact stream for reconciliationRead or configuration
GET /v1/accounting/walk-back/:factIdWalk a fact back to its origin eventRead or configuration
GET /v1/accounting/legs/:legId/walk-backWalk a statement line back to its originRead or configuration
POST /v1/accounting/chart/ensureEnsure the chart of accounts for a tenantRead or configurationIdempotency-Key required
POST /v1/accounting/afs/:tenantId/generateGenerate annual financial statements for a frameworkRead or configurationIdempotency-Key required
POST /v1/chain/verifyRecompute the audit and ledger chains from originRead or configurationIdempotency-Key required
POST /v1/compliance/discloseZero-knowledge prudential disclosure to a regulatorRead or configurationIdempotency-Key required
GET /v1/auditHash-chained audit eventsRead or configuration

What a call looks like

Originating an unsecured facility. The affordability assessment runs server-side and a breach refuses the origination — it does not warn.
POST /v1/loans/unsecured
Authorization: Bearer <tenant credential>
Idempotency-Key: 8f1c0a3e-4d2b-4a19-9f7e-2c6d1b0a5e34
Content-Type: application/json

{
  "borrower_person_id": "…",
  "principal_cents": 2500000,
  "currency": "ZAR",
  "term_months": 24,
  "purpose_code": "consolidation"
}
A replay of the same key. The original outcome comes back marked, and no second facility exists.
HTTP/1.1 200 OK
Idempotency-Status: replayed

{
  "facility_id": "…",
  "status": "originated",
  "already_processed": true
}
A refusal. Every failure is one of a closed set of codes with a stable shape.
HTTP/1.1 409 Conflict

{
  "code": "wynk.conflict",
  "message": "consumer is under debt review",
  "details": { "reason": "nca_s86_debt_review", "since": "2026-03-11" },
  "correlation_id": "…"
}
Walking a statement line back to the human decision behind it.
GET /v1/accounting/legs/<legId>/walk-back

{
  "leg": { "account_code": "1104-loans-sme", "amount_cents": -450000, "side": "C" },
  "fact": { "id": "…", "chain_seq": 918342, "hash_row": "…" },
  "origin_event": { "kind": "loan.repayment", "at": "…" },
  "workflow_step": { "id": "…", "approved_by": "…", "two_eyes": true },
  "mandate": { "kind": "debicheck", "reference": "…" }
}

The error taxonomy

Closed, so an integrator can switch exhaustively. A new failure mode maps onto an existing code or the taxonomy changes in a versioned release — it never appears as a new free-text string.

Closed error taxonomy
CodeHTTPMeaning
wynk.validation400The request shape or a field value is invalid. The details name the field.
wynk.unauthenticated401No usable credential. Uniform for absent, malformed and expired — deliberately not an oracle.
wynk.forbidden403Authenticated, but the action is outside this caller's authority — including a browser-security refusal.
wynk.not_found404No such resource within this tenant. A resource in another tenant is not found, not forbidden.
wynk.conflict409A lifecycle or uniqueness precondition failed — including an idempotency key replayed with a different body.
wynk.rate_limited429The caller exceeded a route quota. The response carries the retry window.
wynk.upstream.unavailable502A required counterparty or provider is unreachable. The operation is refused, never partially applied.
wynk.internal500An unexpected fault. The response carries a correlation id and nothing else.

Webhooks

Environments

  1. Sandbox — your own tenant, fixture data, mock counterparties. Every rail responds; none of them move real value.
  2. Pre-production — your own tenant, your migrated data, live counterparties in their test modes.
  3. Production — cutover happens with a chain attestation on both sides, so the opening balances you carry across are evidenced rather than asserted.

Integration questions go to developers@wynk.systems. If you are evaluating, the fastest route is a sandbox tenant — start at onboarding.