Docs · REST API

API Reference

A REST API for creditor systems. JSON in, JSON out. HTTPS only. Credential: short-lived bearer token or long-lived API key (roadmap Q3 2026).

Sample · place an account
POST /api/v1/creditor/place-account
Authorization: Bearer <token>
Content-Type: application/json

{
  "consumer": { "first_name": "Jane", "last_name": "Doe", "email": "jane@example.com" },
  "original_creditor": "Sample Federal CU",
  "principal_balance": 5247.63,
  "charge_off_date": null,
  "account_phase": "phase0"
}

Overview

All endpoints live under https://www.debt-digest.com/api/v1/. Request and response bodies are JSON. All writes are idempotent on a request-ID basis.

Versioning. Use /api/v1/<path>. The unversioned /api/<path> form still works as a transitional alias but returns RFC 8594 Deprecation + Sunset + Link headers. Sunset for unversioned: 2027-05-03 (365-day grace). Webhooks, healthcheck, and internal endpoints are exempt. They keep their fixed URLs. Full policy: app/docs/API_VERSIONING.md.

Authentication

Today: session-based. Log in at POST /api/auth/creditor/login, receive a bearer token, send it on every request:

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

Tokens expire after 4 hours. Refresh by re-authenticating.

Q3 2026 roadmap: API keys for service-to-service integrations. No password exchange required. Scoped to specific endpoints.

Errors

Standard shape:

{
  "error": "Insufficient permissions",
  "code": "FORBIDDEN",
  "requestId": "01h8k2rjm7c3q4v5w6x7y8z9ab"
}
StatusCodeMeaning
400VALIDATION_ERRORRequest body or query failed validation. See details field.
401UNAUTHENTICATEDMissing or invalid bearer token.
403FORBIDDENAuthenticated but not permitted.
404NOT_FOUNDResource does not exist or you cannot see it.
409CONFLICTState conflict (e.g., settlement already accepted).
422UNPROCESSABLEBusiness rule violated (e.g., principal below floor).
429RATE_LIMITEDToo many requests. Honor Retry-After header.
500INTERNALWe goofed. requestId is in the response - share it with support.

