Unified Charge Workflow
Read, charge, print, and email in a single charge-card interaction.
POST /api/terminal/{device_id}/charge-card runs up to four stages in one interaction: read → charge → print (optional) → email (optional).
- Amount format: decimal dollars as a string, greater than zero, at most 2 decimal places (e.g.,
"19.99"). Any invalid amount returns400 {"error": "Field amount is invalid"}. The same rule applies toread-card. order_idis optional; if omitted, one is generated as<4-digit-random><yymmddHHMMSS>.- Requesting a step the device can’t do never fails the transaction. The charge completes, and the skipped step is tagged in
result.stage_errors. - On success,
resultis the Payments API charge response. Fields vary by gateway, so treat the documented fields as representative, not exhaustive.
Reading stage_errors
Handling declines
A decline is an outcome, not a failure — and status won't tell you about it
A declined card returns status: "succeeded" with no stage_errors. Approval or decline is indicated by result — the Payments API’s own result field, carried inside the Terminal API’s result object. Always check result before showing the merchant an approval.
Print and email still run on a decline if requested — the merchant receives a receipt for the declined charge. Don’t treat “printed” or “emailed” as equivalent to “paid.”
result values, per the Payments API:
Recommended result handling
statusisfailedorcancelled→ show thestage_errors.read(or other) message; no charge occurred.statusissucceeded→ checkresult:A(Approved) — show the approval.C(Declined) — show the decline.B(Retry) — a transient processor issue, not a decline; retry the charge with a newcharge-cardcall rather than showing it to the merchant as declined.
- Check
stage_errorsforsignature/printtags and surface them as non-blocking notices.