Skip to main content

Customer Portal — API Contracts

Status: populated Owner: Product Engineering (Frontend) Last updated: 2026-04-18

1. Overview

The customer-portal does not expose its own API to external callers. This document describes:

  1. The Next.js Route Handlers (internal BFF endpoints) used by client components.
  2. The backend API endpoints consumed by Next.js server components and route handlers.

All backend calls go through Kong Gateway with Authorization: Bearer <platform-jwt>.

2. Next.js Route Handlers (BFF Layer)

These handlers live under app/api/ and are called by client-side React code. They proxy to Kong, attaching the JWT from the server-side session.

POST /api/auth/logout

Clears __session and __refresh cookies and redirects to /login.

POST /api/auth/refresh

Calls POST /v1/auth/refresh upstream; rotates __session cookie.

POST /api/api-keys

Proxies POST /v1/api-keys. Returns ApiKeyCreated to client. The rawKey field is passed through exactly once; not logged.

DELETE /api/api-keys/[keyId]

Proxies DELETE /v1/api-keys/{keyId}.

POST /api/send-test

Proxies POST /v1/messages with the test payload. Returns { messageId, status }.

POST /api/webhooks

Proxies POST /v1/webhooks. Returns newly created WebhookConfig including signingSecret.

PUT /api/webhooks/[webhookId]

Proxies PUT /v1/webhooks/{webhookId}.

DELETE /api/webhooks/[webhookId]

Proxies DELETE /v1/webhooks/{webhookId}.

3. Backend Endpoints Consumed

All URLs are relative to Kong base URL configured in NEXT_PUBLIC_API_BASE_URL / API_BASE_URL env vars.

Auth Service

MethodPathUsed on pagePurpose
POST/v1/auth/firebase/loginExchange Firebase ID token for platform JWT
GET/v1/auth/meAll pages (server)Verify customer claim; get account info
POST/v1/auth/refreshMiddlewareRotate JWT using refresh token
GET/v1/api-keys/api-keysList API keys for account
POST/v1/api-keys/api-keysCreate new API key
DELETE/v1/api-keys/{keyId}/api-keysRevoke API key

SMS Orchestrator / Message Store

MethodPathUsed on pagePurpose
POST/v1/messages/send-testSend a test SMS
GET/v1/messages/messagesPaginated message log with filters
GET/v1/messages/{messageId}/messages detailSingle message detail

Query params for GET /v1/messages:

ParamTypeDescription
fromstringFilter by sender ID
tostringFilter by recipient number (E.164)
statusstringqueued, sent, delivered, failed
startDateISO8601Inclusive start of date range
endDateISO8601Inclusive end of date range
pageinteger1-based page number
limitintegerMax 100, default 20

Webhook Dispatcher

MethodPathUsed on pagePurpose
GET/v1/webhooks/webhooksList webhooks for account
POST/v1/webhooks/webhooksCreate webhook (returns signingSecret once)
PUT/v1/webhooks/{webhookId}/webhooksUpdate URL / events
DELETE/v1/webhooks/{webhookId}/webhooksDelete webhook

Billing Service

MethodPathUsed on pagePurpose
GET/v1/billing/invoices/billingPaginated invoice list
GET/v1/billing/invoices/{invoiceId}/billingInvoice detail + PDF URL
GET/v1/billing/usage/billing, /dashboardCurrent period usage summary

4. Standard Response Envelope

All backend services use:

{
"success": true,
"data": { ... },
"error": null,
"meta": { "page": 1, "limit": 20, "total": 143 }
}

The portal propagates error.message to the UI via toast notifications.

5. Error Handling

HTTP StatusPortal behaviour
401Attempt token refresh; if refresh fails, redirect to /login
403Show "Access denied" toast; do not redirect
422Display field-level validation errors in form
429Show "Rate limit exceeded — try again shortly" toast
5xxShow generic "Something went wrong" toast; log to Sentry