Pre-Authorization Guide
Pre-authorization places a temporary hold on a cardholder's funds without capturing them. The final amount is confirmed later — when the actual charge is known — through a Capture operation.
When to use pre-authorization
| Use case | Example |
|---|---|
| Hotel check-in | Hold an estimated amount at check-in; capture the actual stay cost at check-out |
| Car rental | Hold a deposit at pickup; capture fuel + days at return |
| Restaurants (tab) | Hold on card open; capture the final bill including tip |
| Fuel pump (pay-at-pump) | Hold a fixed amount; capture actual fuel dispensed |
Do not use pre-auth for standard retail where the amount is known at the time of card interaction — use Sale instead.
Supported integration paths
| Operation | Cloud API | Android (PAX) | Android (HiLite) | iOS (HiLite) | Cordova |
|---|---|---|---|---|---|
| Create | ✅ | ✅ | ❌ | ❌ | ✅ |
| Increase / Decrease | ✅ | ✅ | ❌ | ❌ | ✅ |
| Capture | ✅ | ✅ | ❌ | ❌ | ✅ |
| Pre-Auth Reversal | ✅ | ✅ | ❌ | ❌ | ✅ |
| Capture Reversal | ✅ | ✅ | ❌ | ❌ | ❌ |
HiLite paths (Android BT, iOS) do not support pre-authorization. Use the Cloud API from your server instead.
The pre-authorization lifecycle
Create (AUTHORISED — hold placed)
│
├── Increase / Decrease ──────────────────┐
│ (adjust hold amount) │
│ └── repeat as needed ─────────────────►│
│ │
├── Capture ◄──────────────────────────────┘
│ (charge the cardholder)
│ │
│ ├── Capture Reversal (pre-settlement only)
│ │ (cancel the capture — same day, before batch close)
│ │
│ └── Refund (post-settlement)
│ (standard refund after settlement)
│
└── Pre-Auth Reversal
(release without charging)
Important constraints:
- The hold expires in 7–30 days depending on the card network and issuer. Always capture or reverse before expiry.
- Always reverse unused holds — unreleased pre-auths count against the cardholder's available credit.
- The
transactionReferenceyou send on the Create links all subsequent operations and enables reconciliation via the/status/allendpoint.
Step 1 — Create a Pre-Authorization
The cardholder presents their card. A hold is placed for the estimated amount.
- Cloud API
- Android (PAX)
- Android (HiLite)
- iOS (HiLite)
- Cordova
curl -X POST https://cloud.handpoint.com/transactions \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operation": "preAuthorization",
"amount": "10000",
"currency": "USD",
"terminal_type": "PAXA920",
"serial_number": "082104578",
"transactionReference": "2bfde1fc-23b1-4c67-93d9-1d4a557f4d4f"
}'
Store from the result:
transactionID— required for Capture, Void, and IncreasetransactionReference— use to query the full operation chain via/status/all
hapi.preAuthorization(BigInteger("10000"), Currency.USD)
// Result arrives in endOfTransaction:
override fun endOfTransaction(result: TransactionResult, ref: TransactionReference) {
if (result.finStatus == FinancialStatus.AUTHORISED) {
val preAuthId = result.transactionID // store — required for capture/void
}
}
Pre-authorization is not supported on the HiLite Bluetooth path. Use the Cloud API from your server.
Pre-authorization is not supported on the iOS HiLite path. Use the Cloud API from your server.
handpoint.preAuthorization(
{ amount: 10000, currency: "USD" },
function(result) {
if (result.finStatus === "AUTHORISED") {
const preAuthId = result.transactionID; // store — required for capture/void
}
},
function(error) { console.error(error); }
);
Step 2 — Increase or Decrease the hold (optional)
Adjusts the held amount before capture — for example, a hotel stay extended (increase) or a car rental returned early (decrease).
Adjustments are cumulative deltas, not new totals. The gateway keeps one running hold amount per pre-authorization and applies each adjustment to it. To raise a $100 hold to $120, send $20 — not $120. Two increases of $50 and $75 on a $100 hold leave a $225 hold.
- Always reference the original pre-authorization
transactionID. Adjustments are never chained to a previous increase. - There is no separate decrease operation — a decrease is an increase carrying a decrease signal. The signal differs by integration path; see the tab for yours.
- The result returns
holdAmount, the running total after this adjustment. Use it to confirm the new hold rather than recalculating it yourself.increaseAmountechoes the delta you sent andoriginalAmountis the amount approved on the Create. - A declined adjustment leaves the hold unchanged.
- The gateway applies no upper limit to an increase. The ceiling comes from the acquirer, the issuer, and the card-scheme tolerances in Hold durations by card network.
- A decrease that would take the hold to zero or below is rejected. To release the hold entirely, send a Pre-Auth Reversal instead.
- Once the pre-authorization has been captured or reversed, no further adjustment is accepted.
- Do not include a
transactionReference— this is a subsequent operation.
Increase / Decrease is not available on every acquirer. Confirm support for yours before relying on it.
Two card-brand rules apply on every route, whatever the headline acquirer:
- Interac (Canadian debit) never supports increase or decrease. Interac authorizations are routed to a debit-only protocol that rejects the operation — see Interac VOID.
- Amex cards do not support increase or decrease when the merchant holds a separate Amex agreement, because the card is routed to the Amex protocol.
- Cloud API
- Android (PAX)
- Android (HiLite)
- iOS (HiLite)
- Cordova
Sent straight to the gateway — no terminal involved, result returned synchronously. Amount in major units as a decimal string and always positive; add "subtract": "1" to decrease.
curl -X POST https://cloud.handpoint.com/preauthorization/increase \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"originalGuid": "01236fc0-8192-11eb-9aca-ad4b0e95f241",
"increaseAmount": "20.00"
}'
To decrease: add "subtract": "1" to the body. increaseAmount is always a positive value — the subtract field controls direction.
| Parameter | Type | Required | Description |
|---|---|---|---|
originalGuid | string | Yes | transactionID from the pre-auth Create result |
increaseAmount | string | Yes | Delta in major units, e.g. "20.00". Always positive |
subtract | string | No | "1" subtracts the delta instead of adding it. "1" is the only accepted value |
customerReference | string | No | Integrator-defined reference, forwarded as-is |
An adjustment carries no tip or tax amount. Send those on the Capture instead.
Pass the delta in minor units. A negative value decreases.
// Increase a $100 hold to $120
hapi.preAuthorizationIncrease(
BigInteger("2000"), // delta, not the new total
Currency.USD,
"01236fc0-8192-11eb-9aca-ad4b0e95f241" // transactionID from the Create
)
// Decrease it back to $100
hapi.preAuthorizationIncrease(BigInteger("-2000"), Currency.USD, "01236fc0-...")
Not supported on HiLite.
Not supported on iOS HiLite.
handpoint.preAuthorizationIncrease(
{
amount: 2000, // delta in minor units; negative to decrease
currency: handpoint.Currency.USD,
originalTransactionID: "01236fc0-8192-11eb-9aca-ad4b0e95f241"
},
function(result) { /* handle */ },
function(error) { console.error(error); }
);
Adjustments are rejected with a dedicated error code when the pre-authorization has already been settled, or when a decrease would empty the hold — see Error codes.
Step 3a — Capture
Finalizes the hold and charges the cardholder. Use the actual amount. It may be lower than the hold, but it must not exceed the current hold total — if the final charge is higher, increase the hold first.
- Cloud API
- Android (PAX)
- Android (HiLite)
- iOS (HiLite)
- Cordova
curl -X POST https://cloud.handpoint.com/preauthorization/capture \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"originalGuid": "01236fc0-8192-11eb-9aca-ad4b0e95f241",
"capturedAmount": "95.00"
}'
originalGuid is the transactionID from the pre-authorization result. capturedAmount is in major currency units as a decimal string — "95.00" = $95.00.
To include a tip:
curl -X POST https://cloud.handpoint.com/preauthorization/capture \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"originalGuid": "01236fc0-8192-11eb-9aca-ad4b0e95f241",
"capturedAmount": "95.00",
"tipAmount": "5.00"
}'
| Parameter | Type | Required | Max length | Description |
|---|---|---|---|---|
originalGuid | string | Yes | 64 chars | transactionID from the pre-auth Create result |
capturedAmount | string | Yes | 32 chars | Amount to capture — see caution below |
tipAmount | string | No | 32 chars | Tip to add on top of capturedAmount |
customerReference | string | No | 64 chars | Integrator-defined reference, forwarded as-is |
capturedAmount and tipAmount are major-unit decimal strings — consistent with all Cloud API back-office (no-reader) calls. "95.00" captures $95.00. This differs from on-device operations (Android SDK preAuthorizationCapture), which take minor-unit integers (BigInteger("9500")).
hapi.preAuthorizationCapture(
BigInteger("9500"), // actual capture amount
Currency.USD,
"01236fc0-8192-11eb-9aca-ad4b0e95f241" // transactionID from pre-auth result
)
override fun endOfTransaction(result: TransactionResult, ref: TransactionReference) {
if (result.finStatus == FinancialStatus.AUTHORISED) {
// capture successful — funds will settle at batch close
}
}
Not supported on HiLite.
Not supported on iOS HiLite.
handpoint.preAuthorizationCapture(
{
amount: 9500,
currency: "USD",
originalTransactionID: "01236fc0-8192-11eb-9aca-ad4b0e95f241"
},
function(result) { /* handle */ },
function(error) { console.error(error); }
);
Step 3b — Pre-Auth Reversal (release without capturing)
Releases the hold without charging the cardholder. Use when a booking is cancelled or the pre-auth is no longer needed.
- Cloud API
- Android (PAX)
- Android (HiLite)
- iOS (HiLite)
- Cordova
Sent straight to the gateway — no terminal involved, result returned synchronously. Use POST /reversal from your server when you want to void the hold without involving the terminal — for example, after a booking is cancelled or a guest checks out early.
Full reversal (release the entire hold):
curl -X POST https://cloud.handpoint.com/reversal \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "originalGuid": "01236fc0-8192-11eb-9aca-ad4b0e95f241" }'
Partial reversal (release part of the hold):
curl -X POST https://cloud.handpoint.com/reversal \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"originalGuid": "01236fc0-8192-11eb-9aca-ad4b0e95f241",
"amount": "50.04",
"currency": "USD"
}'
amount is in major-unit decimal (e.g. "50.04" = $50.04). currency is required whenever amount is provided.
| Parameter | Type | Required | Description |
|---|---|---|---|
originalGuid | string | Yes | transactionID from the pre-auth Create result |
amount | string | No | Major-unit decimal; partial release amount. Omit to release the full hold |
currency | string | Conditional | ISO 4217 currency code. Required when amount is provided |
The result is returned synchronously (HTTP 200) — no polling needed:
{
"finStatus": "AUTHORISED",
"type": "PRE_AUTHORIZATION_REVERSAL",
"transactionID": "f7a8b9c0-8192-11eb-9aca-ad4b0e95f241",
"originalEFTTransactionID": "01236fc0-8192-11eb-9aca-ad4b0e95f241"
}
originalGuid is the transactionID from the Pre-Authorization Create result. The gateway determines whether this is a void (Step 3b) or a capture reversal (Step 4) based on the current state of the original transaction.
hapi.preAuthorizationReversal("01236fc0-8192-11eb-9aca-ad4b0e95f241")
Not supported on HiLite.
Not supported on iOS HiLite.
handpoint.preAuthorizationReversal(
{ originalTransactionID: "01236fc0-8192-11eb-9aca-ad4b0e95f241" },
function(result) { /* handle */ },
function(error) { console.error(error); }
);
Step 4 — Capture Reversal (cancel a capture, pre-settlement)
Cancels a capture that was sent in error — before the batch closes and funds settle. After settlement, only a Refund is possible.
The same preAuthorizationReversal operation is used for both Void hold (Step 3b) and Capture Reversal. The gateway determines the correct action based on the current state of the original transaction.
Partial capture reversal (EPI only): EPI supports reversing part of a capture — for example, if you captured $95 but only $70 should have been charged, you can reverse $25 rather than the full capture amount. On other acquirers, capture reversal is full-amount only.
Not all acquirers support Capture Reversal. Check the acquirer capabilities matrix for current support per acquirer and integration path.
- Cloud API
- Android (PAX)
- Android (HiLite)
- iOS (HiLite)
- Cordova
Sent straight to the gateway — no terminal involved, result returned synchronously. Pass the transactionID from the Capture result as originalGuid.
curl -X POST https://cloud.handpoint.com/reversal \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "originalGuid": "e5f6a7b8-8192-11eb-9aca-ad4b0e95f241" }'
The gateway determines whether this is a void (Step 3b) or a capture reversal based on the current state of the original transaction.
// Same method as Void hold — gateway determines action based on transaction state
hapi.preAuthorizationReversal("01236fc0-8192-11eb-9aca-ad4b0e95f241")
Not supported on HiLite.
Not supported on iOS HiLite.
Not confirmed on Cordova. Use Cloud API or Android SDK (PAX) directly.
Reconciliation via transactionReference
Query the full pre-auth operation chain at any time using the transactionReference you sent on the Create:
curl https://transactions.handpoint.com/transactions/2bfde1fc-23b1-4c67-93d9-1d4a557f4d4f/status/all \
-H "ApiKeyCloud: YOUR_MERCHANT_API_KEY"
Example response — Create → Increase → Capture chain:
[
{
"type": "PRE_AUTHORIZATION",
"finStatus": "AUTHORISED",
"totalAmount": 10000,
"transactionID": "01236fc0-8192-11eb-9aca-ad4b0e95f241",
"transactionReference": "2bfde1fc-23b1-4c67-93d9-1d4a557f4d4f"
},
{
"type": "PRE_AUTHORIZATION_INCREASE",
"finStatus": "AUTHORISED",
"totalAmount": 15000,
"transactionID": "a2b3c4d5-8192-11eb-9aca-ad4b0e95f241",
"originalEFTTransactionID": "01236fc0-8192-11eb-9aca-ad4b0e95f241"
},
{
"type": "PRE_AUTHORIZATION_CAPTURE",
"finStatus": "AUTHORISED",
"totalAmount": 9500,
"transactionID": "e5f6a7b8-8192-11eb-9aca-ad4b0e95f241",
"originalEFTTransactionID": "01236fc0-8192-11eb-9aca-ad4b0e95f241"
}
]
The last operation in the chain reflects the current state. Use the totalAmount of the most recent AUTHORISED operation to determine the net amount charged.
See Transaction Recovery & Status for full documentation on selectors (all, first, last, {n}).
Best practices
| Practice | Why |
|---|---|
| Always reverse unused pre-auths | Unreleased holds reduce the cardholder's available credit and may generate disputes |
| Capture before hold expiry (7–30 days) | Expired holds cannot be captured — you would need to re-initiate a new card interaction |
Store the Create transactionID | Every increase, decrease, capture, and reversal references the original pre-auth — not the most recent operation |
Store transactionReference from Create | Enables /status/all queries for the full chain at any time |
Do not send transactionReference on Capture, Increase, or Void | Only on the original Create. Subsequent operations are linked via originalTransactionId |
| Partial capture is usually allowed | Capture less than the hold amount when the final charge is lower — no need to void and re-charge |
| Increase before capturing more than the hold | A capture above the current hold total is rejected — raise the hold first |
| Release a hold with a reversal, not a decrease | A decrease to zero is rejected; only a Pre-Auth Reversal releases the hold in full |
| After settlement, use Refund — not Capture Reversal | Capture Reversal only works before the batch closes |
Quick reference — which transactionID to send
Every follow-up operation references the original pre-authorization — never a previous increase:
Create → transactionID = "A"
Increase → originalTransactionId = "A", transactionID = "B"
Second Increase → originalTransactionId = "A", transactionID = "C"
Capture → originalGuid = "A"
Pre-Auth Reversal → originalTransactionId = "A"
Capture Reversal is the one exception: it references the transactionID of the Capture result — see Step 4.
Hold durations by card network
A pre-authorization hold expires automatically if not captured or voided within the card network's maximum timeframe. After expiry, the issuer releases the hold — but the authorization record remains, which can cause disputes if a capture is attempted late. Always capture or void before expiry.
Voiding a pre-auth hold is not subject to the same-day cut-off that applies to sale reversals or capture reversals. You can void the hold at any point before it expires. After expiry, the network releases it automatically — no void is needed (or possible).
Visa
| Transaction type | Max processing timeframe | Amount tolerance |
|---|---|---|
| Card-absent with Extended Authorization indicator | 30 calendar days | Up to 15% |
| Card-absent (standard) | 10 calendar days | Up to 15% |
| Estimated auth — taxicabs (MCC 4121) | 5 calendar days | — |
| Estimated auth — eating places (MCC 5812) | 5 calendar days | Up to 30% (CP and CNP) |
| Estimated auth — fast food (MCC 5814) | 5 calendar days | Up to 30% (CP and CNP) |
| Estimated auth — drinking places (MCC 5813) | 5 calendar days | — |
| Estimated auth — beauty shops (MCC 7230) | 5 calendar days | — |
| Estimated auth — spas / health clubs (MCC 7298) | 5 calendar days | — |
| Estimated auth — caterers (MCC 5811) | 5 calendar days | — |
| Grocery / superstore card-not-present (MCC 5411) | 7 calendar days | — |
| Lodging | Duration of stay | — |
| Vehicle rental | Duration of rental | — |
| Truck rental | Duration of rental | — |
| Cruise line | Duration of cruise | — |
Mastercard
| Transaction type | Max processing timeframe | Amount tolerance |
|---|---|---|
| Card-absent with Extended Authorization indicator | 30 calendar days | None specified |
| Card-absent (standard) | 10 calendar days | None specified |
| Estimated auth — eating places (MCC 5812) | 5 calendar days | Up to 30% (CP and CNP) |
| Estimated auth — fast food (MCC 5814) | 5 calendar days | Up to 30% (CP and CNP) |
| Estimated auth — drinking places (MCC 5813) | 5 calendar days | — |
| Estimated auth — beauty shops (MCC 7230) | 5 calendar days | — |
| Estimated auth — spas (MCC 7298) | 5 calendar days | — |
| Estimated auth — caterers (MCC 5811) | 5 calendar days | — |
| Grocery card-not-present (MCC 5411) | 7 calendar days | — |
| Lodging | Duration of stay | — |
| Vehicle rental | Duration of rental | — |
| Truck rental | Duration of rental | — |
| Cruise line | Duration of cruise | — |
| All other (general pre-auth) | 30 calendar days | Up to 15% (or USD 75, whichever greater, for some MCCs) |
Amex
Amex authorizations generally follow issuer-specific rules. The default hold period is 7 calendar days for most transaction types. Extended holds for lodging, car rental, and cruise lines follow the duration of the service.
Discover
Discover follows card-not-present authorization hold rules similar to Visa. Standard CNP holds: 10 calendar days. Extended authorization: up to 30 calendar days with the appropriate indicator.
Source: Visa Core Rules and Visa Product and Service Rules; Mastercard Transaction Processing Rules. Rules are subject to change — always verify with the current card network rulebooks for your region.
Related pages
- Operations Reference — curl examples for pre-auth create, capture, and error responses
- Error Handling Guide — pre-auth capability errors (
preAuthAllowed = false), capture error shapes - Transaction Reference — how
transactionReferencelinks the full pre-auth chain and enables/status/allqueries