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.

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.

FAQs

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

Build a credential rotation checklist when someone leaves

When someone leaves, we check which shared passwords they used in their final months and post a ranked rotation list to your security channel.

1Password
Rippling
Slack Bot
+1
Agentic Task
Weekly Amazon S3 bucket security audit posted to Slack

Every Monday, check every S3 bucket for public exposure, missing encryption and weak backup settings, then get the risks ranked in Slack.

Amazon S3
Slack Bot
Google Sheets
Agentic Task
Log Agorapulse social conversations to HubSpot contacts

Twice every weekday, the conversations from your social inbox land on the right HubSpot contact timelines, with a Slack recap for sales.

Agorapulse
HubSpot
Slack Bot
Agentic Task
Clean up HubSpot contacts from your Amazon SES suppression list

Every morning, find the addresses that hard bounced or filed a spam complaint, update the matching HubSpot contacts, and post a short Slack recap.

Amazon SES
HubSpot
Slack Bot
Agentic Task
Draft polite follow-ups for emails that never got a reply

Every weekday at 4pm, spot the threads that went quiet, stage a ready-to-send nudge in your mailbox, and get a ranked Slack recap.

Aurinko
Google Sheets
Slack Bot
Agentic Task
Replay failed SQS messages when a bug fix is merged

When you merge a fix in GitHub, this agent checks the matching dead-letter queue, replays the failed messages, and reports back on the pull request and in Slack.

Amazon SQS
GitHub
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.