Skip to main content
This is the cards-specific integration guide: the design decisions you make once per program, and the rules around the most sensitive response Sakawave returns.

Choosing a type

The choice is made at issuance and cannot be changed. A disposable card’s single-use nature is its control, which is why sending spendingControls with one is a validation error rather than being ignored. Two consequences of used being terminal: fund a disposable card with exactly the amount needed, and expect refunds to arrive on a card that can no longer spend — recover them with a termination sweep.

Spending controls that hold

Three independent limits, all in USD minor units, all set once.
Set all three. A daily cap without a per-transaction cap allows one purchase to consume the whole day’s allowance; a per-transaction cap without a count allows a hundred small charges.
Controls cannot be edited after issuance. There is no endpoint to raise, lower, or remove them — a change means issuing a new card and terminating the old one. Choose them as if they were permanent, because they are.

The credentials endpoint

POST /v1/cards/{cardId}/details returns the full PAN and CVV, fetched live from the provider. Sakawave does not store them, and this is the only response in the API that contains them.

Why it is a POST

A GET would be reachable from a link, a prefetch, a browser history entry, a server access log with the path in it, and a referrer header. A POST is none of those. The endpoint also answers with Cache-Control: no-store, private and Pragma: no-cache. Treat the method as part of the security design, not a REST quirk.

Rules for handling the response

1

Never log it

Not in request logs, not in error reports, not in an exception breadcrumb. Redact the whole response body at the logging layer rather than trusting each call site.
2

Never store it

Not in a database, not in a session, not in localStorage. Fetch it when the holder asks to see the card, and let it go.
3

Never cache or proxy it

Not through a CDN, not through a caching reverse proxy, not in a service worker. If you proxy the call, forward the no-store headers.
4

Render it so it cannot persist

A component that clears on navigation and on reload. Do not put it in a URL, a query parameter, or a form value that a browser might restore.
5

Fetch on demand, one card at a time

Never prefetch credentials for a list of cards.
Everywhere else, use maskedPan from the card object. It is on every card response and safe to display, log, and store.

When it is unavailable

Neither is a reason to retry in a tight loop. Wait for card.updated to report active, then try again.

Balances, holds, and what can leave

A card balance is not simply a number you can move. A withdrawal draws only on the available portion, so a withdrawal for the full balance can be refused while an authorisation is outstanding. Termination handles this properly: it waits, returns a pending operation, and sweeps the money once the hold clears. If you need to empty a card and are not sure of its holds, terminate rather than withdrawing.

Freeze versus terminate

Freezing is cheap and reversible, so freeze on suspicion. Terminating is neither, so terminate only on a decision.

A card program checklist

  • Card type chosen per use, and disposable cards funded to exactly the amount needed
  • All three spending controls set at issuance, since none can change later
  • Logging configured to redact the credentials response by route, not by call site
  • Credentials fetched on demand, rendered ephemerally, never stored or cached
  • maskedPan used everywhere a card is displayed or recorded
  • Termination, not withdrawal, used to empty a card whose holds are unknown
  • Freeze wired to your fraud signals as the fast, reversible response