# payment-idempotency

A skill for payment connector code that keeps Gateway retries from hitting the acquirer twice and charging the customer again.

- skill · `type=skill` · Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode · 1100 installs · ★ 46
- Author: vtex
- License: not stated · policy=link-only · description only; the file stays with the author
- Source: https://github.com/vtex/skills/tree/HEAD/skills/payment-idempotency/SKILL.md
- Updated: 2026-10-14
- HTML: https://affpapa.org/en/nevibecode/skills/payment-idempotency

## What it does

The skill applies when you write Create Payment, Cancel, Capture or Refund handlers in a payment connector, or when duplicate payment requests show up in your logs. It sets the idempotency rules: `paymentId` is the key for Create Payment, `requestId` for cancel, capture and refund. A repeat call with the same `paymentId` returns the stored response instead of calling the acquirer again.

Inside are the payment state transitions (`undefined` → `approved` → `settled`, `undefined` → `denied`, `approved` → `cancelled`) and TypeScript examples: query the store before processing, then return the exact stored response. Async methods such as Boleto and Pix must stay at `status: "undefined"` until the acquirer confirms — approving them synchronously is wrong.

Responses belong in a persistent store: PostgreSQL, DynamoDB or VBase for VTEX IO. In-memory storage loses records on restart, and the Gateway retries Create Payment with `undefined` status for up to 7 days, so each retry reaches the acquirer again. When two retries overlap, last-write-wins can drop a status update, so persist with an etag or `ifMatch`. Worth checking your storage layer before release.

The skill leaves PPP response shapes and HTTP methods, async callback notifications, PCI compliance and POS terminal payments to their own skills.

## Requirements
- Works with: PostgreSQL

## Install

### Claude Code (native platform)

1. **Skills CLI (Vercel)**
```bash
npx skills add vtex/skills --skill payment-idempotency -a claude-code
```

2. **Manually: put the files in place**
- File: `~/.claude/skills/payment-idempotency/SKILL.md` — Copy the whole skill folder; for one project use .claude/skills/payment-idempotency/

### Codex

1. **Skills CLI (Vercel)**
```bash
npx skills add vtex/skills --skill payment-idempotency -a codex
```

2. **Manually: put the files in place**
- File: `.agents/skills/payment-idempotency/SKILL.md` — For all projects use ~/.agents/skills/

### Cursor

1. **Skills CLI (Vercel)**
```bash
npx skills add vtex/skills --skill payment-idempotency -a cursor
```

2. **Manually: put the files in place**
- File: `.cursor/skills/payment-idempotency/SKILL.md` — Cursor also reads .agents/skills/ and .claude/skills/

### GitHub Copilot

1. **GitHub CLI**
```bash
gh skill install vtex/skills payment-idempotency
```

2. **Manually: put the files in place**
- File: `.github/skills/payment-idempotency/SKILL.md`

### Gemini CLI

1. **Skills CLI (Vercel)**
```bash
npx skills add vtex/skills --skill payment-idempotency -a gemini-cli
```

2. **Platform CLI**
```bash
gemini skills install https://github.com/vtex/skills --path skills/payment-idempotency
```

### Windsurf (Devin Desktop)

**Manually: put the files in place**
- File: `.devin/skills/payment-idempotency/SKILL.md` — The legacy .windsurf/skills/ path still works

### OpenCode

**Skills CLI (Vercel)**
```bash
npx skills add vtex/skills --skill payment-idempotency -a opencode
```

### Claude.ai

**Claude.ai**
- Zip the folder and upload it in Settings → Capabilities → Skills

Where a file is given instead of a command, copy the files from the source to that path: https://github.com/vtex/skills/tree/HEAD/skills/payment-idempotency/SKILL.md

## When to use it
- return the stored response on a repeated Create Payment instead of a new charge
- look up `paymentId` in the store before calling the acquirer
- block invalid payment state transitions
- keep Boleto and Pix at `undefined` until the acquirer confirms
- protect status updates from being overwritten by overlapping retries

## Example prompts
- check my Create Payment handler for idempotency on `paymentId`
- why does a Gateway retry create a second charge, and how do I fix it
- add `requestId` handling to my Refund handler

## Similar
- [api-idempotency-retry](https://affpapa.org/en/nevibecode/skills/api-idempotency-retry.md) — skill · 8000 installs
- [payment-testing](https://affpapa.org/en/nevibecode/skills/payment-testing.md) — skill · 978 installs
- [payment-gateway-integration](https://affpapa.org/en/nevibecode/skills/payment-gateway-integration.md) — skill · 524 installs
- [payment-integration](https://affpapa.org/en/nevibecode/skills/payment-integration.md) — skill · 349 installs
- [payment-processing](https://affpapa.org/en/nevibecode/plugins/payment-processing.md) — plugin · ★ 41729
- [prisma-patterns](https://affpapa.org/en/nevibecode/skills/prisma-patterns.md) — skill · 4500 installs

From the same set: [vtex/skills](https://affpapa.org/en/nevibecode/by/vtex/skills.md) — 8 cards

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
