Take a card payment and credit the org's balance
Takes a payment: charges a single-use card token and credits the caller's org balance, exactly once.
POST /v1/commerce/payments
| Address | https://api.hanzo.ai/v1/commerce/payments |
| Method | POST |
| Operation | takePayment |
| Auth | Authorization: Bearer $HANZO_API_KEY |
Takes a payment: charges a single-use card token and credits the caller's org balance, exactly once.
This is the operation behind "collect money from a customer". It runs the SAME core the console's card top-up runs (commerce billing.TakePayment), so the server-side amount bounds, the idempotency guard and the ledger credit are shared rather than reimplemented — a second charge path would eventually double-charge somebody.
The ORG is the caller's, taken from the validated principal and never from the input, so a payment can only ever credit the account of whoever made the call.
A payment is RISK-SCREENED before the card is charged, so this can be refused without any money moving: 403 means the screen did not authorise it, and 503 means the screen could not reach a decision — that one is worth retrying, and no charge was attempted either way.
Send an idempotencyKey. An agent retries by construction, and the key is what turns a retry into a replay of the first receipt instead of a second charge.
The answer states whether it settled in SANDBOX or live mode (test), and
carries the processor's own reference (processorRef) so the charge can be
reconciled against the processor rather than taken on trust.
A named builder, not a closure, so zipdoc can lift this prose into the registry.
It BUILDS the handler rather than being it, because the screen has to sit inside
the value every projection of this op dispatches to — see exposePayments. charge
is the money move, take is the screened door onto it, and the only registrable
one is the second.
Request
4 fields, body application/json (required).
| Field | In | Type | Required | Description |
|---|---|---|---|---|
amountCents | body | integer | — | AmountCents is the amount to charge, in whole cents (5000 is $50.00). |
currency | body | string | — | Currency is the ISO 4217 code, lower-cased. |
idempotencyKey | body | string | — | IdempotencyKey makes a retry safe: the same key never charges twice, it replays the first result. |
sourceId | body | string | — | SourceID is the single-use payment token that stands in for the card: a Square Web Payments SDK nonce minted in the browser, or a Square sandbox test nonce… |
Response
| Status | Body | Meaning |
|---|---|---|
201 | PaymentOut | created |
201 body — 5 fields.
| Field | In | Type | Always | Description |
|---|---|---|---|---|
balanceCents | body | integer | — | BalanceCents is the org's balance AFTER this payment, read back from the same key just credited so it matches what the balance endpoint reports. |
id | body | string | — | ID is the ledger transaction id for the credit. |
processorRef | body | string | — | ProcessorRef is the payment processor's own reference for the charge (Square's payment id). |
status | body | string | — | Status is "ok" on a settled charge. |
test | body | boolean | — | Test reports which bucket this credited: true is a SANDBOX charge crediting the test balance, false is live money. |
Failure carries the platform error shape — see Errors.
Examples
hanzo has no subcommand for this operation — the CLI serves only what cloud's live route table confirms. Use HTTP or an SDK.
import { Configuration, CommerceApi } from 'hanzoai';
const api = new CommerceApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.takePayment({ amountCents: 0, currency: "<currency>" });from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import CommerceApi
client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = CommerceApi(client).take_payment(amount_cents=0, currency="<currency>")cfg := cloud.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := cloud.NewAPIClient(cfg)
resp, _, err := client.CommerceAPI.TakePayment(context.Background()).Execute()
if err != nil {
return err
}use hanzo_cloud::apis::{configuration::Configuration, commerce_api};
let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();
let result = commerce_api::take_payment(&cfg, Default::default()).await?;import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.CommerceApi;
ApiClient client = new ApiClient();
client.setRequestInterceptor(b -> b.header("Authorization", "Bearer " + System.getenv("HANZO_API_KEY")));
var result = new CommerceApi(client).takePayment();curl -X POST https://api.hanzo.ai/v1/commerce/payments \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amountCents": 0,
"currency": "<currency>"
}'Tool commerce, op takePayment — POST the JSON-RPC envelope to https://api.hanzo.ai/v1/mcp.
curl -X POST https://api.hanzo.ai/v1/mcp \
-H "Authorization: Bearer $HANZO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "commerce",
"arguments": {
"op": "takePayment",
"input": {
"amountCents": 0,
"currency": "<currency>"
}
}
}
}'How is this guide?