chore(claude): refresh razorpay skills/agents against live Razorpay docs#815
chore(claude): refresh razorpay skills/agents against live Razorpay docs#815teetangh wants to merge 2 commits into
Conversation
Full audit of all 24 razorpay .claude files against current docs (2026-06-07) — the bundle predated complete Razorpay documentation. Corrections: refund enums/events (pending/optimum, refund.* not payment.refund.*), fictional subscription params removed (notify_info, pause/resume_initiated_by, customer_id on create), go-live auto-capture claim un-inverted, current test cards/OTP rules, current_end (not current_period_end), 24h-then-auto-disable webhook retry model. Rewrites: plan-change now uses the Update Subscription API (native proration) instead of deferred cancellation; razorpay-invoice generates its own GST invoices (API invoices are non-GST) with the IGST place-of-supply branch. Added: subscription signature order (payment_id|subscription_id), X-Refund-Idempotency, settlements, webhook replay, dispute events. cancel(id, boolean) guidance kept — verified correct for the pinned razorpay@2.9.6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
❌ Deploy Preview for familiarise failed. Why did it fail? →
|
📝 WalkthroughWalkthroughComprehensive Razorpay integration documentation update covering GST-compliant invoice generation with place-of-supply logic, refund idempotency headers and status tracking, optional subscription customer pre-creation, in-place plan updates, webhook production safety (return 200 for unhandled events), and field corrections (current_end vs current_period_end). Updates affect 23 agent and skill documentation files with 337 lines changed. ChangesGST-Compliant Invoice System
Refund Idempotency & Status Lifecycle
Subscription Customer & Plan Management
Webhook Handler Production Safety & Idempotency
SDK Quirks Reference & Local Testing
Admin & Operational Guidance
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request updates the Razorpay integration documentation, agents, and skills to align with GST compliance requirements (specifically handling place-of-supply for CGST/SGST vs. IGST and self-generating invoices), the in-place Update Subscription API, and updated SDK behaviors. The review feedback highlights that the official razorpay Node SDK does not support passing per-request headers (such as X-Refund-Idempotency) as a third argument to helper methods like payments.refund(). Additionally, the feedback points out inconsistencies in the webhook agent and skill templates where createGstInvoice still uses the legacy, non-compliant pattern, and suggests adding refund.failed and refund.speed_changed to the local testing webhook registration list.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
.claude/agents/razorpay-webhook.md (2)
158-160:⚠️ Potential issue | 🟠 Major | ⚡ Quick winEvent mapping still uses
current_period_endinstead of the updated Razorpay field modelThis table still tells implementers to persist/update
current_period_end, which conflicts with your own Step 4b guidance (current_end, with conversion). That inconsistency will lead to mixed implementations.Unify these rows to the same contract used later in the doc (read
current_end, then map to your DB field).Also applies to: 163-163
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/agents/razorpay-webhook.md around lines 158 - 160, Update the event mapping table rows for subscription.activated, subscription.charged and subscription.pending to use the Razorpay field name current_end (with the same conversion note from Step 4b) instead of current_period_end, and clarify that implementers should read current_end from the webhook payload and then map/convert it to the DB column (e.g., current_period_end) as described in Step 4b; ensure the subscription.pending rule still includes the "don't downgrade an active subscription" guard and that the charged row mentions updating current_end for the new billing cycle and triggering GST invoice creation.
224-225:⚠️ Potential issue | 🟠 Major | ⚡ Quick winGST invoice instructions are out of sync with the refreshed GST model
This section still mandates CGST/SGST split line-items as the default pattern. Per this PR’s stated GST rewrite, invoice generation should use place-of-supply logic and support IGST where applicable rather than hardcoding CGST/SGST-only decomposition.
Please update this agent’s GST instructions/snippet to match the new GST contract used in the invoice-focused docs.
Also applies to: 361-362
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/agents/razorpay-webhook.md around lines 224 - 225, The createGstInvoice() guidance is outdated: replace the hardcoded CGST/SGST split with logic that uses the new GST contract and place-of-supply rules so invoices choose CGST+SGST or IGST as appropriate before building Razorpay Invoice line items; update the createGstInvoice() implementation (or its stub comment) to reference and follow the invoice-focused GST contract, compute tax line items based on placeOfSupply and supplier/state vs. customer/state, and include a note on enabling GST generation per the new contract (also update the duplicate guidance near the other occurrence corresponding to the same createGstInvoice() behavior)..claude/agents/razorpay-diagnostics.md (1)
141-142:⚠️ Potential issue | 🟠 Major | ⚡ Quick winSchema check still enforces Stripe-style period field name
CHECK 4bstill requirescurrent_period_end, but this PR’s webhook contract elsewhere standardizes on Razorpay’scurrent_end(mapped into app field naming as needed). Keepingcurrent_period_endas the required canonical column here will generate misleading diagnostics.Please align this check with the updated field contract (accept/store the app’s mapped period-end field while sourcing from
current_endin payloads).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/agents/razorpay-diagnostics.md around lines 141 - 142, CHECK 4b currently enforces the Stripe-style column names (`current_period_end` / `currentPeriodEnd`); update the check to accept the Razorpay contract by requiring the period-end field to be `current_end` (and/or the app-mapped name used elsewhere, e.g., `currentEnd`) as the canonical period-end column while still accepting `last_event_id` / `lastEventId` for idempotency; modify the validation logic that references `current_period_end` to also accept `current_end` and the app field mapping so diagnostics reflect the new webhook contract..claude/skills/razorpay/webhook/SKILL.md (1)
370-372:⚠️ Potential issue | 🟠 Major | ⚡ Quick winWebhook skill still encodes the deprecated CGST/SGST-only invoice pattern
The GST section and sample implementation hardcode base+CGST+SGST line items, which conflicts with the refreshed GST model that depends on place-of-supply and may require IGST.
Please align this skill’s GST guidance/snippet with the new conditional tax logic so generated handlers don’t reintroduce outdated invoice behavior.
Also applies to: 382-405
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/razorpay/webhook/SKILL.md around lines 370 - 372, Update the GST guidance and sample implementation in SKILL.md (the Razorpay webhook skill GST section and its sample handler) to stop hardcoding base+CGST+SGST line items and instead implement conditional tax logic: determine place-of-supply (seller vs buyer state), compute tax type as CGST+SGST when intra-state or IGST when inter-state, calculate tax amounts from the taxable base, and construct Razorpay Invoice API line items accordingly (one base line item plus one or two tax line items as required). Ensure the sample snippet clearly shows the place-of-supply check, tax rate application, and creation of line items compatible with the Invoice API so generated handlers will not reintroduce the deprecated CGST/SGST-only pattern..claude/skills/razorpay/subscription/SKILL.md (1)
185-186:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDedup response contract contradicts the route example.
This section says “block duplicate creation (409)”, but the route example returns
200with the existingshortUrlfor recent pending subscriptions. Pick one behavior and keep it consistent across the doc to avoid divergent implementations.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/razorpay/subscription/SKILL.md around lines 185 - 186, The doc currently contradicts itself: the deduplication bullets say "block duplicate creation (409)" while the route example returns 200 with an existing shortUrl for recent pending subscriptions; choose one behavior and make the doc consistent by either (A) changing the bullet to describe returning 200 with the existing shortUrl for recent (<1h) pending subscriptions, or (B) changing the route example to return 409 and the corresponding error shape for duplicates; update all mentions of "dedup", "shortUrl", and the route example so the response code, body schema, and text align with the chosen behavior..claude/skills/razorpay/one-time-payment/SKILL.md (1)
19-25:⚠️ Potential issue | 🟠 MajorSplit/clarify subscription verification models (webhook-only vs Standard Checkout).
The table says subscription confirmation is webhook-only (
subscription.activated), but the doc also states subscriptions run via Standard Checkout when passingsubscription_id. Standard Checkout subscription flows require verifying the authorization callback signature (razorpay_payment_id/razorpay_subscription_id/razorpay_signature) using the API secret, in addition to validating the webhook signature usingRAZORPAY_WEBHOOK_SECRET(e.g.,X-Razorpay-Signatureover the raw body). Please explicitly separate these variants (and the corresponding secrets) to prevent implementations from using the wrong signature/secret path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/razorpay/one-time-payment/SKILL.md around lines 19 - 25, Update the subscription verification docs to split webhook-only vs Standard Checkout flows: explicitly state that webhook-only subscriptions are validated via the webhook event (e.g., subscription.activated) using RAZORPAY_WEBHOOK_SECRET and X-Razorpay-Signature over the raw body, while Standard Checkout subscriptions (when passing subscription_id to the JS SDK/handler or using short_url with subscription_id) require verifying the authorization callback signature (razorpay_payment_id, razorpay_subscription_id, razorpay_signature) using RAZORPAY_KEY_SECRET (API secret); call out the exact fields to verify for each path and ensure the table rows for "Verification", "Key used for HMAC", and "Where it runs" reflect these two distinct models to prevent mixing secrets..claude/skills/razorpay/stripe-migration/SKILL.md (1)
216-216:⚠️ Potential issue | 🟠 MajorFix
short_urlguidance in the Stripe→Razorpay migration skill
.claude/skills/razorpay/stripe-migration/SKILL.mdstates “Noshort_urlretrieval… cannot be fetched after subscription creation”, but Razorpay’s API docs and the other skills in this repo sayshort_urlis returned byrazorpay.subscriptions.fetch(id)(so recovery runbooks shouldn’t assume you must recreate the subscription just because you lost the URL). Update/remove the bullet at line 216 to match the documented behavior (and clarify any lifecycle caveats only if they affect usability).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/razorpay/stripe-migration/SKILL.md at line 216, Update the note about short_url: remove or replace the claim that Razorpay's hosted checkout URL "cannot be fetched after subscription creation" and instead state that razorpay.subscriptions.fetch(id) returns short_url per Razorpay API; adjust the bullet at line 216 to say you can recover the hosted checkout URL by calling razorpay.subscriptions.fetch(subscriptionId) and only mention lifecycle caveats if they change URL availability (e.g., if the subscription is canceled or expired), referencing the short_url field and the fetch method in the text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/agents/razorpay-invoice.md:
- Around line 83-90: Choose a single canonical contract for non-applicable tax
heads and apply it consistently: change calculateGST to return null for
non-applicable components (update calculateGST signature/return structure and
set cgstAmount, sgstAmount, igstAmount to null instead of 0 when not
applicable), and update the agent’s schema examples and insertion comments (the
table guidance and insert examples referenced near the schema examples and
insertion comments) to use null for non-applicable tax heads as well so all
examples, docs, and returned objects use the nullable convention.
- Around line 58-59: The prompt hardcodes SAC codes 998314/998315 which
conflicts with the project's existing payout SAC constants (currently the 999293
family); either update the canonical payout SAC constants in the codebase in the
same rollout or change this prompt to derive the SAC value from the project's
payout SAC constant(s) (the existing 999293-family constant) at runtime instead
of hardcoding 998314/998315 so generated invoices remain consistent with the
runtime constant.
In @.claude/skills/razorpay/customer-portal/SKILL.md:
- Line 359: The SKILL.md guidance is stale: it references a non-existent
createGstInvoice() webhook handler and the unused razorpay.invoices.create()
flow. Either implement the missing flow (add a createGstInvoice() implementation
and any code that calls razorpay.invoices.create() to generate GST-compliant
invoices and persists razorpay_invoice_id and short_url), or update the
documentation to reflect the current architecture by removing the
createGstInvoice() and invoices.create() mentions and replacing them with the
actual process used today (e.g., “issue GST invoices via Dashboard” or “our
system generates GST invoices via X”), and ensure the docs still instruct
storing razorpay_invoice_id and short_url if applicable.
In @.claude/skills/razorpay/go-live/SKILL.md:
- Line 16: The dashboard navigation label in the SKILL.md guidance is
inconsistent with other runbooks; update the line referencing "Account &
Settings → Payment Capture" to use the same phrasing as other docs (e.g.,
"Settings → Payments → Automatic capture delay") or include both labels
side-by-side (e.g., "Settings → Payments → Automatic capture delay (a.k.a.
Account & Settings → Payment Capture)") and keep the rest of the note about
Orders API `payment.capture` unchanged so operators can find the setting
reliably.
In @.claude/skills/razorpay/refund/SKILL.md:
- Around line 27-37: The Razorpay adapter calls razorpay.payments.refund but
does not attach the required X-Refund-Idempotency header; update the refund
creation code in the Razorpay integration (the function that invokes
razorpay.payments.refund) to pass an options/headers object including
"X-Refund-Idempotency" with a unique key (>=10 chars) such as
`refund-${paymentId}` (or another deterministic unique token), and apply the
same change to the other refund call sites referenced by the review (the other
razorpay.refund invocations); ensure the header is sent in the third argument to
razorpay.payments.refund so duplicate-protection is enforced.
- Around line 45-48: The docs reference refund.speedRequested and
refund.speedProcessed but the runtime persistence contract lacks those
columns/writes; either remove those fields from the SKILL.md examples or add
them to the persistence layer. To fix, update the persistence schema (the Refund
model) to include speed_requested and speed_processed (and run migration) and
then update the webhook-to-DB mapping in the refund processing code where the
refund object is built (the code that assigns refund.status) to set
refund.speedRequested = refund.speed_requested and refund.speedProcessed =
refund.speed_processed (or the inverse mapping from snake_case DB fields),
ensuring consistent field names across the Prisma model and the webhook/utils
mapping.
---
Outside diff comments:
In @.claude/agents/razorpay-diagnostics.md:
- Around line 141-142: CHECK 4b currently enforces the Stripe-style column names
(`current_period_end` / `currentPeriodEnd`); update the check to accept the
Razorpay contract by requiring the period-end field to be `current_end` (and/or
the app-mapped name used elsewhere, e.g., `currentEnd`) as the canonical
period-end column while still accepting `last_event_id` / `lastEventId` for
idempotency; modify the validation logic that references `current_period_end` to
also accept `current_end` and the app field mapping so diagnostics reflect the
new webhook contract.
In @.claude/agents/razorpay-webhook.md:
- Around line 158-160: Update the event mapping table rows for
subscription.activated, subscription.charged and subscription.pending to use the
Razorpay field name current_end (with the same conversion note from Step 4b)
instead of current_period_end, and clarify that implementers should read
current_end from the webhook payload and then map/convert it to the DB column
(e.g., current_period_end) as described in Step 4b; ensure the
subscription.pending rule still includes the "don't downgrade an active
subscription" guard and that the charged row mentions updating current_end for
the new billing cycle and triggering GST invoice creation.
- Around line 224-225: The createGstInvoice() guidance is outdated: replace the
hardcoded CGST/SGST split with logic that uses the new GST contract and
place-of-supply rules so invoices choose CGST+SGST or IGST as appropriate before
building Razorpay Invoice line items; update the createGstInvoice()
implementation (or its stub comment) to reference and follow the invoice-focused
GST contract, compute tax line items based on placeOfSupply and supplier/state
vs. customer/state, and include a note on enabling GST generation per the new
contract (also update the duplicate guidance near the other occurrence
corresponding to the same createGstInvoice() behavior).
In @.claude/skills/razorpay/one-time-payment/SKILL.md:
- Around line 19-25: Update the subscription verification docs to split
webhook-only vs Standard Checkout flows: explicitly state that webhook-only
subscriptions are validated via the webhook event (e.g., subscription.activated)
using RAZORPAY_WEBHOOK_SECRET and X-Razorpay-Signature over the raw body, while
Standard Checkout subscriptions (when passing subscription_id to the JS
SDK/handler or using short_url with subscription_id) require verifying the
authorization callback signature (razorpay_payment_id, razorpay_subscription_id,
razorpay_signature) using RAZORPAY_KEY_SECRET (API secret); call out the exact
fields to verify for each path and ensure the table rows for "Verification",
"Key used for HMAC", and "Where it runs" reflect these two distinct models to
prevent mixing secrets.
In @.claude/skills/razorpay/stripe-migration/SKILL.md:
- Line 216: Update the note about short_url: remove or replace the claim that
Razorpay's hosted checkout URL "cannot be fetched after subscription creation"
and instead state that razorpay.subscriptions.fetch(id) returns short_url per
Razorpay API; adjust the bullet at line 216 to say you can recover the hosted
checkout URL by calling razorpay.subscriptions.fetch(subscriptionId) and only
mention lifecycle caveats if they change URL availability (e.g., if the
subscription is canceled or expired), referencing the short_url field and the
fetch method in the text.
In @.claude/skills/razorpay/subscription/SKILL.md:
- Around line 185-186: The doc currently contradicts itself: the deduplication
bullets say "block duplicate creation (409)" while the route example returns 200
with an existing shortUrl for recent pending subscriptions; choose one behavior
and make the doc consistent by either (A) changing the bullet to describe
returning 200 with the existing shortUrl for recent (<1h) pending subscriptions,
or (B) changing the route example to return 409 and the corresponding error
shape for duplicates; update all mentions of "dedup", "shortUrl", and the route
example so the response code, body schema, and text align with the chosen
behavior.
In @.claude/skills/razorpay/webhook/SKILL.md:
- Around line 370-372: Update the GST guidance and sample implementation in
SKILL.md (the Razorpay webhook skill GST section and its sample handler) to stop
hardcoding base+CGST+SGST line items and instead implement conditional tax
logic: determine place-of-supply (seller vs buyer state), compute tax type as
CGST+SGST when intra-state or IGST when inter-state, calculate tax amounts from
the taxable base, and construct Razorpay Invoice API line items accordingly (one
base line item plus one or two tax line items as required). Ensure the sample
snippet clearly shows the place-of-supply check, tax rate application, and
creation of line items compatible with the Invoice API so generated handlers
will not reintroduce the deprecated CGST/SGST-only pattern.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: fd1ae832-cf03-45f7-a368-ec88dbcc3ed7
📒 Files selected for processing (21)
.claude/agents/razorpay-code-audit.md.claude/agents/razorpay-db-schema.md.claude/agents/razorpay-diagnostics.md.claude/agents/razorpay-invoice.md.claude/agents/razorpay-one-time-payment.md.claude/agents/razorpay-subscription.md.claude/agents/razorpay-test-webhook.md.claude/agents/razorpay-webhook.md.claude/skills/razorpay/admin/SKILL.md.claude/skills/razorpay/customer-portal/SKILL.md.claude/skills/razorpay/debug/SKILL.md.claude/skills/razorpay/dunning/SKILL.md.claude/skills/razorpay/go-live/SKILL.md.claude/skills/razorpay/local-testing/SKILL.md.claude/skills/razorpay/metrics/SKILL.md.claude/skills/razorpay/one-time-payment/SKILL.md.claude/skills/razorpay/plan-change/SKILL.md.claude/skills/razorpay/refund/SKILL.md.claude/skills/razorpay/stripe-migration/SKILL.md.claude/skills/razorpay/subscription/SKILL.md.claude/skills/razorpay/webhook/SKILL.md
…late alignment, field-name drift Verified against the pinned razorpay@2.9.6 source + live docs, not bot claims. refund snippets now use direct REST calls (the SDK drops a 3rd-arg headers object, so X-Refund-Idempotency was never sent); createGstInvoice templates in the webhook agent/skill + customer-portal now self-generate place-of-supply-aware GST records (API invoices are non-GST); calculateGST standardizes on null for non-applicable tax heads; event-table/diagnostics rows read current_end from payloads; subscription dedup returns 200 with the existing short_url; one-time table splits the two subscription verification paths (callback HMAC is payment_id|subscription_id with key secret — reversed vs orders); stripe-migration drops the stale short_url gotcha; legacy replacesSubscription auto-create labeled as pre-Update-API. Part of #815 review feedback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.claude/skills/razorpay/stripe-migration/SKILL.md (1)
207-207: ⚡ Quick winConsider breaking this long line for readability.
The content is accurate and important, but the 207-character line is difficult to scan. Consider reformatting as a multi-line paragraph or bullet list.
📝 Suggested formatting
-6. **Idempotency keys**: Stripe has a universal `Idempotency-Key` header on every API call. Razorpay's support is per-API rather than universal — specific endpoints accept their own header (e.g. `X-Refund-Idempotency` on refunds, `X-Payout-Idempotency` on payouts). For everything else (and for webhook processing), keep doing app-level dedup yourself. **SDK caveat**: razorpay-node (<=2.9.6) helper methods cannot send per-request headers — `payments.refund(id, params, x)` treats `x` as a callback and silently drops it. Call the REST endpoint directly (basic auth + the header) when you need an idempotency key. +6. **Idempotency keys**: Stripe has a universal `Idempotency-Key` header on every API call. Razorpay's support is per-API rather than universal: + - Specific endpoints accept their own header (e.g. `X-Refund-Idempotency` on refunds, `X-Payout-Idempotency` on payouts) + - For everything else (and for webhook processing), keep doing app-level dedup yourself + - **SDK caveat**: razorpay-node (<=2.9.6) helper methods cannot send per-request headers — `payments.refund(id, params, x)` treats `x` as a callback and silently drops it. Call the REST endpoint directly (basic auth + the header) when you need an idempotency key.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.claude/skills/razorpay/stripe-migration/SKILL.md at line 207, Break the long single-line paragraph under the "Idempotency keys" section into multiple lines for readability: convert it to a short multi-line paragraph or a bullet list that separates the key points (Stripe universal Idempotency-Key vs Razorpay per-endpoint headers like X-Refund-Idempotency and X-Payout-Idempotency), call out the app-level dedup note for webhook processing, and keep the SDK caveat as a separate line that references the razorpay-node (<=2.9.6) behavior and the problematic helper signature payments.refund(id, params, x) so readers can clearly see the recommendation to call the REST endpoint directly (basic auth + header) when an idempotency key is required.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.claude/skills/razorpay/stripe-migration/SKILL.md:
- Line 207: Break the long single-line paragraph under the "Idempotency keys"
section into multiple lines for readability: convert it to a short multi-line
paragraph or a bullet list that separates the key points (Stripe universal
Idempotency-Key vs Razorpay per-endpoint headers like X-Refund-Idempotency and
X-Payout-Idempotency), call out the app-level dedup note for webhook processing,
and keep the SDK caveat as a separate line that references the razorpay-node
(<=2.9.6) behavior and the problematic helper signature payments.refund(id,
params, x) so readers can clearly see the recommendation to call the REST
endpoint directly (basic auth + header) when an idempotency key is required.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 144e0d82-e6a8-4831-a966-421bf42450ff
📒 Files selected for processing (11)
.claude/agents/razorpay-diagnostics.md.claude/agents/razorpay-invoice.md.claude/agents/razorpay-webhook.md.claude/skills/razorpay/customer-portal/SKILL.md.claude/skills/razorpay/debug/SKILL.md.claude/skills/razorpay/local-testing/SKILL.md.claude/skills/razorpay/one-time-payment/SKILL.md.claude/skills/razorpay/refund/SKILL.md.claude/skills/razorpay/stripe-migration/SKILL.md.claude/skills/razorpay/subscription/SKILL.md.claude/skills/razorpay/webhook/SKILL.md
✅ Files skipped from review due to trivial changes (1)
- .claude/skills/razorpay/local-testing/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (6)
- .claude/skills/razorpay/debug/SKILL.md
- .claude/skills/razorpay/one-time-payment/SKILL.md
- .claude/skills/razorpay/customer-portal/SKILL.md
- .claude/skills/razorpay/refund/SKILL.md
- .claude/agents/razorpay-invoice.md
- .claude/skills/razorpay/subscription/SKILL.md
Why
The razorpay skill/agent bundle (9 agents + 15 skills under
.claude/) was drafted when Razorpay's documentation was incomplete or inaccurate. A four-domain audit against the live docs (2026-06-07) found claims ranging from stale to production-breaking. This PR applies every verified correction. The audit cross-checked razorpay.com/docs, the officialrazorpay/markdown-docssource repo, and the project's pinnedrazorpay@2.9.6SDK source.Highest-impact corrections
plan-changerewritten: the "create new subscription + deferred cancellation, no proration" thesis is obsolete —PATCH /v1/subscriptions/:id(schedule_change_at: now|cycle_end) does native in-place plan changes with proration.pendingUpdate()/cancelScheduledChanges()verified present in the pinned SDK.razorpay-invoicerestructured: Razorpay's Invoice API creates non-GST invoices only (tax fields cannot be applied via API) — the CGST/SGST-as-line-items pattern was not compliant. The agent now self-generates GST invoice records and adds the IGST place-of-supply branch (inter-state customers were mis-billed CGST+SGST).pending/processed/failed(nocreated/initiated), speedsnormal/optimum(nooptimized), events arerefund.*(the documentedpayment.refund.*names don't exist — handlers would silently process zero refund webhooks). Addedrefund.speed_changed+X-Refund-Idempotency.go-liveauto-capture claim un-inverted: auto-capture is ON by default; added the ~3-day uncaptured auto-refund window and T+2/T+7 settlement defaults.notify_info,pause_initiated_by/resume_initiated_by(real:pause_at/resume_at),customer_idon create;customer_notifyis a boolean. Native trials (start_at) and setup fees (addons) documented as first-class, not workarounds.current_end(current_period_endis a Stripe-ism), retries back off for 24h then the webhook is auto-disabled (not "indefinite"),x-razorpay-event-idis stable across retries; added dashboard replay (≤15 days) +payment.dispute.*events.4100 2800…family), OTP digit-length rule (no fixed1234),failure@razorpay.subscriptions.cancel(id, boolean)— correct for the pinnedrazorpay@2.9.6; the options-object form silently inverts{cancel_at_cycle_end: false}to a cycle-end cancel on this version (documented as a foot-gun).Scope
21 files changed (+544/−360).
setup/razorpay-setup/helpverified clean and untouched. No application code touched.🤖 Generated with Claude Code
Summary by CodeRabbit