AltScore
Credit Management System (CMS)

Credit Cards API

This API manages revolving credit cards: a credit limit, billing cycles with a cut-off date, statements with a due date, configurable daily interest on unpaid balances, a minimum payment with a late fee, and purchase reversals.

It is a product line of its own, separate from DPA flows and debts — the only shared entity is the client. The CMS Base URL is used (see introduction).

No card number, no security code

The tail you see in responses is a display label derived from the account id so support and the cardholder can name the same card. It is not a PAN and cannot be used as a payment instrument — issuing and tokenization belong to a card processor.

The Card Account Object

{
  "id": "fd44532b-f5f6-493b-baab-8dda053c9cff",
  "clientId": "0187f2d0-471e-40ea-90a2-64d559a40577",
  "productId": "dbb59052-955c-456c-9be5-6041df34f60e",
  "referenceId": "partner-acct-001",
  "status": "enabled",
  "creditLimit": { "amount": "10000.00", "currency": "USD" },
  "currency": "USD",
  "currentStatementId": "712043dc-24c6-45b1-9a58-fd72548fe4dc",
  "outstanding": { "amount": "6255.09", "currency": "USD" },
  "creditBalance": { "amount": "0.00", "currency": "USD" },
  "availableCredit": { "amount": "3744.91", "currency": "USD" },
  "expiresOn": "2029-02-06",
  "terms": { "billingPeriod": { "unit": "day", "count": 1, "monthDays": [15] }, "termDays": 10 },
  "version": 7
}

Attributes

AttributeDescriptionType
idCard account idUUID
clientIdThe client the card belongs toUUID
productIdCard product (plan) the terms were copied fromUUID
referenceIdPartner's own id — creation idempotency keyString
statusSee Card StatusString
creditLimitCredit limit (cupo máximo), enforced on every purchaseMoney
outstandingTotal owed: unpaid billed statements + the open cycle's chargesMoney
creditBalanceMoney in the cardholder's favor (overpayment / reversal excess)Money
availableCreditcreditLimit − outstanding + creditBalance — derived, never storedMoney
expiresOnCard validity date (openedOn + terms.validityYears)Date
currentStatementIdThe single open statement (current cycle)UUID
termsFrozen copy of the plan's terms — see Card ProductsObject

Card Status

StatusMeaning
pendingCreated, not yet activated. No purchases, no payments.
enabledOperating: purchases and payments allowed.
disabledPurchases rejected; payments still accepted. Billing and interest continue.
closedTerminal. Requires a settled book (outstanding − creditBalance exactly zero).

Billing Cycles

  • The account always has exactly one open statement. Purchases land there and are never due mid-cycle — that is the grace period.
  • At the cut-off (closeDate, inclusive) the statement is billed: its dueAmount and minDue freeze, and the next cycle opens. Cycle dates always chain from the previous cut-off, so cycles stay contiguous even if a sweep runs late.
  • The due date is closeDate + termDays.
  • Unpaid balances are not re-billed into later cycles: every statement keeps its own dueAmount/paidAmount. Interest and late fees charged against a statement post on the current open statement (they appear on the next bill, like a real card) and therefore never compound.

Statement Status

StatusMeaning
openCurrent cycle, nothing due yet
closedBilled at cut-off, awaiting payment
overduePast the due date with money still owing
paidRemaining due reached zero (or the cycle billed nothing)

Money Rules

  • Credit is revolving: a payment reduces outstanding immediately, so the available credit is restored in the same transaction — no waiting for the cut-off.
  • Payments apply oldest-unpaid-first across billed statements; the remainder becomes creditBalance. The payment records the split in applications.
  • Purchases over the available credit are rejected with 422 insufficient_credit, checked under a row lock so concurrent purchases cannot jointly overrun the limit.
  • Interest is daily, from the day after a statement's due date on its unpaid balance, until it is paid. The base is the statement's own remaining due, so interest never accrues on interest.
  • The late fee is one-shot per statement, charged only when payments through the due date did not reach minDue. Paying at or above the minimum avoids the fee; interest still accrues on the rest.

Idempotency

Every write is idempotent — a replay returns the existing record with 200 instead of creating a twin.

OperationKey
Open accountreferenceId (optional)
Purchase / paymentreferenceId (required)
Purchase reversalone reversal per purchase
Interest / late feeone per statement per day / one per statement

The Idempotency-Key header is additionally honored on purchases, payments and reversals.

Endpoints

Open a Card Account

Creates the account in pending with its first open statement.

POST /v1/card-accounts

Body:

FieldDescriptionType
clientIdClient UUID or the partner's external idString
creditLimitCredit limitMoney
productIdPlan to use. Omitted ⇒ the tenant's default planUUID
referenceIdPartner's id for the account (idempotency)String
termsOverridePer-account overrides of the plan termsObject
openedOnBackdates the account for historical imports (YYYY-MM-DD)Date
metadataFree-formObject

Returns 201 with the Card Account; a replay of the same referenceId returns 200 with the existing one.

Get / List Card Accounts

GET /v1/card-accounts?clientId=&status=&limit=&offset=
GET /v1/card-accounts/{id}

Change the Credit Limit

PUT /v1/card-accounts/{id}/credit-limit

Body: { "creditLimit": { "amount": "15000.00", "currency": "USD" } }. Lowering it below the current usage is allowed — the available credit goes negative and purchases are rejected until the cardholder pays down.

Activate, Suspend or Close

POST /v1/card-accounts/{id}/enable
POST /v1/card-accounts/{id}/disable    {"reason": "..."}
POST /v1/card-accounts/{id}/close      {"reason": "..."}

