{"ok":true,"service":"pewang-payments-api","audience":"External backend developers: call the HTTPS routes below from your server. Paystack secrets stay on this host. If the operator enabled Bearer auth, they must give you an API key.","integrator":{"integrationGuideUrl":"https://payment.pewang.company/payments/developers","overviewUrl":"https://payment.pewang.company/payments/docs","playgroundUrl":"https://payment.pewang.company/payments/test","markdownInRepository":["docs/LOAN-APP-PAYMENTS-INTEGRATION.md","docs/PAYMENTS-API.md"]},"loanAppDeveloperPortal":"https://payment.pewang.company/payments/developers","loanAppIntegrationGuideMarkdown":"docs/LOAN-APP-PAYMENTS-INTEGRATION.md (in repository — full integration spec)","paystackSecretKey":{"configured":true,"mode":"live","charLength":48,"looksShort":false,"hint":"If Paystack still returns Invalid key: regenerate Secret key on Paystack, paste fresh into Vercel (no quotes), redeploy; confirm this Paystack business matches your live mode."},"documentation":"https://payment.pewang.company/payments/docs","documentationLoanIntegration":"https://payment.pewang.company/payments/developers","paystackSecretKey_note":"Diagnostics for this deployment only (integrators: ask the operator if Paystack calls fail or mode looks wrong).","integration":{"humanDocumentation":{"description":"Integrator-first overview + operator appendix: initialize, verify, disburse, webhooks.","pathsOnAnyHost":["/payments/docs","/payments/developers"],"exampleFullUrls":["https://payment.pewang.company/payments/docs","https://payment.pewang.company/payments/developers","https://pewang.company/payments/docs"]},"machineDocumentation":{"description":"This response — same shape on every deployment host.","path":"/api/payments"},"officialPaystackDocs":"https://paystack.com/docs/","repositoryMarkdownFile":"docs/PAYMENTS-API.md"},"webhook":{"path":"/api/paystack/webhook","exampleUrl":"https://payment.pewang.company/api/paystack/webhook","method":"POST","note":"Raw body required for signature verification (x-paystack-signature).","transferNotify":"transfer.success | transfer.failed | transfer.reversed → optional POST to PAYMENTS_TRANSFER_NOTIFY_URL with confirmation_message (see GET /api/payments/transfer)"},"endpoints":{"POST /api/payments/initialize":{"body":{"email":"string","amount_kes":"number (major KES)","callback_url":"optional string","reference":"optional string","metadata":"optional object"},"returns":"authorization_url, access_code, reference","browserDemo":"/payments/test — Pay with Paystack; return /payments/test/pay-return then verify"},"GET /api/payments/verify":{"query":{"reference":"Paystack transaction reference"}},"GET /api/payments/transfer":{"query":{"reference":"OR transfer_code — exactly one: disburse `transfer.reference`, or `TRF_…` / id"},"returns":"confirmation_message (SMS-ready), amount_kes, status, paystack raw object"},"POST /api/payments/disburse":{"body":{"amount_kes":"number","recipient_phone":"0711… or 254711… — normalized to 254 + 9 digits (e.g. 254711164069)","recipient_name":"string","reason":"optional string"},"rules":{"auto_transfer_kes":"amount_kes < 2000 → Paystack transfer initiated","pending_approval":"amount_kes >= 2000 → returns approval_token; call POST /api/payments/disburse/approve with otp"},"returns":{"settlement":"success | processing | otp_required | failed | unknown — derived from Paystack transfer status (pending usually means still processing, not failure)","message":"Human-readable note, especially when Paystack leaves status pending","transfer":"id, reference, status (raw Paystack), optional transfer_code — use webhooks for final settlement","balancePrecheck":"GET /balance (KES) before recipient + transfer; 400 if insufficient; approve checks again before transfer"}},"POST /api/payments/disburse/approve":{"body":{"approval_token":"string from disburse response","otp":"string — must match approval policy configured on this host (operator documents value for integrators)"}}},"auth":{"paystackSecretFromVercel":"Integrators: never send Paystack’s secret. This host reads PAYSTACK_SECRET_KEY server-side and calls Paystack for you.","optionalBearerGate":"If the operator sets PAYMENTS_REQUIRE_BEARER=true and PAYMENTS_API_KEYS, send Authorization: Bearer <issued key> on /api/payments/*. Default: no Bearer."},"env_note":"Operators configure these on the deployment (e.g. Vercel). Integrators only need the public base URL + optional Bearer key from the operator.","env":["PAYSTACK_SECRET_KEY (required — Vercel injects at runtime)","PAYSTACK_PUBLIC_KEY (optional)","PAYSTACK_WEBHOOK_SECRET (optional)","PAYMENT_APPROVAL_OTP (for approve ≥ KES threshold)","PAYMENTS_REQUIRE_BEARER (optional; true = require Bearer + PAYMENTS_API_KEYS)","PAYMENTS_API_KEYS (used only when PAYMENTS_REQUIRE_BEARER=true)","PAYSTACK_KES_MOBILE_BANK_CODE (optional; default MPESA)","PAYMENTS_TRANSFER_NOTIFY_URL (optional — POST JSON on transfer webhooks)","PAYMENTS_TRANSFER_NOTIFY_SECRET (optional — sent as X-Pewang-Notify-Secret)"]}