export const endpoints = { /** Unauthenticated by necessity — between them these produce a session. */ registration: { start: '/registration', verifyOtp: '/registration/verify-otp', mpin: '/registration/mpin', }, crypto: { publicKey: '/crypto/public-key', }, /** * Forgot MPIN. Unauthenticated, like registration — the customer has no MPIN * to open a session with. `initiate` checks the customer with the CBS and * sends an OTP; `verifyOtp` swaps the OTP for a one-time reset token; * `confirm` spends that token on the new, encrypted MPIN and revokes every * open session. There is no resend endpoint: a fresh `initiate` is the resend. */ mpinReset: { initiate: '/mpin-reset/initiate', verifyOtp: '/mpin-reset/verify-otp', confirm: '/mpin-reset/confirm', }, /** * Server-driven feature switches. Deliberately callable without a session — * the sign-in screen's own controls are gated, so this has to resolve before * anyone has signed in. */ features: { config: '/features/config', }, auth: { login: '/auth/login', me: '/auth/me', logout: '/auth/logout', }, /** * Creating the Transaction PIN that authorises fund transfers. Signed-in * only: org, customer, mobile, device and profile all come from the session, * so none of them go in a body. `createInitiate` re-checks the current MPIN * and sends an OTP; `createVerifyOtp` swaps the OTP for a one-time create * token; `createConfirm` spends that token on the new, encrypted TPIN. There * is no resend endpoint: a fresh `createInitiate` — MPIN and all — is the * resend. * * Resetting it follows the same three steps under `/tpin/reset`, with two * differences: `resetInitiate` takes an empty body — the session alone * identifies the customer, and the bank re-verifies them before the OTP goes * out — and it needs a TPIN to already be active. The same session must carry * all three calls; the server refuses a flow that changes user or device. */ tpin: { createInitiate: '/tpin/create/initiate', createVerifyOtp: '/tpin/create/verify-otp', createConfirm: '/tpin/create/confirm', resetInitiate: '/tpin/reset/initiate', resetVerifyOtp: '/tpin/reset/verify-otp', resetConfirm: '/tpin/reset/confirm', }, accounts: { /** * Every account on the signed-in profile. No parameters — the profile comes * entirely from the session. This is the only endpoint that returns a full * account number rather than a masked one. */ list: '/accounts', mmid: '/accounts/mmid', /** * One transactable account's current balance, by `accountNumber` query * parameter. Read live from the bank on every call — nothing is cached * here, and nothing about a balance may be. * * SAVINGS and CURRENT only. A deposit's balance is a term-deposit concept * and lives on `depositDetail` below, which is why the bank keeps the two * apart rather than answering both from one endpoint. */ balance: '/accounts/balance', /* * There is no `/accounts/statement` any more: the paged JSON ledger was * removed from the backend (Statement guide, 14 Oct 2026). */ /** * Every entry in an inclusive date range, as one password-protected PDF. * `accountNumber`, `fromDate` and `toDate` (`yyyy-MM-dd`) are all * required. Answers `application/pdf` on success and the JSON envelope on * any refusal — see `services/files/pdfDownload.ts`. */ statementExport: '/accounts/statement/export', /** * The latest ten entries, newest first, as the JSON envelope. * `accountNumber` only; no date filter is accepted. */ miniStatement: '/accounts/mini-statement', /** * One deposit's terms, by `accountNumber` query parameter. Takes the full * number from `list` above — the masked form every other endpoint returns * will not resolve. */ depositDetail: '/accounts/deposits/detail', }, beneficiaries: { list: '/beneficiaries', save: '/beneficiaries', validate: '/beneficiaries/validate', }, /** * IMPS transfers, in two steps. `initiate` runs the name inquiry and sends an * OTP but moves no money; `verifyOtp` consumes the OTP and sends ReqPay. The * server never sends ReqPay before a verified OTP, and never retries it. */ fundTransfers: { initiate: '/fund-transfers/initiate', verifyOtp: (transferId: string) => `/fund-transfers/${transferId}/verify-otp`, }, /** * The customer's own IMPS transfers, as the server recorded them — the status * authority for how each one ended. The list is paginated and filterable by * status, mode and an inclusive `fromDate`/`toDate`; the detail takes a * `transferId` from the list. Payee identifiers arrive already masked. */ fundTransferHistory: { list: '/fund-transfer-history', detail: (transferId: string) => `/fund-transfer-history/${transferId}`, }, dashboard: { summary: '/dashboard/summary', }, transfer: { beneficiaries: '/transfers/beneficiaries', submit: '/transfers', }, payments: { upi: '/payments/upi', }, deposits: { products: '/deposits/products', fixed: { list: '/fd/list', create: '/fd/create', detail: (id: string) => `/fd/${id}`, close: '/fd/close', }, recurring: { list: '/rd/list', create: '/rd/create', detail: (id: string) => `/rd/${id}`, close: '/rd/close', }, }, services: { requests: '/services/requests', chat: '/services/chat', }, /** * Positive Pay. An account is first enabled with an OTP (`initiate` → * `verifyOtp`, with `resendOtp` reusing the same `requestId`), which never * reaches the bank. Only then can cheques be submitted, and a submitted one * stopped — those two do reach the bank, and the backend saves a record of * each, which `cheques` (paged) and `cheque` read back. * * The reads return the backend's saved state and never ask the bank for a * fresh status, so refreshing cannot settle an uncertain outcome. Ids in a * path are encoded: `chequeId` is the backend's, but it is still data. * * The account is always its `accountNumber` — a query parameter on * `enrollment`, a body field elsewhere. There is no account id in this API. */ pps: { enrollment: '/pps/enrollment/accounts', initiate: '/pps/enrollment/initiate', verifyOtp: '/pps/enrollment/verify-otp', resendOtp: '/pps/enrollment/resend-otp', cheques: '/pps/cheques', cheque: (chequeId: string) => `/pps/cheques/${encodeURIComponent(chequeId)}`, stopPayment: (chequeId: string) => `/pps/cheques/${encodeURIComponent(chequeId)}/stop-payment`, }, /** * Cheque book issuance. * * `charges` quotes the fee before the customer commits to `issue`. `issue` is * synchronous: the serial range comes back in its own response, so there is * no pending state and nothing to poll. `issue` and `list` are the same * path under different methods, named apart because the screens reach for * one or the other and a shared constant reads like a copy-paste slip. */ chequeBook: { charges: '/cheque-book/charges', issue: '/cheque-book', list: '/cheque-book', }, loans: { products: '/loans/products', active: '/loans/active', detail: (id: string) => `/loans/${id}`, apply: '/loans/apply', eligibility: '/loans/eligibility', emiSchedule: (id: string) => `/loans/${id}/emi-schedule`, payEmi: '/loans/pay-emi', foreclosureQuote: (id: string) => `/loans/${id}/foreclosure`, prepay: (id: string) => `/loans/${id}/prepay`, applications: '/loans/applications', documents: '/loans/documents', uploadDocument: '/loans/documents/upload', history: '/loans/history', notifications: '/loans/notifications', }, insurance: { dashboard: '/insurance/dashboard', plans: '/insurance/plans', comparePlans: '/insurance/plans/compare', calculator: '/insurance/calculator', policies: '/insurance/policies', policyDetail: (id: string) => `/insurance/policies/${id}`, purchase: '/insurance/policies/purchase', premiumDues: '/insurance/premiums/due', payPremium: '/insurance/premiums/pay', autoRenew: (policyId: string) => `/insurance/policies/${policyId}/auto-renew`, claims: '/insurance/claims', submitClaim: '/insurance/claims/submit', documents: '/insurance/documents', uploadDocument: '/insurance/documents/upload', notifications: '/insurance/notifications', markNotificationRead: (notificationId: string) => `/insurance/notifications/${notificationId}/read`, otp: '/insurance/otp', }, cards: { overview: '/cards', detail: '/cards/detail', controls: '/cards/controls', limits: '/cards/limits', status: '/cards/status', notifications: '/cards/notifications', virtualCard: '/cards/virtual-card', statements: '/cards/statements', rewards: '/cards/rewards', settings: '/cards/settings', }, profile: { /** The signed-in customer, resolved from the session — no parameters. */ me: '/profile', }, branches: { list: '/branches', detail: (id: string) => `/branches/${id}`, }, agent: { dashboard: '/agent/dashboard', customers: '/agent/customers', customerDetail: (id: string) => `/agent/customers/${id}`, collections: '/agent/collections', collectionHistory: '/agent/collections/history', commission: '/agent/commission', loans: '/agent/loans', sms: '/agent/sms', routes: '/agent/routes', }, };