Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add Venkateshwar-Reddy-Jambula/razorpay-integration-plugin --skill webhookgit clone --depth 1 https://github.com/Venkateshwar-Reddy-Jambula/razorpay-integration-pluginWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/venkateshwar-reddy-jambula/razorpay-integration-plugin/webhook)<a href="https://agentmods.dev/skills/venkateshwar-reddy-jambula/razorpay-integration-plugin/webhook"><img src="https://agentmods.dev/badge/skills/venkateshwar-reddy-jambula/razorpay-integration-plugin/webhook/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/venkateshwar-reddy-jambula/razorpay-integration-plugin/webhook"><img src="https://agentmods.dev/badge/skills/venkateshwar-reddy-jambula/razorpay-integration-plugin/webhook.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00066 | $0.03647 |
| Opus 5 | $0.00033 | $0.01824 |
| Sonnet 5 | $0.00013 | $0.00729 |
| Haiku 4.5 | $0.00007 | $0.00365 |
Grade A, and why
webhook scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 10d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 445 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Razorpay Webhook Handler
Build a webhook handler that survives production chaos: duplicate events, race conditions, out-of-order delivery, and partial failures.
Critical Rules
- Always return 200 for events you don't handle — Razorpay retries on non-2xx
- Verify signature FIRST before any processing
- Idempotency is mandatory — Razorpay uses at-least-once delivery
- Never trust event order —
subscription.chargedmay arrive beforesubscription.activated
Signature Verification
import crypto from "crypto";
function verifyWebhookSignature(rawBody: string, signature: string, secret: string): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
// MUST use timing-safe comparison to prevent timing attacks
try {
return crypto.timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(signature, "hex")
);
} catch {
return false; // Length mismatch = invalid
}
}
Full Webhook Route
// app/api/billing/webhook/route.ts
import crypto from "crypto";
export async function POST(request: Request) {
// 1. Read raw body (NOT parsed JSON — signature is computed on raw string)
const rawBody = await request.text();
const signature = request.headers.get("x-razorpay-signature");
if (!signature) {
return new Response("Missing signature", { status: 400 });
}
// 2. Verify signature
const isValid = verifyWebhookSignature(
rawBody,
signature,
process.env.RAZORPAY_WEBHOOK_SECRET!
);
if (!isValid) {
return new Response("Invalid signature", { status: 400 });
}
// 3. Parse event
const event = JSON.parse(rawBody);
const eventType = event.event;
// 4. Extract event ID (prefer header over payload)
const eventId = request.headers.get("x-razorpay-event-id") || event.id || null;
// 5. Extract subscription ID (multi-path — different event types store it differently)
const subscriptionId = extractSubscriptionId(event);
if (!subscriptionId) {
// Non-subscription event (standalone payment, order, etc.) — acknowledge and skip
return new Response("OK", { status: 200 });
}
// 6. Idempotency check (multi-layer)
const subscription = await getSubscriptionByRazorpayId(subscriptionId);
// Layer 1: Exact event ID match (same event delivered twice)
if (subscription?.lastEventId === eventId && eventId) {
return new Response("Already processed", { status: 200 });
}
// Layer 2: Check processed_events table for this event ID
// Razorpay can send the same logical event with different event IDs on retry
if (eventId) {
const alreadyProcessed = await db
.select()
.from(processedWebhookEvents)
.where(eq(processedWebhookEvents.eventId, eventId))
.limit(1);
if (alreadyProcessed.length > 0) {
return new Response("Already processed", { status: 200 });
}
}
// 7. Handle event
try {
await handleEvent(eventType, event, subscription, eventId);
// Record processed event for idempotency
if (eventId) {
await db.insert(processedWebhookEvents).values({
eventId,
eventType,
subscriptionId,
processedAt: new Date(),
}).onConflictDoNothing(); // Safe if duplicate insert races
}
} catch (error) {
console.error("Webhook processing error:", error);
// Still return 200 to prevent retries on app errors
// Log for manual investigation
}
return new Response("OK", { status: 200 });
}
// Subscription ID lives in different places depending on event type
function extractSubscriptionId(event: any): string | null {
return (
event.payload?.subscription?.entity?.id ||
event.payload?.payment?.entity?.subscription_id ||
event.payload?.invoice?.entity?.subscription_id ||
null
);
}
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 10d ago First seen · 445 lines · 66 tokens per session scan A bdcef02672f7
webhook is a skill published in the GitHub repository Venkateshwar-Reddy-Jambula/razorpay-integration-plugin (6 stars, last pushed 5mo ago), licensed MIT. It adds 66 tokens to every session and 3,647 once invoked, about $0.0003 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other skills, from other repositories
convex-billing
Add Stripe billing/payments to the Convex app via @convex-dev/stripe (checkout + webhook + gating).
cloudbase-wechat-integration
A guide for connecting CloudBase applications to WeChat services, including payments, official accounts, and user identity.
commerce-app-business-config
Manage custom business configuration in an Adobe Commerce app. Use when the user wants to add, modify, or remove merchant-configurable settings (config fields, admin config, store configuration) exposed through Commerce Admin. Creates typed config fields (text, password, email, url, tel, boolean, list) in…
baselinker-webhooks
Receive BaseLinker (Base.com) webhooks. Use when building a BaseLinker order or warehouse callback receiver, because BaseLinker is not a normal webhook source: deliveries arrive as HTTP HEAD requests with NO body, the entire payload is in the query string (observed params: orderid, state), there is NO signature…
b2c-custom-job-steps
Create custom job steps for B2C Commerce batch processing. Use this skill whenever the user needs to write a batch job, data export script, scheduled cleanup task, or any server-side processing that runs on a schedule. Also use when they ask about steptypes.json, chunk-oriented vs task-oriented job steps…
tiktok-shop-webhooks
Receive and verify TikTok Shop webhooks. Use when setting up TikTok Shop webhook handlers, debugging Authorization-header signature verification, or handling events like ORDERSTATUSCHANGE, PACKAGEUPDATE, RECIPIENTADDRESSUPDATE, PRODUCTSTATUSCHANGE, or SELLERDEAUTHORIZATION.