Handle incoming Stripe webhook events
curl --request POST \
--url https://api.decimal.ai/api/v1/billing/webhook \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.decimal.ai/api/v1/billing/webhook"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.decimal.ai/api/v1/billing/webhook', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.decimal.ai/api/v1/billing/webhook",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.decimal.ai/api/v1/billing/webhook"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.decimal.ai/api/v1/billing/webhook")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.decimal.ai/api/v1/billing/webhook")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodybilling
Handle incoming Stripe webhook events
Handle incoming Stripe webhook events.
This endpoint receives events from Stripe’s webhook system. It verifies the signature using the webhook secret, then routes to the appropriate handler. No API key auth required — Stripe signs with its own secret.
Handles:
- checkout.session.completed → upgrade plan (+ store the subscription id)
- invoice.payment_failed → start grace period
- customer.subscription.updated → sync plan from the subscription’s price
- customer.subscription.deleted → downgrade to free
- invoice.paid → confirm renewal, clear grace period
A handler failure 5xxs so STRIPE RETRIES (safe under dispatch_event’s idempotency-claim protocol); success returns 200.
POST
/
api
/
v1
/
billing
/
webhook
Handle incoming Stripe webhook events
curl --request POST \
--url https://api.decimal.ai/api/v1/billing/webhook \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.decimal.ai/api/v1/billing/webhook"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.decimal.ai/api/v1/billing/webhook', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.decimal.ai/api/v1/billing/webhook",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.decimal.ai/api/v1/billing/webhook"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.decimal.ai/api/v1/billing/webhook")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.decimal.ai/api/v1/billing/webhook")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyAuthorizations
Enter your API key (e.g. dai_sk_test_key_001)
Response
Successful Response