feat: add revenuecat-api-v2 reference skill

Server-side reference for the RevenueCat REST API v2: endpoint map,
sk_/atk_ auth, pagination, expandables, rate limits, error types, and
write-safety. Symlinked into ~/.claude/skills and listed in README.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Dunmow 2026-06-15 13:22:57 +08:00 committed by Alex Dunmow
parent b8535ff7d9
commit 182d64403e
2 changed files with 481 additions and 0 deletions

View File

@ -14,6 +14,7 @@ Each skill directory (and command file under `commands/`) is symlinked back into
- **developing-blockninja-plugins** — creating, building, and publishing BlockNinja CMS plugins/themes - **developing-blockninja-plugins** — creating, building, and publishing BlockNinja CMS plugins/themes
- **fleet** — apply a change across many BlockNinja repos with per-repo verification - **fleet** — apply a change across many BlockNinja repos with per-repo verification
- **grill-with-docs** — stress-test a plan against the domain model and update docs inline - **grill-with-docs** — stress-test a plan against the domain model and update docs inline
- **revenuecat-api-v2** — server-side reference for the RevenueCat REST API v2 (endpoints, auth, write-safety)
- **shipit** — full BlockNinja plugin/theme pre-publish pipeline - **shipit** — full BlockNinja plugin/theme pre-publish pipeline
- **star-response-builder** — turn experience/achievements into STAR-style responses - **star-response-builder** — turn experience/achievements into STAR-style responses
- **workorder** — generate numbered work-order documents (WO-NNN) - **workorder** — generate numbered work-order documents (WO-NNN)

480
revenuecat-api-v2/SKILL.md Normal file
View File

