| name | doctor |
| description | Audits an existing PagoKit integration in the current project. Checks .gitignore covers .env, that env vars are present and use test-key prefixes, that the webhook secret looks valid, that the webhook handler verifies signatures, that the minimum events for the integrated provider are routed, and that PAGOKIT_INTEGRATION.md exists. Used by /pagokit:doctor. Read-only โ never writes files. |
| when_to_use | - The user invokes /pagokit:doctor
- The user asks "is my payment integration set up correctly?", "did I miss something?", "is this safe to ship?"
- The integration-specialist subagent wants a sanity check before declaring an integration complete
|
| allowed-tools | Read, Glob, Grep, Bash(ls *), Bash(test *) |
doctor
You audit an existing PagoKit-generated integration. Read-only. Never write files.
Source of truth
The first thing you read is PAGOKIT_INTEGRATION.md in the project root. It was written by integration-specialist when the integration was generated and contains:
- The provider (
stripe | mercadopago | wompi | lemonsqueezy)
- The list of files created
- The list of events handled vs TODO
- The deploy target
- The detected stack/ORM
- The
last_generated_at timestamp
- The pinned SDK version
If PAGOKIT_INTEGRATION.md does not exist, this is NOT necessarily an error โ the user may have an integration that predates PagoKit. In that case, ask the user "I don't see PAGOKIT_INTEGRATION.md. Was this integration generated by PagoKit? If not, I can still audit a known provider โ which one are you using?"
Audit checklist
Run each check and report a list of [OK] / [WARN] / [FAIL] lines. Group by category. At the end, summarize: "N OK, M warnings, K failures."
Category 1 โ Environment hygiene
| Check | How | Severity |
|---|
.gitignore exists and includes .env (or .env* minus .env.example) | Read .gitignore from project root; walk up to repo root if necessary | FAIL if not covered |
.env not committed to git | If .git/ exists, check git ls-files .env would be empty | FAIL if committed |
.env.example exists | Glob .env.example | WARN if missing |
.env.example contains only test-key prefixes (from providers.json.developer_experience.test_keys_prefix) | Read it, grep for live prefixes | FAIL if live keys present |
Category 2 โ Required env vars per provider
Load providers.json. For the integrated provider, the user's .env (read but don't echo!) should contain at minimum:
- Stripe:
STRIPE_SECRET_KEY starting with sk_test_ or sk_live_; STRIPE_PUBLISHABLE_KEY starting with pk_; STRIPE_WEBHOOK_SECRET starting with whsec_.
- Mercado Pago:
MP_ACCESS_TOKEN matching secret_key_pattern; MP_WEBHOOK_SECRET.
- Wompi:
WOMPI_PRIVATE_KEY matching ^prv_(test|prod)_ ; WOMPI_PUBLIC_KEY matching ^pub_(test|prod)_ ; WOMPI_EVENTS_SECRET.
- Lemon Squeezy:
LEMONSQUEEZY_API_KEY matching ^lmnsq_(test|live)_; LEMONSQUEEZY_WEBHOOK_SECRET.
For each required variable:
[OK] โ present and matches pattern
[FAIL] โ missing
[FAIL] โ present but doesn't match pattern
[WARN] โ uses _live_ / _prod_ prefix (production key during audit; the user should know)
Category 3 โ Webhook handler quality
For each webhook file declared in PAGOKIT_INTEGRATION.md (or detected via expected_filenames from providers.json.webhook):
[OK/FAIL] โ the file imports or calls the provider's canonical verifier (or carries the // @pagokit:signature-verified tag).
[OK/FAIL] โ the route uses raw body capture appropriate for the stack (per Rule 5 / SECURITY_RULES.md).
[OK/FAIL] โ the handler's switch covers every event in providers.json.webhook.required_events_minimum. Unhandled events should at least be logged with a TODO comment.
[WARN] โ if the file contains console.log(event) or similar (Rule 6).
[OK/FAIL] โ replay protection: if replay_mitigation_strategy requires event-id-dedup, look for a query against webhook_events_processed (or equivalent).
Category 4 โ Idempotency
[OK/FAIL] โ the checkout endpoint generates an idempotency key with crypto.randomUUID() / uuid.uuid4() / SecureRandom.uuid (Rule 4).
[OK/FAIL] โ the DB has an idempotency_keys table (or equivalent file declared in PAGOKIT_INTEGRATION.md).
Category 5 โ DB schema
If the integration declares an ORM (Prisma / Drizzle / SQLAlchemy / Active Record), verify these tables exist in the schema file:
payments (or provider-named, e.g. stripe_payments)
subscriptions (if billing_mode == subscription)
customers
idempotency_keys
webhook_events_processed
Category 6 โ Production readiness pointer
Last check: does PAGOKIT_PRODUCTION_CHECKLIST.md exist in the project root?
[OK] โ exists; remind user to read it before flipping to live keys.
[WARN] โ missing; suggest re-running /pagokit:start to regenerate it.
Output format
PagoKit Doctor โ <provider> integration audit
Generated <last_generated_at> ยท stack: <stack> ยท deploy: <deploy_target>
Environment hygiene
[OK] .gitignore covers .env
[OK] .env not tracked in git
[OK] .env.example uses test prefixes
...
Webhook handler
[OK] app/api/webhook/stripe/route.ts verifies signature
[OK] raw body captured correctly (Next.js App Router pattern)
[FAIL] customer.subscription.updated not routed (expected per Rule providers.json)
...
(continue per category)
Summary: 17 OK ยท 2 warnings ยท 1 failure
Next steps:
1. Route the missing event customer.subscription.updated (see templates/stripe/subscription.md).
2. Address the warnings before going live.
Anti-patterns
- Do NOT echo secret values back to the user when reporting (read
.env but report [OK]/[FAIL], never the value).
- Do NOT write files, run migrations, or modify anything โ strictly read-only.
- Do NOT fail loudly if the project has no PagoKit-generated artifacts. Offer to set up an audit for a known provider instead.
- Do NOT recommend fixes that require live keys (e.g., don't tell the user to "go to dashboard and rotate the webhook secret" as the first step โ first verify the test sandbox passes).