Rate limits

  • 60 requests/min/IP on general API.
  • 5 requests/min/IP on /api/auth/* endpoints.
  • 100 requests/min/creditor on list endpoints (coming Q2 2026).
  • List-endpoint limit query parameter is clamped server-side to 100.

Performance targets

We track and publish response-time percentiles. The health commitments below are SLOs, not SLAs - we use them to decide what to fix first, and share the numbers on request during pilots.

MetricTargetWhat happens if we miss
p50 latency (median)< 150msLogged internally, reviewed weekly
p95 latency< 500msFlags degraded status on /status
p99 latency< 1500msTriggers slow-query investigation
5xx error rate< 0.5% of requestsEmail to pilot contact within 24h
Uptime99.9% monthlySee /status - incidents enumerated there

Queries running ≥1s are logged automatically with a truncated SQL preview so we can find N+1 offenders before they affect you.

Public REST API (v1)

The /external/v1 surface is the integration API for creditor systems that push accounts to Debt Digest and pull state back into a system of record. It is authenticated with an API key (not a portal session), tenant-scoped to the creditor that owns the key, and rate-limited per key.

Base URL: https://www.debt-digest.com/external/v1/

Mounted separately from the internal portal API. Internal endpoints continue to live under /api/creditor/*. The public surface uses its own /external/v1 prefix so the version-rewrite that aliases /api/v1/*/api/* for internal clients does not affect external integrations.

API keys

Mint, list, and revoke keys from the Settings tab of the creditor portal. Minting requires the admin role. Each raw key is shown exactly once: store it in your secret manager immediately; it is unrecoverable.

Authorization: Bearer 1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890

Rate limit: 100 requests per 15 minutes per API key. Exceeded requests return 429 with a Retry-After: 900 response header.

Tenant isolation: every query is scoped to the creditor the key resolves to. Account IDs that belong to another creditor read as 404, identical to a non-existent ID, so cross-tenant existence cannot be inferred.

Public API endpoints

Identity

GET/external/v1/me

Returns the creditor profile owning the key plus the key's own metadata (id, name, prefix, last-used, created-at). Confirms key ownership during setup.

Portfolio metrics

GET/external/v1/metrics

Aggregate counts, total balance, resolution count, resolution rate, and a status histogram across every account.

List accounts

GET/external/v1/accounts?page=1&limit=20&status=contacted

limit is clamped to 100. status is optional and filters to one of the public account statuses.

Get one account

GET/external/v1/accounts/:id

Returns the account row plus every note attached to it.

Import a single account

POST/external/v1/accounts
{
  "consumerEmail": "member@example.com",
  "firstName": "Jane",
  "lastName": "Doe",
  "originalCreditor": "Sample Federal CU",
  "originalBalance": 5247.63,
  "principalBalance": 5247.63,
  "chargeOffDate": null,
  "phase": "phase1"
}

Runs the same consumer auto-create, FDCPA notice generation, statement-signal extraction, and outreach-profile flow as the CSV importer. phase defaults to phase1; phase0 placements in unlicensed jurisdictions return 403 STATE_NOT_AUTHORIZED.

Update an account

PATCH/external/v1/accounts/:id
{ "status": "contacted", "currentBalance": 4980.00 }

Partial update: at least one of status or currentBalance is required. Terminal statuses (settled, paid_in_full) and the consumer-only disputed status are workflow-gated and rejected with 400.

Set status only

POST/external/v1/accounts/:id/status

Equivalent to PATCH with status only; kept for clients that prefer a verb-style RPC shape.

Add a note

POST/external/v1/accounts/:id/note

Free-text note (≤ 5000 chars) appended to the account audit trail.

List settlement offers for an account

GET/external/v1/accounts/:id/offers

Returns every settlement offer attached to the account across all statuses (pending, countered, accepted, paid, rejected, expired).

List active webhooks

GET/external/v1/webhooks

Read-only mirror of the creditor portal webhook list. Signing secrets are never included; manage webhooks (create, test, delete) from the Settings tab.

Schema: the full OpenAPI 3.0 spec is at app/docs/openapi.yaml in the repo. Every /external/v1/* path lives under the Public API v1 tag, secured by the ApiKeyAuth scheme.

Accounts

List accounts

GET/api/creditor/accounts?limit=25&cursor=&status=&search=

Paginated list. cursor for page-forward, status filter, search matches account ID or consumer last-4 SSN.

Place a single account

POST/api/creditor/place-account
{
  "consumerEmail": "member@example.com",
  "originalBalance": 5280.00,
  "principalBalance": 5280.00,
  "dpd": 78,
  "accountType": "credit_card",
  "accountPhase": "intercept",
  "last4ssn": "4321",
  "creditorReference": "ABC-00123"
}

Returns 201 with accountId and FDCPA §809(a) validation notice metadata.

Bulk upload

POST/api/creditor/upload-accounts

Array of up to 1,000 accounts per batch. Returns row-level success / failure report. See CSV schema for column definitions.

Account detail

GET/api/creditor/accounts/:id

Add account note

POST/api/creditor/account-note

Settlement

Configure settlement matrix

PUT/api/creditor/settlement-matrix

Per-tier discount floors: lump_sum, 12_month, 24_month, 36_month. Values as decimals (0.70 = 70% of principal).

Accept a firm offer

POST/api/creditor/accept-settlement

Webhooks

Configure a single URL per creditor to receive events. We POST signed JSON payloads. See the verification guide.

Configure endpoint

PUT/api/creditor/webhook-config

Test delivery

POST/api/creditor/webhook-config/test

Events emitted

  • account.cured - an account returned to 0 DPD and has stayed current 60+ days.
  • settlement.accepted - a firm offer was accepted and payment terms recorded.
  • settlement.paid - consumer completed settlement payment in full.
  • dispute.filed - consumer filed a dispute; collection paused per FDCPA.
  • charge_off.pending - account within 15 days of regulatory charge-off boundary.

Audit log

View

GET/api/creditor/audit-log?from=&to=&limit=

Export (CSV)

GET/api/creditor/audit-log/export?from=&to=

Returns CSV suitable for NCUA exam submission or internal SOC 2 evidence.