Skip to content

Webhooks

OpenScouter receives webhooks from Stripe for payment and payout events, and provides an OAuth callback endpoint for authentication flows.

Stripe Webhook Security

All incoming Stripe payloads are verified using the Stripe signature header before processing. Requests without a valid Stripe-Signature header return 401. Configure your Stripe webhook endpoint in the Stripe Dashboard with the webhook secret stored in STRIPE_WEBHOOK_SECRET.

Endpoints

POST /api/webhooks/stripe Webhook

Receive and process Stripe payment events

Stripe calls this endpoint for account updates and payout outcomes. You do not call this endpoint directly.

Headers required by Stripe

Stripe-Signature: t=1678901234,v1=abc123...
Content-Type: application/json

Supported event types

EventTrigger
account.updatedA connected account’s details changed (e.g., verification status)
payout.paidA payout was successfully delivered to a tester’s bank account
payout.failedA payout failed and was not delivered

Example payload: payout.paid

{
"id": "evt_001",
"type": "payout.paid",
"created": 1710590400,
"data": {
"object": {
"id": "po_001",
"amount": 1500,
"currency": "usd",
"arrival_date": 1710676800,
"status": "paid",
"destination": "ba_001"
}
}
}

Example payload: payout.failed

{
"id": "evt_002",
"type": "payout.failed",
"created": 1710590500,
"data": {
"object": {
"id": "po_002",
"amount": 1500,
"currency": "usd",
"status": "failed",
"failure_code": "insufficient_funds",
"failure_message": "The bank account has insufficient funds to complete the payout."
}
}
}

Example payload: account.updated

{
"id": "evt_003",
"type": "account.updated",
"created": 1710590600,
"data": {
"object": {
"id": "acct_001",
"charges_enabled": true,
"payouts_enabled": true,
"details_submitted": true,
"requirements": {
"currently_due": [],
"eventually_due": []
}
}
}
}

Response

Return 200 OK to acknowledge receipt. Any other status triggers Stripe retry logic with exponential backoff.

{ "received": true }

Internal processing

EventAction taken
account.updatedUpdates the tester’s Stripe account status in the database
payout.paidMarks the associated session payment as paid, notifies the tester
payout.failedMarks the payment as failed, triggers admin alert, queues retry
GET /api/auth/callback

Handle the OAuth authorization code callback

This endpoint completes the OAuth flow after a user approves the authorization request on an external provider (Google, GitHub, etc.). The provider redirects here with a short-lived authorization code.

Query parameters

ParameterDescription
codeAuthorization code from the OAuth provider
stateCSRF state token generated at the start of the OAuth flow
errorError code if the user denied access (e.g., access_denied)

Successful flow

  1. OpenScouter exchanges code for access and refresh tokens.
  2. The user record is created or updated.
  3. A session JWT is issued.
  4. The user is redirected to the post-login destination.

Example success redirect

GET /api/auth/callback?code=4/abc123&state=xyz789

Redirects to https://openscouter.com/dashboard with a Set-Cookie header containing the session JWT.

Example error redirect

GET /api/auth/callback?error=access_denied&state=xyz789

Redirects to https://openscouter.com/login?error=access_denied.

Error responses

ScenarioResponse
Missing or invalid state400 Bad Request — CSRF check failed
Code exchange fails401 Unauthorized — provider rejected the code
Provider account banned403 Forbidden — account is suspended