A suspended card still accepts payments. Closing requires a settled book.

Register a Purchase

POST /v1/card-accounts/{id}/purchases
FieldDescriptionType
referenceIdRequired idempotency keyString
amountPurchase amountMoney
dateBusiness date. Omitted ⇒ today (YYYY-MM-DD)Date
metadatadescription is shown on the statementObject

412 if the card is not enabled; 422 insufficient_credit if it exceeds the available credit.

Reverse a Purchase

POST /v1/card-accounts/{id}/purchases/{txId}/reverse

Body: optional amount (omit for a full reversal) and reason. Transactions are immutable, so the reversal is a new compensating transaction — one per purchase, full or partial:

  • If the purchase's statement is still open, the reversal voids it inside the cycle and the purchase never gets billed.
  • If the statement was already billed, the reversal applies against that statement like a targeted payment (and can mark it paid, stopping its daily interest). Any excess becomes credit balance.

Interest or late fees already charged for past days are not retro-reverted.

Register a Payment

POST /v1/card-accounts/{id}/payments

Same body as a purchase. Applies oldest-unpaid-first; statements it zeroes become paid, which stops their daily interest from that date. The response carries the split:

{
  "transactionId": "…",
  "type": "payment",
  "amount": { "amount": "800.00", "currency": "USD" },
  "applications": [
    { "statementId": "…jul", "amount": { "amount": "300.00", "currency": "USD" } },
    { "statementId": "…aug", "amount": { "amount": "400.00", "currency": "USD" } }
  ]
}

(the remaining 100.00 became credit balance).

Account Summary

GET /v1/card-accounts/{id}/summary

The cardholder's position right now: creditLimit, outstanding, creditBalance, availableCredit, dueNow, minDueNow, oldestDueDate, daysPastDue, cycleStartDate, nextCutoffDate, nextDueDate, cycleSpend (this period's consumption) and expiresOn.

Statements and Transactions

GET /v1/card-accounts/{id}/statements
GET /v1/card-accounts/{id}/statements/current
GET /v1/card-accounts/{id}/transactions
GET /v1/card-statements/{id}
GET /v1/card-statements/{id}/transactions

Transaction types: purchase, payment, interest, penalty (late fee) and reversal. Interest and late fees carry metadata.sourceStatementId pointing at the cycle that owed the money; reversals carry metadata.sourceTransactionId.

Statement Document (estado de cuenta)

GET /v1/card-statements/{id}/document
GET /v1/card-statements/{id}/document.csv

The composed statement of one cycle in a single payload — issuer, cardholder, card, period, totals and the itemized lines — so a renderer never has to stitch calls or re-derive money. .csv returns the same document as a downloadable attachment (debits positive, credits negative, so summing the amount column reconciles).

{
  "issuer":     { "tenant": "…", "name": "…", "taxId": "…" },
  "cardholder": { "clientId": "…", "name": "…", "taxId": "…", "address": "…" },
  "card":       { "tail": "0539", "creditLimit": {}, "availableCredit": {}, "expiresOn": "2029-02-06" },
  "period":     { "startDate": "2026-06-15", "closeDate": "2026-07-14", "dueDate": "2026-07-24", "minDueMet": false },
  "totals":     { "previousBalance": {}, "purchases": {}, "interest": {}, "penalties": {},
                  "payments": {}, "reversals": {}, "dueAmount": {}, "paidAmount": {},
                  "remainingDue": {}, "minDue": {}, "minDueRemaining": {} },
  "lines":      [ { "date": "2026-06-19", "type": "purchase", "concept": "…", "amount": {}, "debit": true } ]
}

previousBalance is what the older cycles still owed as of this cut-off. It is computed when the document is built (unpaid balances are never re-billed) and it is informational — it is not part of this cycle's dueAmount.

Tax (VAT) on interest and late fees

When the plan sets interestTax (and optionally penaltyTax), every interest or late-fee charge stores its own tax and the document breaks it out:

TotalWhat it is
interest / penaltiesGross: tax included, because that is what the cardholder owes and what dueAmount is built from
interestTax / penaltyTaxThe tax included in each of the two above
taxesinterestTax + penaltyTax for the period

Each interest/late-fee line also carries its own tax; a line's net charge is amount − tax. Every other line (purchases, payments, reversals) carries a zero tax.

Tax is rounded per charge

Interest accrues daily, so the tax is computed and rounded per charge (half-even). The period total is the sum of the lines — the way a line-level VAT invoice adds up. Re-applying the rate to the aggregate interest can differ by cents: the document reports the sum, not the recomputation.

The payment reference is still missing

The document does not yet include a payment reference or coupon. It is deliberately not derived: a number the API invents is registered with no collection network and cannot be paid. The shape will be an opaque per-account reference set by the partner, plus the tenant's configured payment instructions.

Permissions

PermissionGrants
card.account.readaccounts, summary, statements, transactions, statement document
card.account.writeopen an account, change the limit, enable/disable/close
card.purchase.createregister purchases and reverse them
card.payment.createregister payments

Sending X-Test-Mode: true operates on the tenant's sandbox, fully partitioned from production data.

Error Handling

StatusWhen
400Validation: missing referenceId, non-positive amount, currency mismatch, bad dates
404Unknown account, statement or transaction
412Wrong state: purchase on a non-enabled card, closing with debt, reversing a non-purchase
422 insufficient_creditThe purchase exceeds the available credit
200 on replayA duplicate referenceId returns the existing record instead of failing