Finalize a card

Use Affirm's Card API finalize request to refund the remaining unused balance on the virtual card.

Overview

If a merchant does not capture the authorized loan amount from a virtual card in full or issues a partial refund, Affirm will wait through an “auth window” (45 days by default) for the merchant to resolve open authorizations. However, this means that the customer must also wait the full authorization window before receiving their refund.

The Finalize API is an affirmative signal from the merchant that they are done performing actions on the virtual card.

Affirm recommends executing the finalize API request on a virtual card at least 1 week after the last anticipated capture is submitted to the card. Finalizing the card improves the user experience by ensuring that your customers receive timely refunds.

📘

Note:

Once you finalize the virtual card, it will not be able to accept further authorizations or captures.

How it works

The Finalize API resolves an authorized or captured loan down to the amount that has been captured on the Affirm virtual card at the moment of the API request execution.

  • If no funds have been captured, the loan will be voided/canceled.
  • If any funds have been captured, the loan will be refunded down to the amount that is outstanding (including a full refund, if the card has been fully refunded).

📘

If you are unsure if that applies to your business, please contact us via the support widget.

Implementation

Make sure that you only hit the Finalize API 1 week after you have captured all existing authorizations and have no intention of further authorizations/captures on the card.

  • If there is an order cancellation, make sure everything has been captured on the card even if that's lower than the order total.
  • If you still wish to capture on the card, do not hit the Finalize API yet. You can call the Finalize API when you are done capturing.

📘

Note:

Please note that the only event Affirm expects after the card has been finalized is a refund.

Step 1

[Example] Run a query to return orders that need to be finalized

Lookback orders where the last capture occurred 7 days prior:

SELECT order_id, transaction_id FROM customer_orders
WHERE payment_type = 'Affirm' 
AND order_status = 'fully captured' -- check notes below on order status
AND finalized_status = 0 
AND last_capture_date <= DATEADD(day, -7,  current_date)

⚠️

Note on order_status:

The exact definition of a “fully captured” order will depend on your business logic. The core idea is that there are no funds remaining to be captured for the order. E.g.: this would both count for “happy path” orders where 100% of the funds are captured and partial cancellations where, for instance, 60% was captured, and the remaining 40% was canceled; in this case, 100% of the funds that need to be captured are already captured, so the Finalize API can be hit.

Step 2

Call the Finalize API on these orders

With the Affirm checkout ID’s associated to the orders, make a POST call to our Finalize endpoint:

https://api.affirm.com/api/v2/cards/{checkout_id}/finalize

Example of a successful response:

{
  "message": "The card was successfully scheduled to finalize. You should see changes reflected in 24 hours.",
  "code": "success",
  "checkout_token": "FA0UUFRGOND84S7C"
}

Order Flow Diagrams

Multi-item full refund

Multi-item partial refund

Timeline

👍

Successful response

Once a confirmation response is received, the customer's loan will be partially or fully refunded.

  • If the card is in expired, canceled, or auth_expired states, do nothing.
  • If the card is in confirmed state, expire the card, and cancel the charge.
  • If the card is in authorized state, auth expire the card and void the charge.
  • If the card is in captured state, auth expire the card and refund the charge to the balance that is currently captured on the card.

Once the scheduled event is executed, this will either remove the loan from the customer's Affirm user portal or refund and update the payment schedule for the loan to the appropriate amount.

Bad request

  • The merchant is not a Platforms.vcn merchant.
  • There is no checkout token with that checkout_token.
  • There is no card associated with the checkout_token.
  • The current agent does not have update permission on the charge (wrong merchant).
  • The charge is being disputed.
  • The card state is not being handled (should never happen unless we add a new CardState).

Only practically available in the production environment. Needs to hit the payment rails.