Cushion Partner API

Embed instant accident relief coverage into your product.

The Cushion Partner API lets you offer supplemental auto insurance to your users. Create policies, file claims, and receive real-time webhooks when payouts are deposited — all through a simple REST API.

Base URL https://api.getcushion.com/v1

Quick Start

  1. Get your API key from your partner dashboard
  2. Create a policy for your user
  3. When an accident occurs, file a claim
  4. Cushion auto-approves and deposits $500 instantly
Quick example
# Create a policy for your user
curl https://api.getcushion.com/v1/policies \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "external_customer_id": "usr_123",
    "customer_email": "sarah@example.com",
    "customer_first_name": "Sarah",
    "customer_last_name": "Fischer",
    "customer_zip": "48201"
  }'
Response
{
  "id": "pol_a1b2c3d4e5f6g7h8",
  "object": "policy",
  "status": "active",
  "customer": {
    "email": "sarah@example.com",
    "first_name": "Sarah",
    "last_name": "Fischer",
    "zip": "48201"
  },
  "payout_amount": 500.00,
  "premium_cents": 900,
  "effective_date": "2026-03-17T...",
  "created_at": "2026-03-17T..."
}

Authentication

Authenticate requests by including your API key in the Authorization header as a Bearer token.

API keys come in two flavors:

sk_test_...Test environment — no real charges or payouts
sk_live_...Production environment — real policies and payouts
Keep your keys safe. Never expose API keys in client-side code, public repositories, or browser requests.
Authenticated request
curl https://api.getcushion.com/v1/ping \
  -H "Authorization: Bearer sk_test_abc123..."
Response
{
  "object": "ping",
  "partner": "Chime",
  "environment": "test",
  "message": "Authenticated successfully."
}

Errors

Cushion uses conventional HTTP status codes. All errors return a JSON body with an error object.

200Success
201Created
400Bad request — invalid parameters
401Unauthorized — missing or invalid API key
404Not found — resource doesn't exist
409Conflict — resource already exists
429Rate limited — too many requests
500Server error

Error types

authentication_errorInvalid or missing API key
invalid_request_errorMissing or invalid parameters
rate_limit_errorToo many requests
api_errorInternal server error
Error response
{
  "error": {
    "type": "invalid_request_error",
    "message": "external_customer_id and customer_zip are required.",
    "code": null
  }
}

Pagination

List endpoints return paginated results. Use limit and offset query parameters.

limitNumber of results (default 20, max 100)
offsetNumber of results to skip (default 0)

The response includes has_more (boolean) and total_count to help you paginate.

List response shape
{
  "object": "list",
  "data": [ ... ],
  "has_more": true,
  "total_count": 42
}

Webhooks

Cushion sends webhook events to notify your application when things happen — claims approved, payouts completed, etc.

Event types

policy.createdA new policy was created
policy.cancelledA policy was cancelled
claim.submittedA claim was filed
claim.approvedA claim was approved, payout processing
claim.paidPayout deposited to customer
claim.deniedClaim was denied

Verifying signatures

Each webhook includes a Cushion-Signature header. Verify it using your webhook secret to ensure authenticity.

The signature format is t=timestamp,v1=hmac_hex. Compute the HMAC-SHA256 of {timestamp}.{payload_json} with your webhook secret.

Webhook payload
{
  "id": "evt_a1b2c3...",
  "type": "claim.paid",
  "data": {
    "id": "clm_x1y2z3...",
    "object": "claim",
    "status": "paid",
    "payout": {
      "amount": 500.00,
      "status": "completed"
    }
  },
  "created_at": "2026-03-17T..."
}
Verify signature (Node.js)
const crypto = require('crypto');

