UnifiWallet Payments

Holds and captures

Take the money now, charge it when the order ships — and release it at no cost if it never does.

A hold takes the buyer's money out of their wallet without giving it to you. It sits in a contract until you charge it — when the thing ships — or release it, which costs you nothing and needs no refund.

If you sell downloads, you do not want this. If you ship goods, make to order, or take pre-orders, it is the difference between cancelling an order and owing somebody a refund.

What changes

Instant (default)A hold
Money reaches you when the buyer paysMoney sits in a contract until you capture
Cancelling means sending a refund from your wallet, within your deadlineCancelling is a void: nothing to send, nothing owed
Any currency you acceptOnly the currency you settle in
One transactionTwo — the hold, then the charge
payment.settledpayment.authorized, then payment.captured

The flow

// 1. Create the payment as a hold rather than a charge.
const payment = await call('POST', '/v1/payments', {
  amount: '249.00',
  currency: 'USD',
  capture_method: 'manual',      // hold it; charge on despatch
  description: 'Oak dining table',
});

// 2. The buyer pays as usual. You get payment.authorized, not payment.settled:
//    the money is in the escrow contract, not in your wallet.

// 3. It shipped. Charge it.
await call('POST', `/v1/payments/${payment.id}/capture`, {});

// 3b. Or only two of the three items arrived in stock.
await call('POST', `/v1/payments/${payment.id}/capture`, { amount: '166.00' });

// 3c. Or it is out of stock. Release it — this costs you nothing to send.
await call('POST', `/v1/payments/${payment.id}/void`, {});

Charging part of it

A partial capture charges what you shipped and releases the rest. Two of three items in stock: capture two thirds, and the buyer keeps the difference without asking for it. Tax is reversed in proportion, at the rate that applied when the payment was taken.

The payment stays authorized while anything is still held, so you can capture again as the rest of the order ships.

The window

Seven days by default — the same as a card authorization, which is where the expectation comes from. Stripe holds an online authorization for seven days and offers extended ones up to thirty; PayPal keeps one valid for twenty-nine. You can set yours anywhere up to the platform maximum, in Settings → How you take money, or per payment with hold_window_hours.

The window is fixed onto the payment when it is created, so changing your setting never shortens a hold a buyer has already agreed to.

When it lapses the buyer takes their money back and you have not been paid, so if you ship slower than your own window, lengthen it. You get payment.authorization_expiring a day before a hold lapses, and payment.authorization_expired if it does.

An expired hold is not a payment you can still collect.

Once the window closes the buyer may reclaim the funds from the contract themselves, without us and without you. We do it for them as a courtesy rather than leaving them to call a contract function. Capturing after expiry returns authorization_expired.

Why only your settlement currency

A hold has to hand back exactly what the buyer put in. Converting on the way in would mean returning a different amount than they sent, because the rate moved while you were deciding. So a held payment is offered only in the currency you settle in, and the checkout shows that currency alone.

This is why holds go with stablecoins in practice. A merchant settling in ETH and accepting only ETH can hold funds perfectly well; a merchant who wants buyers to pay in anything cannot hold at all.

What we can and cannot do with the money

The constraint is in the contract, not in our good behaviour. While funds are held we can send them to you, or back to the buyer. There is no third instruction — not to us, not to anyone. After the window closes we cannot even do that: only the buyer's own reclaim works.

Everything is confirmed by the chain

capture and void return 202. They submit a transaction and tell you it is on its way; the payment moves when the contract's event confirms it. We never report a capture we have not seen land.

While one is in flight, a second is refused with escrow_operation_in_flight — that is what stops a retry charging the buyer twice. If the transaction fails, you get payment.escrow_operation_failed, nothing has moved, and you can try again.

If a capture is undone by a reorg

Rare, and real. A capture is a transaction like any other, and a chain reorganisation can take it out of the canonical history. The money is then back in the escrow contract, and the contract knows exactly how much — so the payment is resynced from it rather than from our own arithmetic, and returns to authorized with whatever is genuinely still held.

You get payment.reorged. If you had already shipped on a payment.captured, this is the case that costs you — which is why completed, not captured, is the signal to ship on. A payment completes only once every one of its captures is deep enough.

States

StatusMeaning
authorizedThe money is held. Not yours yet.
settledCaptured, in full or in part. The captured amount is yours.
completedConfirmed to the required depth. Safe to ship.
voidedReleased untouched. The buyer has it all back.
expiredThe window closed unclaimed and the buyer took it back.

A void after a partial capture is not a voided payment: some of it was charged, and that money is yours. Those become settled, with amount_captured telling you how much.

What a cancellation costs you

Releasing a hold is free to the buyer and costs you one network fee — the transaction that sends their money back. The same is true of a hold you let expire, and of a deposit returned to a buyer. These are the only transactions with no payment to take the fee from, so they are recorded against you and appear on your statement.

Below a threshold they are not collected at all: on a cheap chain they are fractions of a cent and chasing them would cost more than the amount. Above it you get account.network_fees_owed once, and the amount comes off a future settlement.

Turning it on

In the panel, under Settings → How you take money. It sets the default for new payments; capture_method on an individual payment overrides it either way, so you can hold the furniture and charge instantly for the delivery slot.