Keepable docs
Sender API

Sender approval (KYB)

Before an organisation can send, it clears a know-your-business check. Submit your CAC, TIN, and a director's identity, then track the approval through to a decision.

Sending on Keepable is gated on a know-your-business (KYB) check: an organisation proves who it is before it can deliver mail to identity-anchored recipients. This guide covers submitting the intake and tracking it to a decision.

Submitting needs the approval.write scope; reading status needs approval.read.

Submit the intake

Post your registered business details and a director's identity for verification.

curl -X POST https://api.keepable.co/sender/approval \
  -H "Authorization: Bearer $KEEPABLE_TOKEN" \
  -H "Keepable-Version: 2026-05-24" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "legal_name": "Acme Logistics Ltd",
    "cac_number": "RC-1234567",
    "tin": "12345678-0001",
    "director_nin": "12345678901",
    "documents": [
      { "kind": "cac_status_report", "media_type": "application/pdf", "data": "JVBERi0xLjcK..." },
      { "kind": "tax_certificate",   "media_type": "application/pdf", "data": "JVBERi0xLjcK..." }
    ]
  }'
FieldRequiredNotes
legal_nameyesThe registered legal name, exactly as on the CAC record.
cac_numberyesCAC registration (RC) number.
tinyesTax Identification Number.
director_ninyesA director's 11-digit NIN, for verification only.
documentsyesExactly two supporting files, each { kind, media_type, data } with base64 data (≤ 15 MiB decoded): one cac_status_report and one tax_certificate. media_type is application/pdf, image/jpeg, or image/png.

The director_nin is never stored. Keepable verifies it, keeps only the last four digits, and discards the raw value. Every status response returns director_nin_last4, never the full NIN.

Track the decision

Poll status, or fetch it whenever you need to show progress:

curl https://api.keepable.co/sender/approval \
  -H "Authorization: Bearer $KEEPABLE_TOKEN" \
  -H "Keepable-Version: 2026-05-24"
200 OK
{
  "id": "app_01HXP",
  "state": "verifying_kyb",
  "submitted_at": "2026-05-24T09:00:00Z",
  "updated_at": "2026-05-24T09:05:00Z",
  "legal_name": "Acme Logistics Ltd",
  "cac_number": "RC-1234567",
  "tin": "12345678-0001",
  "director_nin_last4": "8901"
}

The intake moves through these states:

stateMeaning
submittedReceived, queued for verification.
verifying_kybAutomated checks against CAC, TIN, and the director's identity are running.
pending_reviewChecks are done; a human reviewer is making the call.
info_requestedThe reviewer needs a correction or more detail. See decision_reason, fix, and resubmit.
approvedYou can send.
rejectedDeclined. See decision_reason.

When state is rejected or info_requested, decision_reason carries the reviewer's explanation, and checks projects which individual verifications passed or failed.

Resubmit

Resubmit is valid only from info_requested; from any other state it returns 409 Conflict. Send just the fields you're correcting to POST /sender/approval/resubmit: unlike the initial submit, no field is required, and documents are not part of the resubmit body. Resubmission re-enters verification (info_requested → verifying_kyb).