agentleFS
charanjit-singhcharanjit-singh/lovable-skills/skills/payment-webhook-idempotency/SKILL.md

payment-webhook-idempotency

Skill10 starsChanged 6 months agoMITView on GitHub

Use when Stripe or payment webhooks fire twice, need duplicate event handling, stripe_webhook_events table, ordering, or safe retries. Not for first-time webhook setup without idempotency concerns (use stripe-payment-webhooks).

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If work fails after partial writes, prefer:

    line 46

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Payment webhook idempotency

Stripe retries webhooks on non-2xx, slow responses, or network blips. Handlers must be safe to run multiple times for the same event.id.

Rules

  1. Insert event.id first (or check existence) before side effects.
  2. On duplicate event.id, return 200 immediately — do not re-grant credits or extend subscription twice.
  3. Side effects (DB upsert, emails, credits) must be upserts keyed by stable IDs (subscription_id, payment_intent_id), not blind inserts.

Table

create table public.stripe_webhook_events (
  id text primary key,
  type text not null,
  livemode boolean,
  processed_at timestamptz not null default now()
);

-- RLS: no client access; edge function uses service role only
alter table public.stripe_webhook_events enable row level security;
-- no policies for anon/authenticated

Handler flow

receive event
  → verify signature
  → if event.id exists in stripe_webhook_events → 200 OK (duplicate)
  → begin logical work
  → upsert subscription / order (idempotent on stripe_subscription_id)
  → insert stripe_webhook_events
  → 200 OK

If work fails after partial writes, prefer:

  • Transaction where possible, or
  • Compensating upsert on retry, or
  • Insert event id only after success (accept rare double-work on crash — mitigate with unique constraints on business keys)

Unique constraints (business layer)

alter table public.subscriptions
  add constraint subscriptions_stripe_sub_id_unique unique (stripe_subscription_id);

create table public.orders (
  id uuid primary key default gen_random_uuid(),
  stripe_payment_intent_id text unique,
  user_id uuid not null,
  amount_cents int not null,
  status text not null
);

Ordering

Events may arrive out of order (subscription.updated before checkout.session.completed). Upsert from latest Stripe object via API retrieve when unsure, or handle both paths to the same upsert function.

Avoid

  • insert into credits (amount) values (100) without idempotency key per event.
  • Returning 500 after successfully granting access (causes retry + duplicate grant).
  • Deleting webhook event rows in production.

Checklist

  • Primary key = Stripe event.id
  • Duplicate returns 200
  • Business tables have unique Stripe IDs

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.