RevRule integration reference
RevRule computes who is owed what from economic events and keeps the auditable record. Your payment rail moves the money; RevRule determines the economics. RevRule never holds funds and never executes payments. Base URL https://payload-rail.fly.dev. Every example on this page was run against the live API.
1. Get a free API key
POST /v1/access-keys needs no authentication and returns a free self-serve key:
curl -X POST https://payload-rail.fly.dev/v1/access-keys \
-H "Content-Type: application/json" \
-d '{"label":"my-integration"}'
# -> 201 {"key":"...","accountId":"...","tier":"free"}
The key is shown once, so store it when it is returned. Send it as Authorization: Bearer <key>. A free key can create, activate, simulate, and post events to your own graphs. The $99 one-time license adds the entitlement-gated surfaces, including payout evidence.
2. Create a Revenue Graph
POST /v1/graphs (Bearer key) creates a graph. New graphs start as drafts. The complete spec:
id(string, required): your unique graph id.projectId(string, required): the project the graph belongs to.ownerId(string, required): the id of the owning participant. It must match one of the participants, and that participant must carry the"owner"role.participants(array, required): each entry is{id, kind, roles, payoutDestinations}.revenueSources(array): each entry is{id, kind, config, eventTypes};eventTypeslists the event types the graph accepts.rules(array, required): each entry is{id, type, priority, params}with an optionalconditions. Rule types: percentage, fixed, remainder, referral, recoupment, waterfall, caps. A percentage rule takesrateBps(basis points) and abaseofgrossorremaining;subjectParticipantIdnames the participant the rule pays.
This complete example passes the live validator (platform 5% of gross, creator 70% of the remainder, referrer 25% of the remainder when the event carries attribution, creator takes what is left):
curl -X POST https://payload-rail.fly.dev/v1/graphs \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"id": "creator-split",
"projectId": "creator-split",
"ownerId": "creator",
"participants": [
{"id": "payload_platform", "kind": "company", "roles": ["platform"], "payoutDestinations": []},
{"id": "creator", "kind": "person", "roles": ["creator", "owner"], "payoutDestinations": []},
{"id": "referrer", "kind": "person", "roles": ["referrer"], "payoutDestinations": []}
],
"revenueSources": [
{"id": "x402", "kind": "x402", "config": {}, "eventTypes": ["API_PAYMENT"]}
],
"rules": [
{"id": "platform-fee", "type": "percentage", "priority": 1,
"params": {"rateBps": 500, "subjectParticipantId": "payload_platform", "base": "gross"}},
{"id": "creator-share", "type": "percentage", "priority": 2,
"params": {"rateBps": 7000, "subjectParticipantId": "creator", "base": "remaining"}},
{"id": "referrer-share", "type": "percentage", "priority": 3,
"params": {"rateBps": 2500, "subjectParticipantId": "referrer", "base": "remaining"},
"conditions": {"requireAttribution": true}},
{"id": "creator-remainder", "type": "remainder", "priority": 4,
"params": {"subjectParticipantId": "creator"}}
]
}'
# -> 201, graph returned with "status": "draft"
Activate it before production events:
curl -X POST https://payload-rail.fly.dev/v1/graphs/creator-split/activate \
-H "Authorization: Bearer $KEY"
# -> 200, "status": "active"
3. Post an economic event
POST /v1/graphs/{id}/events (Bearer key) takes the body {"event": {...}}. On this path every field in the envelope is required. The server validates the event before anything is written and answers 400 INVALID_EVENT naming the first missing or invalid field.
eventId: a unique string. Events are idempotent oneventId; a replay returns the original result.graphId: the graph id.type: one ofSALE_COMPLETED,API_PAYMENT,LICENSE_PAID,SUBSCRIPTION_PAYMENT,REFERRAL_CONVERTED,ROYALTY_RECEIVED,CAMPAIGN_MILESTONE,MARKETPLACE_TRANSACTION,TOUCH. Use a type the graph lists in its revenue sourceeventTypes.occurredAt: ISO 8601 timestamp.amountMicros: integer micro-units (1000000 = 1.00). Integers, never strings.currency: for exampleUSD.rail: one ofstripe,ach,x402,manual,stablecoin.processingCostMicros: integer, 0 or more, the processing cost in micro-units.raw: an object holding the source-native payload, retained for audit. It may be an empty object, but it must be present.
curl -X POST https://payload-rail.fly.dev/v1/graphs/creator-split/events \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"event":{"eventId":"sale-1","graphId":"creator-split","type":"API_PAYMENT","occurredAt":"2026-10-16T00:00:00Z","amountMicros":25000000,"currency":"USD","rail":"x402","processingCostMicros":0,"raw":{}}}'
Dry run first: POST /v1/graphs/{id}/simulate with the same body returns the entitlements and writes nothing. Read the results with GET /v1/graphs/{id}/ledger.
4. Public evaluate (no key, $0.01)
POST /v1/x402/public/evaluate evaluates one event against a fixed public demo graph (the split in section 2) for $0.01 USDC on Base. No API key is needed. The event is validated before payment: a malformed body gets a 400, and a valid unpaid body gets the x402 v2 402 challenge.
Required event fields on this endpoint: eventId, type (same list as section 3), rail, and amountMicros. currency defaults to USD and occurredAt to the current time when omitted. The endpoint accepts the full envelope from section 3, including processingCostMicros and raw, and that full shape is the one to send. graphId is fixed to the demo graph; do not set it.
One gap to know about: the 402 challenge's advertised bazaar bodySchema lists only type, amountMicros, currency, and occurredAt. eventId and rail are also required, and an event that follows only the advertised schema gets a 400 naming the missing field. This complete example reaches the 402 stage:
curl -X POST https://payload-rail.fly.dev/v1/x402/public/evaluate \
-H "Content-Type: application/json" \
-d '{"event":{"eventId":"eval-1","type":"API_PAYMENT","occurredAt":"2026-10-16T00:00:00Z","amountMicros":25000000,"currency":"USD","rail":"x402","processingCostMicros":0,"raw":{}}}'
# -> 402 with the x402 v2 payment requirements (0.01 USDC, Base, network eip155:8453)
To complete the evaluation, pay the $0.01 to the payTo address in the challenge and resubmit the same body with "txHash": "0x..." added at the top level. Each txHash is single-use.
5. MCP tools
The RevRule MCP server (io.github.payload-tools/revrule-mcp, listed on the official MCP Registry and Smithery) exposes three tools:
revrule_get_graph: read a graph and its current state.revrule_list_payout_evidence: list payout evidence recorded against a graph's entitlements.revrule_simulate_event: dry-run an event. Pass the event in the same{event: ...}envelope as section 3; nothing is written.
6. Errors and limits
Errors return {"error": {"code": "...", "message": "..."}}. The common ones: 400 INVALID_EVENT (the event failed validation; the message names the field), 401 (missing or invalid key), 402 (payment required on the paid endpoints). RevRule computes entitlements and keeps the record; it does not execute payments, hold funds, or guarantee that a payout happens.
More: API reference with the full quickstart · console · in-browser sandbox · llms.txt · OpenAPI · all Payload services