Stripe | Financial Infrastructure to Grow Your Revenue

Stripe | Financial Infrastructure to Grow Your Revenue

4466 articles

Issuing real-time authorizations


Issuing real-time authorizations

Learn about real-time authorizations.

Using the synchronous webhook, you can approve or decline authorization requests in real time.

Your webhook endpoint can be configured in your settings. When a card is used to make a purchase, Stripe creates an issuing_authorization.request and sends it to your configured endpoint for your approval.

Get started with our interactive guide to real-time authorizations.

Responding to authorization requests

You can respond to authorization requests by responding directly to the webhook event.

Respond directly

Respond to the issuing_authorization.request webhook event directly to either approve or decline an authorization after it’s received.

Webhook response

Our webhook accepts JSON responses with the following parameters:

Status code: Return 200 to indicate success.

Header:

field namerequired or optionaldescription
Stripe-VersionrequiredSee API Versioning for supported values.
Content-TypeoptionalThe only content type accepted for Authorization webhook responses is application/json.

Body:

field namerequired or optionaltypedescription
approvedrequiredBooleanSet true to approve an authorization and false to decline.
amountoptionalIntegerIf the authorization’s pending_request.is_amount_controllable property is true, you can provide this value to control how much to hold for the authorization. It must be positive.
metadataoptionalSet of key-value pairsThis can be useful for storing additional information about the object in a structured format.
send_fraud_challenges Public previewoptionalArray of stringsYou can send a fraud challenge for this authorization only through SMS. Leave it blank if you don’t want to send a challenge.

server.rb

Select a language

Ruby

Python

PHP

Node.js

Java

Go

.NET

No results

# Using Sinatra.
require 'sinatra'
require 'stripe'

set :port, 4242

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('sk_test_BQokikJOvBiI2HlWgH4olfQ2')

# Replace with a real secret. You can find your endpoint's secret in your webhook settings.
webhook_secret = 'whsec_...'

post '/webhook' do
 payload = request.body.read
 sig_header = request.env['HTTP_STRIPE_SIGNATURE']

 event = nil

 # Verify webhook signature and extract the event.
 begin
 event = Stripe::Webhook.construct_event(
 payload, sig_header, webhook_secret
 )
 rescue JSON::ParserError => e
 # Invalid payload.
 status 400
 return
 rescue Stripe::SignatureVerificationError => e
 # Invalid signature.
 status 400
 return
 end

 if event['type'] == 'issuing_authorization.request'
 auth = event['data']['object']
 # ... custom business logic

 status 200
 header 'Stripe-Version' => '2025-03-31.basil', 'Content-Type' => 'application/json'
 data = { 'approved' => true }
 body data.to_json
 end
 # ...handle other cases
end

If Stripe doesn’t receive your approve or decline response within 2 seconds, the Authorization is automatically approved or declined based on your timeout settings, or Autopilot settings, if configured.

Note

If your Issuing balance has insufficient funds for the incoming authorization, the authorization will be denied and your webhook endpoint won’t receive the issuing_authorization.request event. To learn more about funding your Issuing balance, read here.

Authorization requests

When an authorization request is sent to your webhook, the amount requested is stored in pending_request.

{
 "id": "iauth_1CmMk2IyNTgGDVfzFKlCm0gU",
 "object": "issuing_authorization",
 "approved": false,
 "amount": 0,
 "currency": "usd",
 "status": "pending",
 ...
 "pending_request": {
 "amount": 400,
 "currency": "usd",
 "merchant_amount": 360,
 "merchant_currency": "gbp"
 }
}

The top-level amount in the request is set to 0 and approved is false. After you respond to the request, the top-level amount reflects the total amount approved or declined, the approved field is updated, and pending_request is set to null.

Testing webhooks locally

To test webhooks locally, you can use Stripe CLI. After you install it, you can forward events to your server:

Command Line

stripe listen --forward-to localhost:4242/webhook
Ready! Your webhook signing secret is '{{WEBHOOK_SIGNING_SECRET}}' (^C to quit)

In another terminal, you can then manually trigger issuing_authorization.request events from the CLI for more streamlined testing.

Command Line

stripe trigger issuing_authorization.request

Learn more about setting up webhooks.

Monitor your webhook responses

Monitor your webhook responses for timeouts and errors by subscribing to the issuing_authorization.created and issuing_authorization.updated webhook events. When the request_history.reason property is either webhook_error or webhook_timeout, Stripe isn’t receiving your responses. Don’t rely on approved to gauge integration health because Autopilot can approve on your behalf during an error condition. For example, investigate if an authorization has approved: true but request_history.reason: webhook_error. We surface detailed error messages in the request_history.reason_message field.

Autopilot Public preview

Autopilot provides fallback options that allow you to continue making real-time authorization decisions when your systems are down, don’t respond to an authorization request, or provide an invalid response.

Autopilot makes an authorization decision on your behalf based on a predefined set of rules. We create Authorization objects for transmission to reconcile Autopilot transactions. When Autopilot approves or declines an authorization, the request_history.reason property of the issuing_authorization.created webhook is either webhook_error or webhook_timeout:

  • webhook _ error if you respond to the real-time authorization webhook with an invalid Stripe API version in the request headers , or if we can’t process your response.
  • webhook _ timeout for all other failure modes.

To configure Autopilot, contact Stripe support, and monitor.

Stripe Autopilot Public preview

For users with their own dedicated Bank Identification Numbers (BIN), Stripe Autopilot can help make authorization decisions when the card network can’t reach Stripe.

When an authorization is approved or declined through Stripe Autopilot while Stripe is down, the request_history.reason property of the issuing_authorization.created webhook is network_fallback.

In some cases, Stripe declines an authorization but can’t communicate with the card network, and the network approves the authorization. When that happens, Stripe doesn’t hold the authorized funds, but they might still be captured.

To configure Stripe Autopilot, contact Stripe support, and monitor.

Fraud challenges through webhooks Public preview

Fraud challenges allow your cardholders to retry non-fraudulent transactions that would have otherwise been blocked. While fraud challenges are generally available, the ability to trigger them yourself through real-time webhook responses is in public preview.

To manage the rules that dictate when a fraud challenge is sent, adjust your response to the issuing_authorization.request webhook. You can trigger fraud challenges in scenarios where you detect spending that appears suspicious and want additional verification (for example, a cardholder using their card out of the country).

To do so, decline the issuing_authorization.request webhook and include the send_fraud_challenges field with the ["sms"] value.

Triggering fraud challenges through real-time webhook responses is currently limited to preview users. You must be an Issuing customer to join the preview. To request access to the preview, log in to your Stripe account and refresh the page. Contact Stripe for more information.

Last verified 2026-09-24

Is this helpful?