Skip to navigation

Manual and delayed capture

Manual capture is the process of placing an authorization hold on a card, and then capturing the payment later, typically at the time of fulfillment.

The initial invocation of create_payment_session requires that the customer be present in the checkout flow. Additional calls for capture or voids don’t require customer-in-flow.

Authorization holds for manual capture are created and managed using the same create_payment_session endpoint outlined in Accept Your First Payment.

Manual capture relies on your system storing the id field from the payment session response and calling /payments/v1/payment_session/{business_id}/capture when the payment should be captured, or /payments/v1/payment_session/{business_id}/void to release the authorization hold.

Suggested implementation

Use manual capture when your order should be authorized at checkout, but charged later after a fulfillment decision.

1

Create the payment session as an authorization

Pass kind: "authorization" to create_payment_session. Store the returned payment session id on your order.

2

Wait for the authorization webhook

Listen for payment_session_complete. For manual capture, the key post-checkout webhook status is authorized. This means the authorization hold is ready to capture or void.

3

Capture when you are ready to fulfill

Call capture_payment_session with a unique idempotency_key, the total_amount to capture, and the item_details being captured.

4

Fulfill after capture succeeds

The authorization webhook tells you the funds are held, not captured. Fulfill after your capture request succeeds for the amount you intend to charge.

5

Void if you will not fulfill

If the order should not be fulfilled, call void_payment_session to release the authorization hold.

If you need to capture more than the original authorization amount, void the authorization and create a new payment session. Capture amounts must be less than or equal to the original authorization.

Flow diagram

alt [Ready to fulfill] [Order should not be fulfilled] Click "Pay with HSA/FSA" POST /create_payment_session (kind: authorization) redirect_url + payment_session_id Store payment_session_id on order Redirect to Truemed Complete health survey Enter HSA/FSA card details Redirect to success_url payment_session_complete (processing) payment_session_complete (authorized) POST /payment_session/{business_id}/capture Capture succeeds POST /payment_session/{business_id}/void Void request accepted payment_session_complete (authorization_voided) Do not fulfill yet Authorization hold is ready Fulfill order Release order without fulfillment User Merchant Truemed

Request body

The create_payment_session endpoint can be invoked with the additional fields described here.

FieldTypeDescription
kindstringOne of: one_time_payment (default) or authorization

Kind values

  • one_time_payment (DEFAULT): The charge is immediately captured. This is the default if this field is not set.
  • authorization: A one_time_payment authorization hold only. Must be manually captured or voided with a follow-up API call.

Response body

The response is the same as described in the create_payment_session API reference, with additional error states.

Bad request

HTTP Status: 400

If a field is missing or the request otherwise can’t be processed, we’ll return a 400.

Capture and void operations

Once an authorization hold has been created, you can either capture or void it:

Capture request

Use a unique idempotency_key for each capture attempt. Include the total amount being captured and the specific items included in the capture.

If you plan to capture by item, provide item_id on each order_items entry when creating the payment session so you can reference those same items in item_details.

curl https://dev-api.truemed.com/payments/v1/payment_session/c51f5d44-9f8d-4e9f-bc5f-929a6f9f2f51/capture \
-X POST \
-H "Content-Type: application/json" \
-H "x-truemed-api-key: $TRUEMED_API_KEY" \
-d '{
"total_amount": 12500,
"idempotency_key": "capture_order_12345",
"final": true,
"item_details": [
{
"item_id": "line_item_1",
"quantity": 1,
"total": 12500
}
]
}'

Set final to false only if you plan to make additional captures against the same authorization. This requires multi-capture, which is off by default — see Capturing in multiple parts.

Void request

Void the authorization when the order should not be fulfilled.

curl https://dev-api.truemed.com/payments/v1/payment_session/c51f5d44-9f8d-4e9f-bc5f-929a6f9f2f51/void \
-X POST \
-H "Content-Type: application/json" \
-H "x-truemed-api-key: $TRUEMED_API_KEY" \
-d '{
"idempotency_key": "void_order_12345"
}'

Capturing in multiple parts

Multi-capture lets you capture part of one authorization at a time, usually once per shipment. Each capture collects what shipped; the rest stays authorized until your final capture.

Set request_multicapture: true in the create_payment_session request. Truemed then requests multi-capture when it authorizes the cards. The card network confirms availability for each transaction, and Truemed returns the result as multicapture_available in the authorized payment_session_complete webhook and in get_payment_session. Check it before you ship part of an order.

When multicapture_available is true, capture each shipment as it goes out with final: false. When the networks have not made multi-capture available, the session supports only a single capture. Attempting multi-capture with final: false in this case is rejected.

