Capture an order
Capture a full or partial payment against an authorized order with POST /captures, and attach the order lines and shipping details each capture covers.
Capture is the call that moves money from the customer to your bank account, and you make it when you fulfill. This page covers capturing in full and capturing in parts as you ship. It assumes you have an authorized order and credentials that can act on it.
What capture means
Section titled “What capture means”Checkout authorizes: it reserves the money without taking it. Capture takes it. They are separate because you should only charge for what you actually ship, and the moment you know that’s fulfillment, not purchase. It’s also why partial capture exists rather than being an edge case — an order shipped in two parcels is two captures against one authorization, and the customer is charged as each one leaves.
Before you start
Section titled “Before you start”You need the order_id from a completed checkout, and an API credential for the same
environment the order was created in. Paths are relative to your
base URL: https://api.playground.kustom.co/ while
testing, https://api.kustom.co/ in production.
Send a Kustom-Idempotency-Key on every write. Every POST and PATCH to Order Management moves money or changes the order. Send a Kustom-Idempotency-Key header with one UUID per operation, and reuse it when you retry, so a call repeated after a timeout runs once instead of twice. Idempotency and retries has the rules and the retry schedule.
Capture
Section titled “Capture”Capture the whole order once it ships.
POST /ordermanagement/v1/orders/{order_id}/capturesKustom-Idempotency-Key: 6a1f7c3e-9b2d-4a11-8f0e-2c5d7b9a4e13Content-Type: application/json{ "captured_amount": 6000, "reference": "c9a94cf1-7126-4f55-92fa-4d34f416ed7f", "description": "Shipped the full order", "order_lines": [ { "type": "physical", "reference": "123050", "name": "Tomatoes", "quantity": 10, "quantity_unit": "kg", "unit_price": 600, "tax_rate": 2500, "total_amount": 6000, "total_tax_amount": 1200 } ], "shipping_info": [ { "shipping_company": "Postnord", "tracking_number": "1234567890" } ]}Only captured_amount is required, and for a full capture it must match the order’s
order_amount. The rest is optional but worth sending: order_lines is what the customer
and the Portal display as the contents of this capture, and shipping_info is required in
practice for physical goods.
A successful capture returns 201 Created with a capture_id and a Location header.
Use that Location as given rather than assembling a URL from the id:
GET /ordermanagement/v1/orders/{order_id}/captures/{capture_id}Then read the order itself and check the arithmetic — captured_amount should have gone
up by what you captured, and remaining_authorized_amount down by the same. That’s the
check that catches a double capture, which is the failure an idempotency key exists to
prevent.
Partial capture
Section titled “Partial capture”Partial capture is the same endpoint with a smaller captured_amount — send the lines
you’re actually shipping, and their shipping_info. Do this once per shipment. The
remaining authorization stays available for the rest, and the order’s status becomes
PART_CAPTURED.
Keep each capture’s order-line reference values: a later refund of something from that
shipment sends the same references, so the credit lands on the right invoice — see
Partial refund.
Troubleshooting
Section titled “Troubleshooting”A capture larger than remaining_authorized_amount is rejected rather than clamped. So is
a capture against an order that has expired — authorizations don’t last indefinitely, and
once one expires the money is gone from your side of the transaction. If fulfillment is
going to run long, extend before it expires rather than after.
Both of those come back as CAPTURE_NOT_ALLOWED,
which is a statement about where the order is rather than about your request — so retrying it
unchanged will fail identically. Read the order first. A capture id you no longer recognize
gives NO_SUCH_CAPTURE. List the order’s captures
rather than reconstructing the id.
An order with a very large number of lines can exceed the accepted body size and return
PAYLOAD_TOO_LARGE. Sustained traffic above
your account’s limit returns TOO_MANY_REQUESTS,
and a Kustom-side failure returns
TEMPORARILY_UNAVAILABLE — the last two
are worth retrying with backoff, the rest never are.
Related
Section titled “Related”- Refund an order — giving it back once captured
- Extend order expiry — before it expires, not after
- Order Management — where capture sits in the lifecycle
- Update or cancel an order — reading back what you just did
This page is also available as Markdown — append .md to its URL — and is indexed in llms.txt.