function verifyWebhook(payload, header, secret) {
  const [tPart, vPart] = header.split(',');
  const timestamp = tPart.split('=')[1];
  const signature = vPart.split('=')[1];

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${JSON.stringify(payload)}`)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature), Buffer.from(expected)
  );
}

Policies

A Policy represents Cushion accident relief coverage for one of your users. Each policy entitles the holder to an instant cash payout if they're in a car accident.

The Policy object

idstring Unique identifier (pol_...)
external_customer_idstring Your user ID
customerobject Customer details (email, first_name, last_name, zip)
planstring Always "accident_relief"
payout_amountnumber Payout on claim ($200-$1000, default $500)
premium_centsinteger Monthly premium in cents (default 900)
statusstring active, cancelled, or expired
effective_datestring ISO 8601 date when coverage begins
metadataobject Arbitrary key-value data you can attach
The Policy object
{
  "id": "pol_a1b2c3d4e5f6g7h8",
  "object": "policy",
  "external_customer_id": "usr_123",
  "customer": {
    "email": "sarah@example.com",
    "first_name": "Sarah",
    "last_name": "Fischer",
    "zip": "48201"
  },
  "plan": "accident_relief",
  "payout_amount": 500.00,
  "premium_cents": 900,
  "status": "active",
  "effective_date": "2026-03-17T02:30:00.000Z",
  "metadata": {},
  "created_at": "2026-03-17T02:30:00.000Z"
}

POST /v1/policies

Creates a new Cushion policy for your user.

Parameters

external_customer_idrequired Your unique user identifier
customer_ziprequired Customer's ZIP code
customer_emailstring Customer email
customer_first_namestring First name
customer_last_namestring Last name
payout_amountnumber $200-$1000 (default $500)
premium_centsinteger 500-2000 (default 900)
metadataobject Arbitrary key-value pairs
Create a policy
curl https://api.getcushion.com/v1/policies \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "external_customer_id": "usr_123",
    "customer_email": "sarah@example.com",
    "customer_first_name": "Sarah",
    "customer_last_name": "Fischer",
    "customer_zip": "48201",
    "payout_amount": 500,
    "metadata": {
      "plan_tier": "premium"
    }
  }'

GET /v1/policies

Returns a paginated list of policies.

Query parameters

statusFilter by status (active, cancelled, expired)
limitResults per page (default 20, max 100)
offsetNumber of results to skip
List policies
curl https://api.getcushion.com/v1/policies?status=active&limit=10 \
  -H "Authorization: Bearer sk_test_..."

GET /v1/policies/:id

Retrieves a single policy by ID.

Retrieve a policy
curl https://api.getcushion.com/v1/policies/pol_a1b2c3d4e5f6g7h8 \
  -H "Authorization: Bearer sk_test_..."

PATCH /v1/policies/:id

Updates a policy's metadata or customer email.

Parameters

metadataobject Replace metadata
customer_emailstring Update email
Update a policy
curl -X PATCH https://api.getcushion.com/v1/policies/pol_a1b2c3... \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "metadata": { "plan_tier": "basic" } }'

DELETE /v1/policies/:id

Cancels a policy. Sets status to cancelled. This cannot be undone.

Cancel a policy
curl -X DELETE https://api.getcushion.com/v1/policies/pol_a1b2c3... \
  -H "Authorization: Bearer sk_test_..."

Claims

A Claim represents an accident report filed against a policy. When a claim is created, Cushion automatically reviews, approves, and deposits the payout.

Claim lifecycle

reviewing approved

The Claim object

idstring Unique identifier (clm_...)
policy_idstring Associated policy
statusstring submitted, reviewing, approved, paid, denied
incidentobject Accident details (date, description, location, etc.)
payoutobject Payout info (amount, status, completed_at)
metadataobject Arbitrary key-value data
The Claim object
{
  "id": "clm_x1y2z3a4b5c6d7e8",
  "object": "claim",
  "policy_id": "pol_a1b2c3d4e5f6g7h8",
  "status": "paid",
  "incident": {
    "date": "2026-03-17T14:30:00Z",
    "description": "Rear-ended at intersection",
    "location": "Michigan Ave & State St",
    "others_involved": "yes",
    "injuries": "none",
    "car_drivable": true
  },
  "payout": {
    "amount": 500.00,
    "status": "completed",
    "completed_at": "2026-03-17T14:30:12Z"
  },
  "metadata": {}
}

POST /v1/policies/:policy_id/claims

Files a new claim against a policy. The policy must be active. Cushion will automatically process the claim and deposit the payout.

Parameters

incident_daterequired ISO 8601 date of the accident
incident_descriptionstring What happened
incident_locationstring Where it happened
incident_latitudenumber GPS latitude
incident_longitudenumber GPS longitude
others_involvedstring yes, no, unknown
injuriesstring none, minor, hospital
car_drivableboolean Is the car drivable?
metadataobject Arbitrary key-value pairs
File a claim
curl https://api.getcushion.com/v1/policies/pol_a1b2c3.../claims \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "incident_date": "2026-03-17T14:30:00Z",
    "incident_description": "Rear-ended at intersection",
    "incident_location": "Michigan Ave & State St",
    "others_involved": "yes",
    "injuries": "none",
    "car_drivable": true
  }'

GET /v1/claims

Returns a paginated list of claims across all policies.

Query parameters

statusFilter by status
policy_idFilter by policy
limitResults per page (default 20, max 100)
offsetNumber of results to skip
List claims
curl https://api.getcushion.com/v1/claims?status=paid \
  -H "Authorization: Bearer sk_test_..."

GET /v1/claims/:id

Retrieves a single claim by ID.

Retrieve a claim
curl https://api.getcushion.com/v1/claims/clm_x1y2z3a4b5c6d7e8 \
  -H "Authorization: Bearer sk_test_..."

Webhook Endpoints

Configure where Cushion sends webhook events.

PUT /v1/webhooks

Set or update your webhook URL. Returns the webhook secret for signature verification.

GET /v1/webhooks

Retrieve your current webhook configuration.

GET /v1/webhook-events

List recent webhook delivery attempts. Filter by status (pending, delivered, failed).

POST /v1/webhook-events/:id/retry

Retry delivery of a failed webhook event.

Configure webhook
curl -X PUT https://api.getcushion.com/v1/webhooks \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://your-app.com/webhooks/cushion" }'
Response
{
  "object": "webhook_config",
  "url": "https://your-app.com/webhooks/cushion",
  "secret": "whsec_abc123...",
  "status": "active"
}

Testing

Use your sk_test_ API key to create test policies and claims. Test mode behaves identically to live mode but doesn't create real charges or payouts.

Test scenario: Full claim lifecycle

  1. Create a policy with POST /v1/policies
  2. File a claim with POST /v1/policies/:id/claims
  3. Poll GET /v1/claims/:id to watch the status progress: submitted → reviewing → approved → paid
  4. Or configure a webhook to receive events at each transition

Claims are auto-approved in test mode. The full lifecycle (submitted → paid) completes in about 5-10 seconds.

Create a test partner

Run the seed script to generate a test API key:

Generate test API key
cd server
node scripts/create-partner.js "My App" "dev@myapp.com" test
Full test flow
# 1. Create a policy
curl -s localhost:3000/api/v1/policies \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"external_customer_id":"test_1","customer_zip":"48201"}' \
  | jq .

# 2. File a claim (use the policy ID from step 1)
curl -s localhost:3000/api/v1/policies/pol_.../claims \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"incident_date":"2026-03-17T14:30:00Z"}' \
  | jq .

# 3. Check claim status (wait a few seconds)
curl -s localhost:3000/api/v1/claims/clm_... \
  -H "Authorization: Bearer $API_KEY" \
  | jq .status