Best practices

Check multicapture_available before you split an order. When it’s false, capture the full order in one request.

Capture items that may qualify for HSA/FSA spending first, and shared shipping with them or at the end. That keeps the most money on the customer’s HSA/FSA card.

Put tax, shipping and discounts on the items at checkout if you know them. Then each item’s capture is simply its total.

Send final: true on the last capture. It releases whatever you didn’t collect.

Turning it on

  1. Ask Truemed to enable multi-capture for your sales channel.
  2. Create the session with kind: "authorization" and request_multicapture: true. Sessions that save or reuse a card (tokenize or payment_token) can’t use it.
  3. Once the session is authorized, read multicapture_available on the payment_session_complete webhook or get_payment_session.

If multicapture_available is false, the card network allowed only one capture. A final: false capture will be rejected, and a final capture releases everything it doesn’t collect. Decide how to fulfill that order before you ship part of it.

Capturing

Send one capture_payment_session per shipment, each with a new idempotency_key, the units that shipped in item_details, and final: false until the last.

curl https://dev-api.truemed.com/payments/v1/payment_session/c51f5d44-9f8d-4e9f-bc5f-929a6f9f2f51/capture \
-X POST \
-H "Content-Type: application/json" \
-H "x-truemed-api-key: $TRUEMED_API_KEY" \
-d '{
"total_amount": 6000,
"idempotency_key": "capture_order_12345_shipment_1",
"final": false,
"item_details": [
{ "item_id": "line_item_1", "quantity": 2, "total": 6000 }
]
}'

To close without collecting more, send total_amount: 0, item_details: [] and final: true, or void the session. A capture of everything still owed closes the session on its own.

Partial quantities: why a rounding rule, and which one

An item’s max_capture_amount covers its full quantity, but its units may be captured separately. Rounding each capture independently could leave cents behind or let the captures collect more than the item’s limit. Truemed therefore calculates each capture from the cumulative quantity:

share(k) = max_capture_amount × k ÷ quantity, rounded half up to the nearest cent

If b units were captured before and the next capture contains n, their base share is share(b + n) - share(b). This produces the same total whether units are captured individually, in groups, or all at once.

Your system may place a rounding cent on a different unit than Truemed does. To accommodate that, the cumulative limit allows up to one additional cent per captured unit, without ever exceeding max_capture_amount. For example, when max_capture_amount is 1000 and quantity is 3, the item’s captures may total up to 334 after one unit, 669 after two, and 1000 after all three. Amount left uncollected on an earlier unit does not otherwise increase what a later unit may collect.

Shipping, tax and discounts sent for the whole order

If you send them in the session’s top-level amount_details, Truemed splits them across the items when the session is authorized. Each item publishes its order_level_charges_share, order_level_discounts_share, and max_capture_amount: its total plus the charges share less the discounts share. Captures can then carry that money in either of two ways:

  • Send item totals and let Truemed work it out. total_amount can be the items’ totals plus any order-level money still owed, so one box can carry all the shipping. Coming in under the items’ totals applies your order-level discounts.
  • Declare it. Send amount_details on the capture or on each item, in the same shape as at checkout, when your fulfillment system knows each box’s tax, shipping and discounts. A discount declared on an item belongs to that item, and an item you send without amount_details keeps the charges and discounts it was created with.

If a session’s first capture sends no amount_details, later captures can’t send them either; a final capture without amount_details collects what’s left. A session whose first capture declares can mix declared and inferred captures.

If a discount only applies to some items, such as a bundle deal, declare it on those items: otherwise Truemed spreads it across the whole order. The capture reference has the exact rules.

Good to know

  • $0.50 minimum. A card can’t be charged less than $0.50 in one capture. If an item worth less than that ships last on its own, add it to an earlier box or leave it uncollected.
  • The regular card’s authorization. When a customer splits payment between an HSA/FSA card and a regular card, Truemed may authorize a little more on the regular card than the customer’s share, so later boxes can always be charged. You never collect more than the order total, and the unused part is released when the session closes.
  • HSA/FSA money on the regular card. Sometimes money that may qualify for HSA/FSA spending has to go on the regular card, for example eligible shipping captured before the items it belongs to. The receipt still reports the full eligible amount, so the customer can choose to seek reimbursement from their HSA/FSA administrator for the portion charged to the regular card.
  • Limits. One authorization allows at most 50 non-final captures plus the final one.

Refunds

Each capture appears in captures[] on the session with its own id. Refund against a specific capture by passing that id as capture_id on create_refund, one refund per capture. A refund doesn’t free up authorization for later captures.