Payments PendingPayPal Capture, Authorize, and Void Flows in Order Processing

PayPal Capture, Authorize, and Void Flows in Order Processing

Understanding PayPal's state machine prevents payment failures during order processing.

· 8 min read

PayPal capture, authorize, and void flows in order processing form a strict state machine. Reliable fulfillment depends on respecting each transition, its timing limits, and its failure modes. The same rules must govern both the integration and its tests, because successful endpoint calls alone do not prove that an order can move safely from approval to settlement or cancellation.

What the PayPal authorize-capture-void flow actually is

The order’s intent establishes the path through the payment lifecycle. Orders API v2 accepts CAPTURE for settlement immediately after buyer approval or AUTHORIZE to place a hold and defer settlement. That choice is set when the order is created and cannot be changed afterward. Authorization therefore separates the decision to reserve funds from the decision to collect them. Capture then settles an authorized amount, while void cancels the authorization that remains.

PayPal’s delay-capture documentation lists pre-orders, made-to-order goods, hotel and rental bookings, and high-value items that need verification as cases where settlement can wait. These cases share a gap between buyer approval and readiness to charge. Order statuses including CREATED, SAVED, APPROVED, VOIDED, COMPLETED, and PAYER_ACTION_REQUIRED describe the checkout lifecycle, while authorization and capture have their own states. Keeping those resources distinct matters because an order’s existence does not establish that its funds can be captured. The legal next operation depends on the payment’s current state.

Diagram: The Authorization–Capture–Void State Machine. Visualizes: Visualize the PayPal payment state machine as a directed flow showing the legal transitions between named states and the error that blocks each illegal one.

The CREATED-to-AUTHORIZED transition and what can go wrong before capture

Creating an order and securing an authorization are separate events with separate clocks. PayPal’s Orders API standard describes a short window for capturing or modifying an order before it expires in CREATED, with extensions for specific use cases. Buyer approval is another condition that must be met after order creation. The payer is sent to the “Review your purchase” page and must act before the authorization is valid. An order left in CREATED without payer action is therefore not a payment reservation.

The deferred flow begins by setting intent to "AUTHORIZE" at order creation. The authorization ID is returned at purchase_units[0].payments.authorizations[0].id in the approval response described by the integration notes [0]. Later capture and void calls need that authorization ID in place of the order ID [0]. Store it in the merchant’s database as part of the order-creation and authorization flow when it becomes available. Without that stored identifier, later operations require a lookup rather than a reliable reconstruction from the order ID [0].

PayPal’s authorization and capture guide explains that re-authorization generates a new Authorization ID and restarts the honor period, so subsequent captures must use the new ID [0]. However, re-authorization near the end of the authorization period leaves only a short honor window. A restarted honor period does not remove the overall expiration constraint. Treating one authorization ID as permanent for an order can therefore leave later capture calls tied to the wrong authorization [0].

Capture: what the transition permits, what it forbids, and how partial captures change the state

Capture uses POST /v2/payments/authorizations/{authorization_id}/capture through Payments API v2. It settles funds against the authorization, but it need not collect the entire authorized amount at once. Multiple partial captures support fulfillment in separate shipments, with each shipment captured when it ships. After a partial capture, the uncaptured amount remains available and can later be captured, voided, or left to expire. The critical distinction is between a successful capture and a fully consumed authorization.

A partial capture does not close the authorization in the way a full capture does. Fulfillment systems should track how much has been captured in total against the authorization ceiling, as well as whether a capture call succeeded. Each later capture depends on how much has already settled. Testing it in isolation misses the accumulated amount that counts against the authorization ceiling.

PayPal’s authorization and capture guide describes an overcapture limit bounded by a percentage allowance and an absolute-dollar allowance, whichever is less. If a shipping surcharge or price adjustment brings the total above the authorized amount, it must still stay within that ceiling. Once the authorization is fully captured, another capture attempt returns AUTHORIZATION_ALREADY_CAPTURED with a 422 response. If the 29-day authorization window has passed instead, capture returns AUTHORIZATION_EXPIRED with a 422 response, and the merchant must create a new order rather than recover the expired authorization in place.

Void: the transitions it permits, the ones it forbids, and what happens to the customer's funds

Void uses POST /v2/payments/authorizations/{authorization_id}/void to cancel an authorization that still permits cancellation. It applies to a fresh authorization or the uncaptured remainder after a partial capture. However, it cancels that entire remainder, because partial void is not supported. Once voided, the authorization is permanently cancelled, and a later capture attempt fails. There is no reverse transition that restores the same authorization.

The errors distinguish an unavailable cancellation from one already completed. Voiding a fully captured or expired authorization returns AUTHORIZATION_CANNOT_BE_VOIDED, while voiding an already-voided authorization returns AUTHORIZATION_VOIDED. After capture, returning the settled money requires a refund. PayPal’s void documentation says that cancelling before capture saves on processing fees compared with giving a refund afterward. A cancellation during partial fulfillment therefore requires attention to which funds have already settled and which remain authorized.