@ -0,0 +1,480 @@
---
name: revenuecat-api-v2
description: Use when integrating, inspecting, automating, or debugging the RevenueCat REST API v2 server-side — reading customer subscription/entitlement/access state, creating or updating customers and attributes, granting or revoking promotional access, managing products, entitlements, offerings, packages, paywalls, apps, or webhooks, and handling refunds, cancellations, metrics, audit logs, or receipt/state migrations. Covers the v2 endpoint map, sk_/atk_ auth, pagination, expandables, rate limits, error types, and write-safety. Server-side REST, not the client SDK.
---
# RevenueCat API v2 Skill
Use this skill when integrating, inspecting, automating, or debugging RevenueCat REST API v2.
## Source of truth
Use the current official RevenueCat API v2 docs before implementing. API v2 is still under development and does not cover every v1 use case. Use v1 only when v2 lacks the required endpoint.
Base URL:
```text
https://api.revenuecat.com/v2
```
## When to use SDK vs REST
Use the RevenueCat SDK for normal client purchase flows.
Use REST API v2 for server-side work:
- reading customer subscription/access state
- creating or updating customers and attributes
- granting or revoking promotional access
- managing products, entitlements, offerings, packages, paywalls, apps, webhooks
- refunds, cancellations, subscription management URLs
- metrics, audit logs, invoices, virtual currencies
- migrations where the backend already has receipts or user state
## Authentication
Every request uses:
```http
Authorization: Bearer <token>
```
Valid tokens:
- `sk_...` secret API key: server-to-server, project-scoped.
- `atk_...` OAuth access token: third-party tools, developer-scoped.
- Public SDK keys are for SDK/client configuration only. Never use secret keys in an app, website, repo, or frontend.
API v1 keys do not work with API v2. Create a v2 secret key and assign only the endpoint permissions needed.
## Required request habits
For `POST`, `PUT`, and `PATCH`:
```http
Content-Type: application/json
```
Always URL-encode path params such as `customer_id`.
Use environment filters where relevant:
```text
environment=sandbox
environment=production
```
Do not infer production state from sandbox data.
## Core objects
RevenueCat v2 is project-centred.
Common object hierarchy:
```text
Project
Apps
Products
Entitlements
Offerings
Packages
Products
Customers
Attributes
Aliases
Active entitlements
Subscriptions
Purchases
Invoices
Virtual currencies
Paywalls
Webhook integrations
Metrics / audit logs
```
Use `project_id` for almost every v2 endpoint.
## Endpoint map
### Projects and apps
```text
GET /projects
POST /projects
GET /projects/{project_id}/apps
POST /projects/{project_id}/apps
GET /projects/{project_id}/apps/{app_id}
POST /projects/{project_id}/apps/{app_id}
DEL /projects/{project_id}/apps/{app_id}
GET /projects/{project_id}/apps/{app_id}/api_keys
GET /projects/{project_id}/apps/{app_id}/store_kit_config
```
### Customers
```text
GET /projects/{project_id}/customers
POST /projects/{project_id}/customers
GET /projects/{project_id}/customers/{customer_id}
DEL /projects/{project_id}/customers/{customer_id}
GET /projects/{project_id}/customers/{customer_id}/active_entitlements
GET /projects/{project_id}/customers/{customer_id}/subscriptions
GET /projects/{project_id}/customers/{customer_id}/purchases
GET /projects/{project_id}/customers/{customer_id}/aliases
GET /projects/{project_id}/customers/{customer_id}/attributes
POST /projects/{project_id}/customers/{customer_id}/attributes
```
Customer search currently supports exact email matching via `$email`.
### Customer actions
```text
POST /projects/{project_id}/customers/{customer_id}/actions/transfer
POST /projects/{project_id}/customers/{customer_id}/actions/grant_entitlement
POST /projects/{project_id}/customers/{customer_id}/actions/revoke_granted_entitlement
POST /projects/{project_id}/customers/{customer_id}/actions/assign_offering
POST /projects/{project_id}/customers/{customer_id}/actions/restore_purchase_by_order_id
```
Granting an entitlement creates a promotional subscription. Revoking it expires that promotional subscription. Treat both as user-impacting writes.
### Subscriptions
```text
GET /projects/{project_id}/subscriptions/{subscription_id}
GET /projects/{project_id}/subscriptions
GET /projects/{project_id}/subscriptions/{subscription_id}/transactions
GET /projects/{project_id}/subscriptions/{subscription_id}/entitlements
GET /projects/{project_id}/subscriptions/{subscription_id}/authenticated_management_url
POST /projects/{project_id}/subscriptions/{subscription_id}/actions/cancel
POST /projects/{project_id}/subscriptions/{subscription_id}/actions/extend
POST /projects/{project_id}/subscriptions/{subscription_id}/actions/refund
POST /projects/{project_id}/subscriptions/{subscription_id}/transactions/{transaction_id}/actions/refund
```
Use subscription fields such as `gives_access`, `status`, `auto_renewal_status`, `pending_payment`, `current_period_ends_at`, `store_subscription_identifier`, and `total_revenue_in_usd`. Prefer `gives_access` and active entitlements over hand-rolled expiry logic.
### Purchases
```text
GET /projects/{project_id}/purchases/{purchase_id}
GET /projects/{project_id}/purchases/{purchase_id}/entitlements
GET /projects/{project_id}/purchases
POST /projects/{project_id}/purchases/{purchase_id}/actions/refund
```
Use purchase search when starting from a store purchase identifier.
### Product catalog
```text
GET /projects/{project_id}/entitlements
POST /projects/{project_id}/entitlements
GET /projects/{project_id}/entitlements/{entitlement_id}
POST /projects/{project_id}/entitlements/{entitlement_id}
DEL /projects/{project_id}/entitlements/{entitlement_id}
POST /projects/{project_id}/entitlements/{entitlement_id}/actions/archive
POST /projects/{project_id}/entitlements/{entitlement_id}/actions/unarchive
POST /projects/{project_id}/entitlements/{entitlement_id}/actions/attach_products
POST /projects/{project_id}/entitlements/{entitlement_id}/actions/detach_products
GET /projects/{project_id}/products
POST /projects/{project_id}/products
GET /projects/{project_id}/products/{product_id}
POST /projects/{project_id}/products/{product_id}
DEL /projects/{project_id}/products/{product_id}
POST /projects/{project_id}/products/{product_id}/actions/archive
POST /projects/{project_id}/products/{product_id}/actions/unarchive
POST /projects/{project_id}/products/{product_id}/create_in_store
```
Product creation does not create Web Billing products. Store push has store-specific requirements.
### Offerings and packages
```text
GET /projects/{project_id}/offerings
POST /projects/{project_id}/offerings
GET /projects/{project_id}/offerings/{offering_id}
POST /projects/{project_id}/offerings/{offering_id}
DEL /projects/{project_id}/offerings/{offering_id}
GET /projects/{project_id}/offerings/{offering_id}/packages
POST /projects/{project_id}/offerings/{offering_id}/packages
GET /projects/{project_id}/offerings/{offering_id}/packages/{package_id}
POST /projects/{project_id}/offerings/{offering_id}/packages/{package_id}
DEL /projects/{project_id}/offerings/{offering_id}/packages/{package_id}
POST /projects/{project_id}/offerings/{offering_id}/packages/{package_id}/actions/attach_products
POST /projects/{project_id}/offerings/{offering_id}/packages/{package_id}/actions/detach_products
```
Deleting an offering also deletes attached packages.
### Paywalls
```text
POST /projects/{project_id}/paywalls/media
GET /projects/{project_id}/paywalls
POST /projects/{project_id}/paywalls
GET /projects/{project_id}/paywalls/{paywall_id}
PATCH /projects/{project_id}/paywalls/{paywall_id}
DEL /projects/{project_id}/paywalls/{paywall_id}
```
Paywall updates affect drafts.
### Webhooks
```text
GET /projects/{project_id}/integrations/webhooks
POST /projects/{project_id}/integrations/webhooks
GET /projects/{project_id}/integrations/webhooks/{webhook_integration_id}
POST /projects/{project_id}/integrations/webhooks/{webhook_integration_id}
DEL /projects/{project_id}/integrations/webhooks/{webhook_integration_id}
```
Webhook fields include name, URL, optional authorization header, environment, event types, and optional app scope.
### Metrics and audit
```text
GET /projects/{project_id}/metrics/overview
GET /projects/{project_id}/metrics/revenue
GET /projects/{project_id}/metrics/charts/{chart_id}
GET /projects/{project_id}/metrics/charts/{chart_id}/options
GET /projects/{project_id}/audit_logs
GET /projects/{project_id}/collaborators
```
Metrics have stricter rate limits than customer reads.
## Pagination
List responses use:
```json
{
"object": "list",
"items": [],
"next_page": "...",
"url": "..."
}
```
Use:
- `limit`, default `20`
- `starting_after`
- `next_page` until absent
Pagination is forward-only.
## Expandables
Use `expand` when an endpoint supports it to fetch related objects in one request.
Example:
```text
GET /projects/{project_id}/customers/{customer_id}?expand=attributes
```
Only request expansions the API key has permission to read.
## Rate limits
Default domains:
- Customer Information: 480 requests/minute
- Charts & Metrics: 25 requests/minute
- Project Configuration: 60 requests/minute
- Virtual Currency transaction creation: 480 requests/minute
Read these headers:
- `RevenueCat-Rate-Limit-Current-Usage`
- `RevenueCat-Rate-Limit-Current-Limit`
- `Retry-After` on `429`
Back off on `429`, `423`, retryable `5xx`, and any response with `retryable: true` or `backoff_ms`.
## Error handling
RevenueCat uses normal HTTP status classes:
- `2xx`: success
- `4xx`: client/auth/validation/conflict/rate-limit issue
- `5xx`: RevenueCat/upstream issue
Error bodies include fields like:
```json
{
"type": "parameter_error",
"param": "customer_id",
"message": "id is too long",
"retryable": false,
"doc_url": "..."
}
```
Common error types:
- `authentication_error`: bad token
- `authorization_error`: token lacks access to project/permission
- `invalid_request`: wrong method or missing JSON content type
- `parameter_error`: invalid path/query/body value
- `rate_limit_error`: wait using `backoff_ms` / `Retry-After`
- `resource_missing`: bad ID or deleted resource
- `resource_already_exists`: duplicate ID
- `resource_locked_error`: concurrent modification
- `store_error`: upstream app store problem
- `unprocessable_entity_error`: valid syntax, impossible operation
- `entity_references_archived_entities`: unarchive referenced objects first
## Write safety
Before any write, state:
- method and endpoint
- required permission
- affected object IDs
- side effects
- whether it touches production or sandbox
Do not perform destructive/user-impacting writes unless explicitly authorized.
Treat these as high-risk:
- deleting customers, apps, products, offerings, paywalls, webhooks
- granting/revoking entitlements
- transferring purchases/subscriptions
- refunding purchases/subscriptions
- cancelling/extending subscriptions
- changing production product catalog
- changing production webhooks
For uncertain writes, provide a dry-run request and explain expected result.
## Common workflows
### Check whether a customer has access
1. Fetch the customer:
```text
GET /projects/{project_id}/customers/{customer_id}
```
2. Fetch active entitlements:
```text
GET /projects/{project_id}/customers/{customer_id}/active_entitlements
```
3. Fetch subscriptions if detail is needed:
```text
GET /projects/{project_id}/customers/{customer_id}/subscriptions?environment=production
```
Use `active_entitlements` and subscription `gives_access`. Do not invent access rules from expiry dates alone.
### Find a customer by email
```text
GET /projects/{project_id}/customers?search=user@example.com
```
This searches exact `$email` attribute matches.
### Set customer attributes
```text
POST /projects/{project_id}/customers/{customer_id}/attributes
Content-Type: application/json
```
Use reserved attribute names like `$email` only according to RevenueCats rules. Keep custom attribute names short and stable.
### Grant temporary access
```text
POST /projects/{project_id}/customers/{customer_id}/actions/grant_entitlement
```
Explain that this creates a promotional subscription.
### Revoke granted access
```text
POST /projects/{project_id}/customers/{customer_id}/actions/revoke_granted_entitlement
```
Explain that this expires the promotional subscription.
### Build a product catalogue view
Read in this order:
1. apps
2. products
3. entitlements
4. entitlement product attachments
5. offerings
6. packages
7. package product attachments
8. paywalls
Use `expand` where supported.
### Configure webhooks
Create or update:
```text
POST /projects/{project_id}/integrations/webhooks
POST /projects/{project_id}/integrations/webhooks/{webhook_integration_id}
```
Always specify environment intentionally. Use an authorization header for webhook verification. Do not log webhook secrets.
### Refund or cancel
Use the endpoint that matches the store and object:
- Web Billing purchase refund
- Web Billing subscription cancel/refund/extend
- Play Store or Galaxy subscription transaction refund
- subscription management URL for customer-managed changes
Always confirm production environment and affected subscription/purchase ID.
## Response standards
When answering RevenueCat API questions:
- identify SDK vs REST
- identify v1 vs v2
- state endpoint, method, and required token type
- state required permission scope when relevant
- show minimal `curl` or code using env vars
- never expose real tokens
- call out side effects
- explain retry/backoff behaviour
- convert timestamps to readable ISO dates when shown
- distinguish sandbox from production
- mention when v1 is still required
## Minimal curl pattern
```bash
curl -sS \
-H "Authorization: Bearer $REVENUECAT_API_KEY" \
-H "Content-Type: application/json" \
"https://api.revenuecat.com/v2/projects/$REVENUECAT_PROJECT_ID/customers/$CUSTOMER_ID"
```
For writes:
```bash
curl -sS -X POST \
-H "Authorization: Bearer $REVENUECAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"key":"value"}' \
"https://api.revenuecat.com/v2/projects/$REVENUECAT_PROJECT_ID/..."
```