Stripe Get Event Details
Audience:
Low-code EngineersSkill Prerequisites:
Actions,Tokens,API endpoints,Stripe account
Checks that a webhook call really comes from Stripe, and gives you the event type and the event's data as tokens. Use it at the start of an API endpoint that Stripe sends its webhook events to.
The action checks the Stripe-Signature header of the request with your webhook's signing secret. It doesn't call Stripe, so it doesn't need a connector.
This action is part of the Stripe add-on (DnnSharp.Stripe). The add-on is installed separately and needs the STRIPE feature in your license. If it isn't licensed, the action fails with a "not licensed" error. If you don't see the Stripe actions, the add-on isn't installed.
Typical Use Cases
- Record each subscription payment, for example on
invoice.payment_succeeded - Remove access when a subscription ends, on
customer.subscription.deleted - React to refunds, disputes or failed payments
- Handle events for payments that weren't made with Stripe Checkout
Don't use it to
- Fulfill a Stripe Checkout payment. Stripe Checkout has its own webhook and runs On Webhook Call for that.
- Read the details of an event by its ID. The action only reads the request Stripe sent.
- Handle PayPal notifications. Use PayPal - Parse IPN Request instead.
Related Actions
| Action Name | Description |
|---|---|
| Parse JSON Into Tokens | Reads fields from the event data, for example the customer or amount. |
| Raw Response | Returns the response to Stripe, for example a 200 status. |
| Run SQL Query | Saves the event data in your database. |
| Stripe Checkout | Takes payments and handles their checkout.session.completed event itself. |
| Stripe Create Subscription | Creates subscriptions whose events you can handle here. |
Input Parameter Reference
| Parameter | Description | Supports Tokens | Default | Required |
|---|---|---|---|---|
| Raw Json Input | The request body exactly as Stripe sent it. Use [RawInput], which the API endpoint fills in. Don't change or rebuild the JSON, or the signature check fails. | Yes | empty string | Yes |
| Event Type Output Token | The name of a token to save the event type in, for example StripeEventType. | No | empty string | No |
| Event JSON Output Token | The name of a token to save the event's data object in, as JSON, for example StripeObject. | No | empty string | No |
Output Parameters Reference
| Parameter | Description |
|---|---|
| Event Type Output Token | The event type, for example invoice.payment_succeeded or charge.refunded. |
| Event JSON Output Token | The object the event is about, as JSON, for example the invoice or the charge. It's the event's data.object, not the whole event. Read its fields with Parse JSON Into Tokens. |
For the rest of the event, such as its id or livemode, parse [RawInput] with Parse JSON Into Tokens.
Setting up the webhook
-
Create the API endpoint. Add a
POSTmethod and put this action first in its action list. Stripe doesn't sign in, so give the API public access. The signature check is what protects it. -
Add the webhook in Stripe. In the Stripe dashboard, add a webhook endpoint with your API's URL, and pick the events you want.
-
Save the signing secret. Copy the endpoint's signing secret (
whsec_...) and add it to theappSettingssection of your site'sweb.config. Add the portal ID to the key name to use a different secret for each portal:<add key="DnnSharpStripeEventApiSigningSecretKey_0" value="whsec_..." />A key without the portal ID,
DnnSharpStripeEventApiSigningSecretKey, is used for any portal that doesn't have its own. -
Answer with
200. Stripe needs a2xxresponse, or it tries to send the event again. If no action returns a response, the API returnsSuccesswith a200status. You can also use Raw Response.
Security
The action fails, and the actions after it don't run, when:
- The
Stripe-Signatureheader is missing from the request. - The signature doesn't match the body and the signing secret, for example because the request didn't come from Stripe or the body was changed.
- The event is too old. The signature's timestamp must be within 5 minutes, so a captured request can't be replayed later.
- No signing secret is set in
web.config. The error saysStripe API Key was not found., but it's the signing secret that's missing. - Raw Json Input is empty.
Stripe sees an error response and retries the event. Keep these points in mind:
- Put the action first. Actions before it run for any caller, including fake ones.
- One secret per portal. Each Stripe webhook endpoint has its own signing secret, and the action reads one secret per portal. Send all Stripe events for a portal to one API endpoint, and branch on the event type.
- Test and live mode have different secrets. Update
web.configwhen you switch. - Handle repeats. Stripe may send the same event more than once. Save the event
idfrom[RawInput]and skip events you've already processed.
Considerations
- It doesn't check the event with Stripe. The signature proves the event came from Stripe, so there's no need to fetch it again. If you need the latest state of an object, get it from Stripe separately, for example with Server Request.
- Branch on the event type. Use conditions such as
[StripeEventType] == "invoice.payment_succeeded"on the actions that follow. - Answer quickly. Stripe waits only a short time for the response. Run slow work, such as sending many emails, with Execute Actions Asynchronously.
- Don't send
checkout.session.completedtwice. If you also use Stripe Checkout, its webhook already handles that event. - Where it works. API endpoints only.
Examples
To understand how to use the below examples, please see Running Examples.
1. Record subscription payments
These actions check the event, and when it's invoice.payment_succeeded, save the paid invoice for its subscription. Then they answer Stripe with 200.
[
{
"Title": "Stripe Get Event Details",
"ActionType": "StripeGetEventDetails",
"Description": "Check the Stripe signature and read the event",
"Parameters": {
"RawJsonInput": "[RawInput]",
"EventTypeOutputToken": "StripeEventType",
"EventJsonOutputToken": "StripeObject"
}
},
{
"Title": "Parse JSON Into Tokens",
"ActionType": "ParseJsonIntoTokens",
"Description": "Read the invoice",
"Condition": "[StripeEventType] == \"invoice.payment_succeeded\"",
"Parameters": {
"JsonString": "[StripeObject]",
"BaseTokenName": "Invoice"
}
},
{
"Title": "Run SQL Query",
"ActionType": "RunSql",
"Description": "Save the payment",
"Condition": "[StripeEventType] == \"invoice.payment_succeeded\"",
"Parameters": {
"SqlQuery": "INSERT INTO SubscriptionPayments (InvoiceId, SubscriptionId, CustomerId, AmountPaid) SELECT @InvoiceId, @SubscriptionId, @CustomerId, @AmountPaid WHERE NOT EXISTS (SELECT 1 FROM SubscriptionPayments WHERE InvoiceId = @InvoiceId)",
"BindTokens": [
{
"name": "InvoiceId",
"value": "[Invoice:id]"
},
{
"name": "SubscriptionId",
"value": "[Invoice:subscription]"
},
{
"name": "CustomerId",
"value": "[Invoice:customer]"
},
{
"name": "AmountPaid",
"value": "[Invoice:amount_paid]"
}
]
}
},
{
"Title": "Raw Response",
"ActionType": "RawResponse",
"Description": "Tell Stripe the event was received",
"Parameters": {
"Content": "OK",
"HttpCode": "200"
}
}
]
amount_paid is in the currency's smallest unit, for example cents.
Revised 09/27/2026