A successful void also does not mean that the customer’s bank immediately removes the hold. Sandbox funds release immediately, but production release depends on the customer’s bank. PayPal’s authorization and capture guide says that Visa and Mastercard authorization holds are reversed, but a bank hold may stay in place for several days until the card issuer reverses it. Support needs to account for that delay when explaining why a cancelled order still seems to leave the customer with less available balance. For cancellations before shipment, unavailable stock, failed fraud verification, or cancellation during fulfillment, void promptly rather than wait for expiration, which does not guarantee immediate release.

The API version you must be on and what changes when you migrate

This integration uses Orders API v2 to authorize and Payments API v2 to capture or void. They are separate APIs with separate base paths. PayPal’s Payments v1 reference marks the payment listing, creation, detail, capture, void, and re-authorization endpoints as deprecated. Although the deprecated surface accepts new integrations, it is not the v2 behavior model described here.

PayPal’s v1-to-v2 migration guide describes how checkout is separate from the processing that takes place after approval. Migration therefore involves request and response fields, operation semantics, status values, and notification mechanisms as well as endpoint URLs. In Payments v2, GET /v2/payments/authorizations/{authorization_id} gives the details of an authorization, while GET /v2/payments/captures/{capture_id} gives the details of a captured payment. Refunds use POST /v2/payments/captures/{capture_id}/refund.

Why this flow breaks stateless mocks and what that costs a CI pipeline

A stateless mock returns its configured response without remembering earlier requests. That can validate an isolated endpoint interaction, but it cannot establish that a payment sequence obeys the state machine. For example, AUTHORIZED → VOIDED must change what later calls against the same authorization can do. A mock that still reports capture success after void has allowed a sequence that cannot happen.

The same gap appears with a fresh authorization and one that has already been fully captured. The latter must reject another capture with AUTHORIZATION_ALREADY_CAPTURED, so the mock must know about the earlier settlement. Partial capture accumulation adds an amount constraint to that state constraint. A static response cannot distinguish a permitted capture from one that exceeds the ceiling after earlier captures.

A CI pipeline has a separate risk if an unavailable mock silently sends requests to the live PayPal API. A green build then no longer proves that the flow ran in the test environment it was meant to use. Instead, the build depends on credentials, rate limits, and non-deterministic sandbox behavior. This mixes a coverage problem with an environment dependency.

What a stateful simulator provides that closes the gap

A stateful simulator makes earlier calls part of the conditions for later ones. It generates and stores authorization IDs, then looks up the current resource when capture or void uses an ID. A successful void changes that authorization to VOIDED, so a later capture against the same ID must fail. The test can then distinguish an application that respects cancellation from one that attempts settlement afterward.

Amounts need the same continuity. Partial captures accumulate against the authorization, allowing the simulator to enforce the overcapture ceiling across requests. Negative testing can also inject AUTHORIZATION_EXPIRED without waiting for natural expiration. This makes failure handling repeatable while preserving the relationship between the authorization and the attempted operation.

A locally hosted simulator removes PayPal sandbox availability from the CI pipeline’s dependencies. Tests can run offline or in an air-gapped environment without live credentials or upstream rate limits. That does not make a static imitation of each endpoint sufficient. The useful property is enforcement of the transition rules, including identifiers, accumulated amounts, cancellation, and expiration.

The test matrix that covers the state machine completely

An implementable test matrix pairs each starting condition with an operation and an expected result. PayPal’s delay-capture and void documentation gives the standard scenarios and named failures for those pairs. Begin with an order that has AUTHORIZE intent and capture shortly after authorization, expecting the authorization to succeed and the capture to complete. For a partial capture, expect the captured portion to settle while the remainder stays available. For a fresh authorization, expect void to return VOIDED, and for a partially captured authorization, expect void to cancel the uncaptured remainder.

Capture after the 29-day window should return AUTHORIZATION_EXPIRED with a 422 response. Capture after full settlement should return AUTHORIZATION_ALREADY_CAPTURED, also with a 422 response. Multiple partial captures should exercise both permitted accumulation and rejection when the combined amount exceeds the ceiling.

The cancellation cases cover a different set of boundaries. Void after full capture or expiration should return AUTHORIZATION_CANNOT_BE_VOIDED, and voiding twice should return AUTHORIZATION_VOIDED on the second attempt. Capture after a successful void must fail, leaving funds unsettled. An invalid authorization ID should return RESOURCE_NOT_FOUND with a 404 response, while void with the wrong credentials should return PERMISSION_DENIED. An injected INTERNAL_SERVER_ERROR should test 500-error handling while the application keeps running and its state stays consistent.

Timing completes the matrix because an authorization’s age changes its usefulness before it expires. Capture after the honor period, during days 4–29, has a lower success rate, and re-authorization is recommended. The matrix should also cover the new Authorization ID after re-authorization, the shortened honor window near expiry, and the day 29 boundary where a new order is required. PayPal’s delay-capture documentation says that sandbox authorizations do not expire on the normal schedule, so testing expiration calls for negative testing. Expiration and honor-period degradation cannot be made fast, repeatable CI cases by relying on the live sandbox’s clock.

Sources

  1. Void an authorized payment
  2. Website Payments Pro authorization and capture
  3. Authorize and delay capture
  4. Payments
  5. Payments v2
  6. PayPal Checkout
  7. Orders API v1 → v2 integration upgrade guide

More in Stripe Integration