From paygentic
Use when a developer wants to integrate Paygentic into their application using the SDK or raw REST API. Use this skill whenever someone wants to send usage events, create customers, manage subscriptions, check entitlements, retrieve invoices, or set up payments with Paygentic. Works with any language — TypeScript and Python via SDK, all other languages via direct HTTP API. Also use when someone says "set up billing", "add metering", "wire up Paygentic", "integrate Paygentic", or has the @paygentic/sdk or paygentic-sdk package installed. Even if they just say "I want to bill my users" in a project that has Paygentic as a dependency, use this skill.
How this skill is triggered — by the user, by Claude, or both
Slash command
/paygentic:integrateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Write integration code for merchant developers using the SDK (TypeScript, Python) or the raw REST API (any language). Detect their language, understand their setup state, and generate working code.
Write integration code for merchant developers using the SDK (TypeScript, Python) or the raw REST API (any language). Detect their language, understand their setup state, and generate working code.
Before writing any code, determine:
Setup state — Do they have an API key and SDK installed?
Language — Check the project for signals:
package.json with @paygentic/sdk → TypeScript SDKrequirements.txt / pyproject.toml with paygentic-sdk → Python SDKWhat they want to do — metering, customers, subscriptions, entitlements, invoices, or payments
Environment — Always start with sandbox.
https://api.sandbox.paygentic.io)https://api.paygentic.ioIf the developer's message already makes context obvious, skip questions and proceed.
After determining the language:
references/typescript-sdk.mdreferences/python-sdk.mdnet/http for Go, HttpClient for Java, reqwest for Rust, guzzle/curl for PHP).When in doubt, check the API reference and make direct calls. Don't guess at IDs, field names, or configuration — verify by hitting the API.
The full API reference is at docs.paygentic.io/api-reference. Use WebFetch to look up endpoint details when unsure about parameters, request/response shapes, or available query filters.
When debugging or verifying setup, make curl calls directly in the terminal. This is faster than writing SDK code for one-off checks.
Base URL (sandbox): https://api.sandbox.paygentic.io/v0
Common debugging calls:
# List billable metrics — verify event types are configured
curl -s "https://api.sandbox.paygentic.io/v0/billableMetrics?merchantId={MERCHANT_ID}" \
-H "Authorization: Bearer $PAYGENTIC_BEARER_AUTH" | jq
# List customers — verify customer was created
curl -s "https://api.sandbox.paygentic.io/v0/customers?merchantId={MERCHANT_ID}" \
-H "Authorization: Bearer $PAYGENTIC_BEARER_AUTH" | jq
# Get a specific subscription
curl -s "https://api.sandbox.paygentic.io/v0/subscriptions/{SUBSCRIPTION_ID}" \
-H "Authorization: Bearer $PAYGENTIC_BEARER_AUTH" | jq
# List plans — verify plan IDs
curl -s "https://api.sandbox.paygentic.io/v0/plans?merchantId={MERCHANT_ID}" \
-H "Authorization: Bearer $PAYGENTIC_BEARER_AUTH" | jq
# List entitlements for a customer
curl -s "https://api.sandbox.paygentic.io/v0/entitlements?customerId={CUSTOMER_ID}" \
-H "Authorization: Bearer $PAYGENTIC_BEARER_AUTH" | jq
Many debugging scenarios require IDs that only the developer can provide from their dashboard. Proactively ask for these when relevant:
merchantId — their organization ID (visible in dashboard settings)billableMetricId — the metric they're trying to meter againstplanId / productId — the plan or product they're subscribing customers tocustomerId — the Paygentic customer ID (not their internal user ID)subscriptionId — for debugging billing or entitlement issuesDon't make the developer hunt for why something is silently failing — ask for the ID, hit the API, and show them the actual state.
Always start with sandbox. The only difference between sandbox and production is the serverURL and API key.
npm install @paygentic/sdk
import { Paygentic } from "@paygentic/sdk";
// Sandbox (default for initial integration)
const paygentic = new Paygentic({
serverURL: "https://api.sandbox.paygentic.io",
bearerAuth: process.env.PAYGENTIC_BEARER_AUTH,
});
// Production — switch when ready to go live:
// const paygentic = new Paygentic({
// serverURL: "https://api.paygentic.io",
// bearerAuth: process.env.PAYGENTIC_BEARER_AUTH,
// });
pip install paygentic-sdk
import os
from paygentic_sdk import Paygentic
# Sandbox (default for initial integration)
paygentic = Paygentic(
server_url="https://api.sandbox.paygentic.io",
bearer_auth=os.getenv("PAYGENTIC_BEARER_AUTH", ""),
)
# Production — switch when ready to go live:
# paygentic = Paygentic(
# server_url="https://api.paygentic.io",
# bearer_auth=os.getenv("PAYGENTIC_BEARER_AUTH", ""),
# )
Python supports both sync and async. Every method has an _async variant (e.g., customers.create_async()). Use async with Paygentic(...) as paygentic: for async context management.
For languages without an SDK (Go, Java, Ruby, Rust, PHP, etc.), integrate directly with the REST API. The SDKs are thin wrappers — every SDK method maps 1:1 to an HTTP endpoint.
Base URL (sandbox): https://api.sandbox.paygentic.io/v0
Base URL (production): https://api.paygentic.io/v0
Header: Authorization: Bearer <API_KEY>
Content-Type: application/json
Note: Most endpoints use /v0, but entitlements use /v1. This is called out in the examples below.
POST /v0/events
{
"type": "api-call",
"source": "my-api-service",
"subject": "customer_abc123",
"data": {
"tokens": 1500,
"model": "gpt-4"
}
}
Returns 202 Accepted always — fire-and-forget. Optional fields: namespace, timestamp (ISO 8601), idempotencyKey.
POST /v0/customers
{
"merchantId": "org_abc123",
"consumer": {
"name": "Acme Corp",
"email": "[email protected]",
"address": {
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postalCode": "94105",
"country": "US"
}
},
"externalId": "acme-123"
}
Returns 201 Created with { "customerId": "cus_...", "validTaxAddress": { ... } }. Use consumerId instead of consumer to reference an existing consumer.
POST /v0/subscriptions
{
"name": "Acme Pro Subscription",
"planId": "plan_pro_monthly",
"customerId": "cus_abc123",
"startedAt": "2026-04-17T00:00:00Z",
"autoCharge": true
}
Returns 201 Created. Optional fields: endingAt, taxExempt, sessionExpiryMinutes, testClockId, redirectUrls.
GET /v1/entitlements?customerId=cus_abc123&featureKey=api-calls
Note the /v1/ path — entitlements are on v1, not v0.
Returns:
{
"object": "list",
"data": [
{
"hasAccess": true,
"featureKey": "api-calls",
"featureType": "metered",
"balance": 847,
"usageInPeriod": 153,
"status": "active"
}
]
}
GET /v0/billableMetrics?merchantId=org_abc123
GET /v0/plans?merchantId=org_abc123
POST /v0/subscriptions/{id}/terminate
{
"reason": "Customer requested cancellation"
}
POST /v0/subscriptions/{id}/portal-link
| Operation | Method | Path |
|---|---|---|
| Ingest event | POST | /v0/events |
| List customers | GET | /v0/customers?merchantId={id} |
| Create customer | POST | /v0/customers |
| Get customer | GET | /v0/customers/{id} |
| List subscriptions | GET | /v0/subscriptions?merchantId={id} |
| Create subscription | POST | /v0/subscriptions |
| Terminate subscription | POST | /v0/subscriptions/{id}/terminate |
| Portal link | POST | /v0/subscriptions/{id}/portal-link |
| List entitlements | GET | /v1/entitlements?customerId={id} |
| List billable metrics | GET | /v0/billableMetrics?merchantId={id} |
| Query meter usage | GET | /v0/billableMetrics/{id}/meter |
| List plans | GET | /v0/plans?merchantId={id} |
| List invoices | GET | /v0/invoicesV2?subscriptionId={id} |
| Create payment | POST | /v0/payments |
When generating code for a specific language, use the idiomatic HTTP client for that language and translate the JSON bodies above. Always include error handling and the Authorization header. When in doubt about an endpoint, check the API reference.
The most common integration point. Merchants send meter events as customers use their product.
Endpoint: events.ingest() — fire-and-forget. Always returns 202 Accepted. Uses CloudEvents format.
IMPORTANT: Do NOT use usageEvents.create() or usageEvents.batchCreate() — those are v0-only and will error on v1 billing plans.
await paygentic.events.ingest({
type: "api-call", // matches a billable metric's event type
source: "my-api-service", // identifies the sending service
subject: "customer_abc123", // the customer/entity being metered
data: {
tokens: 1500, // usage amount — key must match metric config
model: "gpt-4", // optional dimensions for grouping/filtering
},
});
// Always returns 202 — no confirmation, fire-and-forget
paygentic.events.ingest(
type_="api-call", # note: type_ with underscore (Python reserved word)
source="my-api-service",
subject="customer_abc123",
data={
"tokens": 1500,
"model": "gpt-4",
},
)
Use billableMetrics.meter() to read aggregated usage data:
const usage = await paygentic.billableMetrics.meter({
id: "metric_abc123", // billable metric ID
from: new Date("2026-04-01"), // start of query window
to: new Date("2026-04-30"), // end of query window
subject: "customer_abc123", // optional: filter by customer
windowSize: "DAY", // optional: bucket by DAY, HOUR, MINUTE
});
Sync customers from the merchant's own user model into Paygentic.
const customer = await paygentic.customers.create({
merchantId: "merchant_xyz",
consumer: {
name: "Acme Corp",
email: "[email protected]",
address: {
line1: "123 Main St",
city: "San Francisco",
state: "CA",
postalCode: "94105",
country: "US",
},
},
externalId: "acme-123", // your internal ID for cross-referencing
});
Other operations: customers.list(), customers.get(), customers.update(), customers.delete().
Subscribe customers to plans. Plans are created in the dashboard.
const subscription = await paygentic.subscriptions.create({
name: "Acme Pro Subscription",
planId: "plan_pro_monthly", // from dashboard
customerId: customer.id,
startedAt: new Date(),
autoCharge: true, // charge automatically at period end
});
await paygentic.subscriptions.terminate({
id: subscription.id,
requestBody: {
reason: "Customer requested cancellation",
},
});
Generate a self-service portal URL for customers to manage their subscription:
const portal = await paygentic.subscriptions.generatePortalLink({
id: subscription.id,
});
// portal.url — time-limited URL (default 10 minutes, max 7 days)
Other operations: subscriptions.list(), subscriptions.get().
The most common integration pattern: customer gets N credits/month included in their plan, usage is tracked, and access is gated when credits run out (or overage is billed).
This combines metering + entitlements + grants into one flow.
api-calls) linked to a billable metric. Attach an entitlement template to the price with grant amount and reset period.const entitlements = await paygentic.entitlements.list({
customerId: "customer_abc123",
featureKey: "api-calls",
});
const entitlement = entitlements.data[0];
if (!entitlement || entitlement.balance <= 0) {
// No credits left — block or trigger overage
return res.status(429).json({ error: "API call quota exceeded" });
}
// Credits available — proceed with the request, then track usage
await paygentic.events.ingest({
type: "api.call",
source: "my-api-service",
subject: "customer_abc123",
data: { endpoint: req.path },
});
isSoftLimit: false): Access blocked when balance hits zero. Use for free-tier caps.isSoftLimit: true): Access continues at zero balance, overage is tracked and billed. Use for "1000 included, then $0.01 each."// Top up a customer with additional credits
const grant = await paygentic.entitlements.grants.create({
entitlementId: entitlement.id,
amount: 500, // additional units
});
// Or let the customer purchase credits (creates invoice + payment session)
const purchase = await paygentic.entitlements.grants.purchase({
entitlementId: entitlement.id,
amount: 1000,
});
// purchase — creates ad-hoc invoice with payment session
const grants = await paygentic.entitlements.grants.list({
entitlementId: entitlement.id,
});
// Void a grant (removes from balance)
await paygentic.entitlements.grants.void({
entitlementId: entitlement.id,
grantId: grant.id,
});
Beyond credit-based billing, entitlements also support boolean feature gating (on/off access).
const entitlements = await paygentic.entitlements.list({
customerId: "customer_abc123",
featureKey: "priority-support", // boolean feature
});
const hasAccess = entitlements.data.length > 0;
await paygentic.entitlements.issue({
customerId: "customer_abc123",
featureId: "feature_priority_support",
template: {
type: "boolean",
},
});
Invoices are auto-generated from subscriptions. You can read them and add manual line items.
// List invoices for a subscription
const invoices = await paygentic.invoicesV2.list({
subscriptionId: "sub_abc123",
});
// Get a specific invoice with line items
const invoice = await paygentic.invoicesV2.get({
id: "inv_abc123",
expand: "lineItems",
});
// Add a manual line item (ad-hoc charge or credit)
await paygentic.invoicesV2.createLineItem({
invoiceId: "inv_abc123",
description: "Custom consulting fee",
amount: "250.00",
currency: "USD",
});
# List invoices for a subscription
invoices = paygentic.invoices_v2.list(
subscription_id="sub_abc123",
)
# Get a specific invoice with line items
invoice = paygentic.invoices_v2.get(
id="inv_abc123",
expand="lineItems",
)
# Add a manual line item (ad-hoc charge or credit)
paygentic.invoices_v2.create_line_item(
invoice_id="inv_abc123",
description="Custom consulting fee",
amount="250.00",
currency="USD",
)
Create one-off payment charges. Returns a checkout URL the customer visits to pay.
const payment = await paygentic.payments.create({
amount: "99.00",
currency: "USD",
customerId: "customer_abc123",
reference: "onboarding-fee",
successRedirectUrl: "https://myapp.com/payment/success",
failureRedirectUrl: "https://myapp.com/payment/failed",
lineItems: [
{ description: "Onboarding fee", amount: "99.00" },
],
});
// payment.checkoutUrl — redirect customer here to complete payment
payment = paygentic.payments.create(
amount="99.00",
currency="USD",
customer_id="customer_abc123",
reference="onboarding-fee",
success_redirect_url="https://myapp.com/payment/success",
failure_redirect_url="https://myapp.com/payment/failed",
line_items=[
{"description": "Onboarding fee", "amount": "99.00"},
],
)
# payment.checkout_url — redirect customer here to complete payment
These are available in the SDK but covered lightly here. Ask if the developer needs help with any:
costs.createCost(), costs.getCostSummary())sources.create(), sources.events.approve(), sources.rules.create())testClocks.create(), testClocks.advance())Using v0 usage endpoints with v1 plans — usageEvents.create() and usageEvents.batchCreate() will return an error for v1 billing subscriptions. Always use events.ingest().
Expecting confirmation from ingest — events.ingest() always returns 202 Accepted with no validation. If the event type doesn't match a metric, it's silently ignored. Verify metric configuration in the dashboard — or better, make a direct API call to list billable metrics and confirm the event type matches.
Missing idempotency — For critical metering, pass idempotencyKey to events.ingest() to prevent duplicate charges on retries.
Not using the portal link — Instead of building custom subscription management UI, use subscriptions.generatePortalLink() to give customers self-service access.
Integrating directly against production — Always develop and test against sandbox first (api.sandbox.paygentic.io). Moving to production is just changing the serverURL and API key — no code changes needed.
Guessing at IDs instead of verifying — When events aren't showing up or subscriptions fail, don't guess. Hit the API directly (curl the billable metrics, plans, or customers endpoint) to verify the IDs and configuration are correct.
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub paygentic/skills --plugin paygentic