const url = ' https://data.predictefy.com/v1/billing/webhook/stripe ' ;
headers: { ' stripe-signature ' : ' example ' , ' Content-Type ' : ' application/json ' },
const response = await fetch ( url , options );
const data = await response . json ();
--url https://data.predictefy.com/v1/billing/webhook/stripe \
--header ' Content-Type: application/json ' \
--header ' stripe-signature: example ' \
Verifies the stripe-signature header against the RAW request bytes.
Credit grants. A signed, PAID (payment_status=paid, mode=payment)
checkout.session.completed credits the SERVER-RECORDED checkout session EXACTLY ONCE —
the grant amount and account come from the checkout_sessions row written at session
creation, never from Stripe-supplied metadata. Idempotent through the stripe_events
primary key and the session's consumed_at flag; replays and unknown, consumed or unpaid
sessions answer 200 without crediting.
Wave C subscription lifecycle.
A subscription-mode checkout.session.completed consumes and binds the server-side
subscribe intent.
customer.subscription.created mirrors into the subscriptions table ONLY when it traces
back to such an intent. Metadata alone never mints a mirror, and a duplicate open
subscription for an account is acknowledged without a mirror and flagged for manual
cancel and refund.
updated and deleted events only ever UPDATE an existing mirror, never create one.
invoice.paid grants the plan's monthly credits from OUR plans row ONLY for
billing_reason subscription_create or subscription_cycle — prorations and manual invoices
never grant. At most once per billing period (period_start-keyed), never for a canceled
mirror, idempotent through the stripe_events primary key. An ANNUAL subscription is granted
twelve months at once, and only when the mirror (resolved from the Stripe price id) and
the invoice's own line price both say annual AND the invoice's amount_paid is above zero;
otherwise one month is granted. When the event's embedded line list is truncated
(lines.has_more) the remaining lines are read from Stripe first; if they cannot be, the
webhook answers 503 and records nothing, so Stripe retries. A switch between monthly and
annual billing never grants or claws back by itself, and an upgrade grants its delta only
when the funded period and the subscription bill on the same interval (for annual: the
monthly difference x the whole months remaining in the prepaid year). An invoice.paid
for a not-yet-mirrored subscription answers 503 so Stripe retries until the lifecycle
event lands, bounded by Stripe's ~72h retry window.
All grants stay DARK until ops seed plans rows. Other event types are recorded and
acknowledged. Processing errors answer 500 so Stripe retries.
Media type application/json
Raw Stripe event payload (verified byte-exact; never re-serialized).
object
Event acknowledged (credited at most once).
Media type application/json
INVALID_SIGNATURE — verification failed
Media type application/json
object object string
Allowed values: VALIDATION_ERROR NOT_SUPPORTED ACCOUNTS_UNSUPPORTED VENUE_NOT_AVAILABLE EXCHANGE_NOT_AVAILABLE MARKET_NOT_FOUND EVENT_NOT_FOUND TRADERS_UNSUPPORTED TRADER_NOT_FOUND CLUSTER_NOT_FOUND OUTCOME_NOT_FOUND SNAPSHOT_NOT_FOUND CATALOG_UNAVAILABLE CATALOG_QUERY_TOO_BROAD HISTORY_UNAVAILABLE SPORTS_SCREEN_UNAVAILABLE SPORTS_FIXTURE_NOT_FOUND SPORTS_BLOCK_NOT_FOUND ROUTE_NOT_FOUND INTERNAL AUTHENTICATION_ERROR PERMISSION_DENIED RATE_LIMIT_EXCEEDED NETWORK_ERROR NOT_FOUND BAD_REQUEST BRIDGE_UNSUPPORTED BRIDGE_NO_ROUTE BRIDGE_UPSTREAM BRIDGE_PROVIDER_UNAVAILABLE BRIDGE_TRANSACTION_NOT_FOUND BRIDGE_SESSION_NOT_FOUND TRANSFER_PLAN_UNSUPPORTED UNAUTHORIZED SCOPE_MISSING PLAN_REQUIRED INSUFFICIENT_CREDITS RATE_LIMITED GEO_BLOCKED VENUE_REGION_BLOCKED IDEMPOTENCY_KEY_REQUIRED RESERVED_IDEMPOTENCY_KEY IDEMPOTENCY_CONFLICT ARTIFACT_VERSION_CONFLICT SPEND_CAP_EXCEEDED RESERVATION_REQUIRED RESERVATION_CONSUMED RESERVATION_MISMATCH RESERVATION_EXPIRED RESERVATION_RELEASED ARTIFACT_BOUNDS_VIOLATION ARTIFACT_INTEGRITY_MISMATCH CLAIM_GENERATION_UNDETERMINED VENUE_NOT_SUPPORTED EXECUTION_NOT_FOUND EXECUTION_TERMINAL CONDITIONAL_NOT_FOUND CONDITIONAL_NOT_ARMED CONDITIONAL_ATTEMPT_CONFLICT CONDITIONAL_ARMED CONDITIONAL_CLOSED_NOT_SUBMITTED OCO_GROUP_CLOSED HOSTED_FIRE_NOT_ELIGIBLE HOSTED_FIRE_UNAVAILABLE NOT_IMPLEMENTED VENUE_CREDENTIAL_REJECTED VENUE_CREDENTIAL_BREAKER_OPEN GEMINI_TIME_NONCE_REQUIRED GEMINI_HEARTBEAT_KEY_UNSUPPORTED VENUE_RELAY_FAILED EXEC_UNAVAILABLE RAIN_INVALID_OPTION RAIN_INVALID_SIDE RAIN_INVALID_PRICE RAIN_INVALID_AMOUNT RAIN_SLIPPAGE_REQUIRED RAIN_INVALID_DEADLINE RAIN_PHASE_NOT_OPEN RAIN_ORDER_LIMIT_REACHED RAIN_POOL_SAFETY_CHECK_FAILED PLATFORM_UNAVAILABLE PACK_NOT_FOUND BILLING_UNAVAILABLE BILLING_CUSTOMER_REQUIRED PLAN_NOT_FOUND SUBSCRIPTION_EXISTS WEBHOOK_NOT_FOUND INVALID_SIGNATURE PAPER_INSUFFICIENT_CASH PAPER_POSITION_TOO_SMALL PAPER_MARKET_CLOSED PAPER_WORKING_ORDER_CAP PAPER_NO_LIVE_BOOK PAPER_ORDER_NOT_FOUND PAPER_ORDER_NOT_OPEN SQL_QUERY_FAILED SQL_TIMEOUT FEED_NOT_FOUND FEEDS_UNAVAILABLE FEED_UPSTREAM MATCHES_UNAVAILABLE ARBITRAGE_UNAVAILABLE
Always present on errors; quote this id when reporting a failed request.
string
exchange
Present only when a venue error is attributed to a specific exchange.
string
Example "code" : " VALIDATION_ERROR "
Unprocessable grant — Stripe retries
Media type application/json
object object string
Allowed values: VALIDATION_ERROR NOT_SUPPORTED ACCOUNTS_UNSUPPORTED VENUE_NOT_AVAILABLE EXCHANGE_NOT_AVAILABLE MARKET_NOT_FOUND EVENT_NOT_FOUND TRADERS_UNSUPPORTED TRADER_NOT_FOUND CLUSTER_NOT_FOUND OUTCOME_NOT_FOUND SNAPSHOT_NOT_FOUND CATALOG_UNAVAILABLE CATALOG_QUERY_TOO_BROAD HISTORY_UNAVAILABLE SPORTS_SCREEN_UNAVAILABLE SPORTS_FIXTURE_NOT_FOUND SPORTS_BLOCK_NOT_FOUND ROUTE_NOT_FOUND INTERNAL AUTHENTICATION_ERROR PERMISSION_DENIED RATE_LIMIT_EXCEEDED NETWORK_ERROR NOT_FOUND BAD_REQUEST BRIDGE_UNSUPPORTED BRIDGE_NO_ROUTE BRIDGE_UPSTREAM BRIDGE_PROVIDER_UNAVAILABLE BRIDGE_TRANSACTION_NOT_FOUND BRIDGE_SESSION_NOT_FOUND TRANSFER_PLAN_UNSUPPORTED UNAUTHORIZED SCOPE_MISSING PLAN_REQUIRED INSUFFICIENT_CREDITS RATE_LIMITED GEO_BLOCKED VENUE_REGION_BLOCKED IDEMPOTENCY_KEY_REQUIRED RESERVED_IDEMPOTENCY_KEY IDEMPOTENCY_CONFLICT ARTIFACT_VERSION_CONFLICT SPEND_CAP_EXCEEDED RESERVATION_REQUIRED RESERVATION_CONSUMED RESERVATION_MISMATCH RESERVATION_EXPIRED RESERVATION_RELEASED ARTIFACT_BOUNDS_VIOLATION ARTIFACT_INTEGRITY_MISMATCH CLAIM_GENERATION_UNDETERMINED VENUE_NOT_SUPPORTED EXECUTION_NOT_FOUND EXECUTION_TERMINAL CONDITIONAL_NOT_FOUND CONDITIONAL_NOT_ARMED CONDITIONAL_ATTEMPT_CONFLICT CONDITIONAL_ARMED CONDITIONAL_CLOSED_NOT_SUBMITTED OCO_GROUP_CLOSED HOSTED_FIRE_NOT_ELIGIBLE HOSTED_FIRE_UNAVAILABLE NOT_IMPLEMENTED VENUE_CREDENTIAL_REJECTED VENUE_CREDENTIAL_BREAKER_OPEN GEMINI_TIME_NONCE_REQUIRED GEMINI_HEARTBEAT_KEY_UNSUPPORTED VENUE_RELAY_FAILED EXEC_UNAVAILABLE RAIN_INVALID_OPTION RAIN_INVALID_SIDE RAIN_INVALID_PRICE RAIN_INVALID_AMOUNT RAIN_SLIPPAGE_REQUIRED RAIN_INVALID_DEADLINE RAIN_PHASE_NOT_OPEN RAIN_ORDER_LIMIT_REACHED RAIN_POOL_SAFETY_CHECK_FAILED PLATFORM_UNAVAILABLE PACK_NOT_FOUND BILLING_UNAVAILABLE BILLING_CUSTOMER_REQUIRED PLAN_NOT_FOUND SUBSCRIPTION_EXISTS WEBHOOK_NOT_FOUND INVALID_SIGNATURE PAPER_INSUFFICIENT_CASH PAPER_POSITION_TOO_SMALL PAPER_MARKET_CLOSED PAPER_WORKING_ORDER_CAP PAPER_NO_LIVE_BOOK PAPER_ORDER_NOT_FOUND PAPER_ORDER_NOT_OPEN SQL_QUERY_FAILED SQL_TIMEOUT FEED_NOT_FOUND FEEDS_UNAVAILABLE FEED_UPSTREAM MATCHES_UNAVAILABLE ARBITRAGE_UNAVAILABLE
Always present on errors; quote this id when reporting a failed request.
string
exchange
Present only when a venue error is attributed to a specific exchange.
string
Example "code" : " VALIDATION_ERROR "
BILLING_UNAVAILABLE — Stripe env absent
Media type application/json
object object string
Allowed values: VALIDATION_ERROR NOT_SUPPORTED ACCOUNTS_UNSUPPORTED VENUE_NOT_AVAILABLE EXCHANGE_NOT_AVAILABLE MARKET_NOT_FOUND EVENT_NOT_FOUND TRADERS_UNSUPPORTED TRADER_NOT_FOUND CLUSTER_NOT_FOUND OUTCOME_NOT_FOUND SNAPSHOT_NOT_FOUND CATALOG_UNAVAILABLE CATALOG_QUERY_TOO_BROAD HISTORY_UNAVAILABLE SPORTS_SCREEN_UNAVAILABLE SPORTS_FIXTURE_NOT_FOUND SPORTS_BLOCK_NOT_FOUND ROUTE_NOT_FOUND INTERNAL AUTHENTICATION_ERROR PERMISSION_DENIED RATE_LIMIT_EXCEEDED NETWORK_ERROR NOT_FOUND BAD_REQUEST BRIDGE_UNSUPPORTED BRIDGE_NO_ROUTE BRIDGE_UPSTREAM BRIDGE_PROVIDER_UNAVAILABLE BRIDGE_TRANSACTION_NOT_FOUND BRIDGE_SESSION_NOT_FOUND TRANSFER_PLAN_UNSUPPORTED UNAUTHORIZED SCOPE_MISSING PLAN_REQUIRED INSUFFICIENT_CREDITS RATE_LIMITED GEO_BLOCKED VENUE_REGION_BLOCKED IDEMPOTENCY_KEY_REQUIRED RESERVED_IDEMPOTENCY_KEY IDEMPOTENCY_CONFLICT ARTIFACT_VERSION_CONFLICT SPEND_CAP_EXCEEDED RESERVATION_REQUIRED RESERVATION_CONSUMED RESERVATION_MISMATCH RESERVATION_EXPIRED RESERVATION_RELEASED ARTIFACT_BOUNDS_VIOLATION ARTIFACT_INTEGRITY_MISMATCH CLAIM_GENERATION_UNDETERMINED VENUE_NOT_SUPPORTED EXECUTION_NOT_FOUND EXECUTION_TERMINAL CONDITIONAL_NOT_FOUND CONDITIONAL_NOT_ARMED CONDITIONAL_ATTEMPT_CONFLICT CONDITIONAL_ARMED CONDITIONAL_CLOSED_NOT_SUBMITTED OCO_GROUP_CLOSED HOSTED_FIRE_NOT_ELIGIBLE HOSTED_FIRE_UNAVAILABLE NOT_IMPLEMENTED VENUE_CREDENTIAL_REJECTED VENUE_CREDENTIAL_BREAKER_OPEN GEMINI_TIME_NONCE_REQUIRED GEMINI_HEARTBEAT_KEY_UNSUPPORTED VENUE_RELAY_FAILED EXEC_UNAVAILABLE RAIN_INVALID_OPTION RAIN_INVALID_SIDE RAIN_INVALID_PRICE RAIN_INVALID_AMOUNT RAIN_SLIPPAGE_REQUIRED RAIN_INVALID_DEADLINE RAIN_PHASE_NOT_OPEN RAIN_ORDER_LIMIT_REACHED RAIN_POOL_SAFETY_CHECK_FAILED PLATFORM_UNAVAILABLE PACK_NOT_FOUND BILLING_UNAVAILABLE BILLING_CUSTOMER_REQUIRED PLAN_NOT_FOUND SUBSCRIPTION_EXISTS WEBHOOK_NOT_FOUND INVALID_SIGNATURE PAPER_INSUFFICIENT_CASH PAPER_POSITION_TOO_SMALL PAPER_MARKET_CLOSED PAPER_WORKING_ORDER_CAP PAPER_NO_LIVE_BOOK PAPER_ORDER_NOT_FOUND PAPER_ORDER_NOT_OPEN SQL_QUERY_FAILED SQL_TIMEOUT FEED_NOT_FOUND FEEDS_UNAVAILABLE FEED_UPSTREAM MATCHES_UNAVAILABLE ARBITRAGE_UNAVAILABLE
Always present on errors; quote this id when reporting a failed request.
string
exchange
Present only when a venue error is attributed to a specific exchange.
string
Example "code" : " VALIDATION_ERROR "