Audit failed Stripe payments in DynamoDB with a Slack triage note

When a Stripe charge fails, save the failure to your DynamoDB audit table with duplicate protection and post a Slack triage line that says how worried to be.

Agentic Task
Amazon DynamoDBStripeSlack BotFinanceOperationsNotifications & Alerts
PromptCreate

When Stripe fires a charge.failed webhook, log the failure to a DynamoDB audit table and post a triage line to the finance Slack channel that classifies how worried we should be.

Trigger: Stripe webhook, event type charge.failed. The event payload includes the failed charge id, customer id, amount, and failure reason.

Steps:

  1. Read the charge id, customer id, amount, and failure reason from the charge.failed event payload.

  2. Use Stripe Retrieve Customer with that customer id to pull the customer's name and email.

  3. Use Stripe List Charges filtered by that customer id and a created timestamp in the last 90 days, so we can see prior successes and failures in that window. Count the failures (status = failed) for use in the classification and the audit row.

  4. Use Amazon DynamoDB Query against the payment_failures table with a KeyConditionExpression on the customer_id partition key, to fetch any prior failure rows already on file for this customer.

  5. Use Amazon DynamoDB Put Item to write a new row to payment_failures with customer_id as the partition key, charge_id as the sort key, and the following attributes: amount, failure_reason, customer_id, timestamp (event created), and prior_90d_failures (the count from step 3). Set ConditionExpression to attribute_not_exists(charge_id) so a retried webhook cannot double-write. If DynamoDB returns ConditionalCheckFailedException, treat it as an already-logged duplicate: stop the workflow cleanly and do NOT post to Slack again.

  6. Use Slack Bot Send a Message to post a single-line triage note to the finance channel. Include the customer name, the amount, the failure reason, and a link to the Stripe dashboard entry at https://dashboard.stripe.com/payments/{charge_id}. Prefix the note with exactly one of these three classifications:

    • "first time, likely a card issue" — the customer has zero prior failures in the last 90 days AND is not over the high-value threshold.

    • "recurring, dunning candidate" — the customer has one or more prior 90-day failures AND is not over the high-value threshold.

    • "high-value customer, human review" — the customer's lifetime revenue exceeds the configurable threshold, regardless of prior failure count.

Computing lifetime revenue: sum the amount of all succeeded charges returned by Stripe List Charges for the customer. If you already carry lifetime revenue elsewhere, use that instead.

Rules:

  • Never DM the customer directly. This workflow is internal only. No Stripe emails, no SMS, no customer-facing messages.

  • Only escalate to "high-value customer, human review" when lifetime revenue exceeds the configured threshold.

  • If Put Item's ConditionExpression fails (ConditionalCheckFailedException), stop the workflow. Do not re-post to Slack. This is the expected idempotency path for retried Stripe webhooks.

  • The DynamoDB table must exist ahead of time with customer_id as the partition key and charge_id as the sort key.

Configurables:

  • financeChannelId — the Slack channel id the triage note is posted to.

  • highValueRevenueThresholdUsd — lifetime revenue above which a customer is escalated to human review. Default: 10000.

  • lookbackDays — window used to count prior failures and successes. Default: 90.

  • tableName — DynamoDB table name. Default: payment_failures.

Additional information

What does this prompt do?
  • Fires the moment Stripe reports a failed charge.
  • Pulls the customer's name, email, and last 90 days of Stripe charges to see if this failure is a one-off or a pattern.
  • Writes a durable row to your DynamoDB payment_failures table with duplicate protection, so retried webhooks do not double-log.
  • Posts a one-line triage to your finance Slack channel that classifies the failure and links to the Stripe dashboard entry.
What do I need to use this?
  • A Stripe account with API access, and a charge.failed webhook pointed at this workflow.
  • An AWS account with a DynamoDB table named payment_failures (customer_id as the partition key, charge_id as the sort key).
  • A Slack workspace and the internal channel you want triage notes posted to.
How can I customize it?
  • The lifetime revenue threshold that flips a customer into human-review territory.
  • Which Slack channel gets the triage note (finance, revenue ops, on-call).
  • The 90-day lookback window used to decide whether a failure is a first-timer or a repeat.
  • The DynamoDB table name if you already use a different one for audit rows.

Frequently asked questions

Does this message the customer directly?
No. This workflow is internal only. It writes to your audit table and posts to your Slack channel. It never emails, texts, or DMs the customer.
What happens if Stripe retries the same webhook?
The database write is protected against duplicates on the charge id, so a retried webhook cannot create a second row or fire a second Slack alert. Retries stop cleanly.
Do I need to create the DynamoDB table first?
Yes. Create a table (default name: payment_failures) with customer_id as the partition key and charge_id as the sort key before you turn the workflow on.
What counts as high-value for the human-review escalation?
Whatever number you configure. The default is a lifetime revenue threshold you set once, and any customer over that number gets flagged for a human to review instead of routed to normal dunning.
Can I use Microsoft Teams or Discord instead of Slack?
Yes. Swap the Slack step for whichever team chat you use. The rest of the workflow (Stripe lookup, DynamoDB audit row, classification logic) stays identical.

Related templates

Daily Braintree declined-payment recovery digest to Slack

Every weekday at 8am, your billing team gets a Slack rundown of yesterday's failed Braintree charges, the revenue at risk, and who to chase first.

Braintree
Slack Bot
Agentic Task
Weekday Azure DevOps sprint standup digest in Slack

Every weekday morning, roll up your sprint's work items into a clear per-person standup summary and post it to your team's Slack channel before you meet.

Azure DevOps
Slack Bot
Agentic Task
Track new Braintree disputes before the deadline slips

Every three hours we scan Braintree for new disputes and chargebacks, open a tracked ticket with a tailored evidence checklist, and alert your team in Slack before the response deadline slips.

Braintree
Zendesk
Slack Bot
Agentic Task
Daily Databricks data health check with Slack alerts

Every weekday morning we check your most important Databricks tables for freshness and data problems, and ping Slack only when something actually looks wrong.

Databricks
Slack Bot
Agentic Task
Monday morning employee breach exposure briefing in Slack

Every Monday, automatically find which employee accounts on your company domain turned up in data breaches and get a plain-English briefing in Slack.

Have I Been Pwned
Slack Bot
Agentic Task
Instant Slack alert when an Azure DevOps build fails

When a pipeline build fails, we post a tight Slack card naming who pushed, the likely cause, and a link to the build so on-call can triage in seconds.

Azure DevOps
Slack Bot
Agentic Task

Give every failed Stripe charge a durable audit trail and a triaged Slack ping.

Stop letting failed charges disappear into email. Log them, classify them, and route the ones that actually need attention.