Issuing
Real-time authorizations
 

Real-time authorizations

 

Learn more 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.

Responding to authorization requests

Make an API call to either approve or decline the request and include the Authorization ID.

Your webhook must approve or decline each authorization before responding to the incoming webhook request. If Stripe does not receive your approve or decline request within 2 seconds, the Authorization is automatically approved or declined based on your timeout settings.

# Using Sinatra. require 'sinatra' require 'stripe' set :port, 4242 # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Uncomment and 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'] handle_authorization(auth) end status 200 end def handle_authorization(auth) # Authorize the transaction. authorization = Stripe::Issuing::Authorization.approve(auth["id"]) end
import stripe import json # Using Flask. from flask import ( Flask, render_template, request, ) app = Flask(__name__, static_folder=".", static_url_path="", template_folder=".") # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Uncomment and replace with a real secret. You can find your endpoint's # secret in your webhook settings. # webhook_secret = 'whsec_...' @app.route("/webhook", methods=["POST"]) def webhook_received(): request_data = json.loads(request.data) signature = request.headers.get("stripe-signature") # Verify webhook signature and extract the event. try: event = stripe.Webhook.construct_event( payload=request.data, sig_header=signature, secret=webhook_secret ) except ValueError as e: # Invalid payload. return HttpResponse(status=400) except stripe.error.SignatureVerificationError as e: # Invalid signature. return HttpResponse(status=400) if event["type"] == "issuing_authorization.request": auth = event["data"]["object"] handle_authorization(auth) return json.dumps({"success": True}), 200 def handle_authorization(auth): # Authorize the transaction. authorization = stripe.issuing.Authorization.approve(auth['id']) if __name__ == "__main__": app.run(port=4242)
<?php // Using Slim. use Slim\Http\Request; use Slim\Http\Response; use Stripe\Stripe; require_once('vendor/autoload.php'); $app = new \Slim\App; // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Uncomment and replace with a real secret. You can find your endpoint's // secret in your webhook settings. // $webhook_secret = 'whsec_...'; $app->post('/webhook', function ($request, $response, $next) { $payload = $request->getBody(); $sig_header = $request->getHeaderLine('stripe-signature'); $event = null; // Verify webhook signature and extract the event. try { $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $webhook_secret ); } catch(\UnexpectedValueException $e) { // Invalid payload. return $response->withStatus(400); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature. return $response->withStatus(400); } if ($event->type == 'issuing_authorization.request') { $auth = $event->data->object; handleAuthorizationRequest($auth); } return $response->withStatus(200); }); function handleAuthorizationRequest($auth) { // Authorize the transaction. $authorization = \Stripe\Issuing\Authorization::retrieve($auth['id']); $authorization->approve(); }; $app->run();
// Using Express const express = require('express'); const bodyParser = require("body-parser"); const app = express(); app.use(express.json()); // Use JSON parser for all non-webhook routes app.use((req, res, next) => { if (req.originalUrl === "/webhook") { next(); } else { bodyParser.json()(req, res, next); } }); // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Uncomment and replace with a real secret. You can find your endpoint's // secret in your webhook settings. // const webhook_secret = 'whsec_...'; app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => { const sig = request.headers['stripe-signature']; let event; // Verify webhook signature and extract the event. try { event = stripe.webhooks.constructEvent(request.body, sig, webhook_secret); } catch (err) { return response.status(400).send(`Webhook Error: ${err.message}`); } if (event.type === 'issuing_authorization.request') { const auth = event.data.object; handleAuthRequest(auth); } response.json({received: true}); }); const handleAuthRequest = (auth) => { // Authorize the transaction. stripe.issuing.authorizations.approve(auth['id']) } app.listen(4242, () => console.log(`Node server listening on port ${4242}!`));
package com.stripe.sample; import com.stripe.Stripe; import com.stripe.model.issuing.Authorization; import com.stripe.model.Event; import com.stripe.model.EventDataObjectDeserializer; import com.stripe.exception.SignatureVerificationException; import com.stripe.net.Webhook; import com.google.gson.JsonSyntaxException; import spark.Response; // Using Spark. import static spark.Spark.*; public class Server { public static void main(String[] args) { port(4242); // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; post("/webhook", (request, response) -> { String payload = request.body(); String sigHeader = request.headers("Stripe-Signature"); // Uncomment and replace with a real secret. You can find your endpoint's // secret in your webhook settings. // String webhookSecret = "whsec_..."; Event event = null; // Verify webhook signature and extract the event. try { event = Webhook.constructEvent( payload, sigHeader, webhookSecret ); } catch (JsonSyntaxException e) { // Invalid payload. response.status(400); return ""; } catch (SignatureVerificationException e) { // Invalid signature. response.status(400); return ""; } if ("issuing_authorization.request".equals(event.getType())) { // Deserialize the nested object inside the event EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer(); Session session = null; if (dataObjectDeserializer.getObject().isPresent()) { auth = (Authorization) dataObjectDeserializer.getObject().get(); handleAuthorizationRequest(auth); } else { // Deserialization failed, probably due to an API version mismatch. // Refer to the Javadoc documentation on `EventDataObjectDeserializer` for // instructions on how to handle this case, or return an error here. } } response.status(200); return ""; }); } private static void handleAuthorizationRequest(Authorization auth) { // Authorize the transaction. Authorization authorization = Authorization.retrieve(auth.getId()); authorization.approve(); } }
package main import ( "encoding/json" "log" "fmt" "net/http" "io/ioutil" "github.com/stripe/stripe-go/v71" "github.com/stripe/stripe-go/v71/webhook" "github.com/stripe/stripe-go/v71/issuing/authorization" "os" ) func main() { // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" http.HandleFunc("/webhook", handleWebhook) addr := "localhost:4242" log.Printf("Listening on %s ...", addr) log.Fatal(http.ListenAndServe(addr, nil)) } func handleWebhook(w http.ResponseWriter, req *http.Request) { const MaxBodyBytes = int64(65536) req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes) body, err := ioutil.ReadAll(req.Body) if err != nil { fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err) w.WriteHeader(http.StatusServiceUnavailable) return } // Uncomment and replace with a real secret. You can find your endpoint's // secret in your webhook settings. // webhookSecret := "whsec_..." // Verify webhook signature and extract the event. event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), webhookSecret) if err != nil { fmt.Fprintf(os.Stderr, "Error verifying webhook signature: %v\n", err) w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature. return } if event.Type == "issuing_authorization.request" { var auth stripe.IssuingAuthorization err := json.Unmarshal(event.Data.Raw, &auth) if err != nil { fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err) w.WriteHeader(http.StatusBadRequest) return } handleAuthorizationRequest(auth) } w.WriteHeader(http.StatusOK) } func handleAuthorizationRequest(auth stripe.IssuingAuthorization) { // Authorize the transaction. _, _ = authorization.Approve(auth.ID, &stripe.IssuingAuthorizationParams{}) }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Stripe; using Stripe.Checkout; namespace Controllers { public class ConnectController : Controller { private readonly ILogger<ConnectController> logger; public ConnectController( ILogger<ConnectController> logger, ) { this.logger = logger; } [HttpPost("webhook")] public async Task<IActionResult> ProcessWebhookEvent() { var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(); // Uncomment and replace with a real secret. You can find your endpoint's // secret in your webhook settings. // const string webhookSecret = "whsec_..."; // Verify webhook signature and extract the event. try { var stripeEvent = EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], webhookSecret); if (stripeEvent.Type == Events.CheckoutSessionCompleted) { var session = stripeEvent.Data.Object as Session; HandleCheckoutSession(session); } return Ok(); } catch (Exception e) { logger.LogInformation(e.ToString()); return BadRequest(); } } private void HandleAuthorizationRequest(Authorization auth) { // Authorize the transaction. var service = new AuthorizationService(); var authorization = service.Approve(auth.getId()); } } }

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. Once 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. Once you have it installed, you can forward events to your server:

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.

stripe trigger issuing_authorization.request

Learn more about setting up webhooks.

Was this page helpful?
Questions? Contact us.
Developer tutorials on YouTube.
You can unsubscribe at any time. Read our privacy policy.