MENU navbar-image

Introduction

Severe weather alert API — CAP-based alerts, geo queries, signed webhooks, and usage metering.

Severe Alerts normalizes severe weather alerts from multiple national sources into a single JSON shape. Integrate by:

  1. Creating an account and API key (control plane)
  2. Pulling alerts over HTTPS (data plane)
  3. Optionally receiving signed webhook POSTs when alerts change

Quick start

# 1. Register (returns a Sanctum control-plane token)
curl -s -X POST "$BASE_URL/api/v1/auth/register" \
  -H "Content-Type: application/json" -H "Accept: application/json" \
  -d '{"name":"Acme","email":"[email protected]","password":"your-password"}'

# 2. Create an API key (requires Sanctum token + active subscription)
curl -s -X POST "$BASE_URL/api/v1/keys" \
  -H "Authorization: Bearer $SANCTUM_TOKEN" \
  -H "Content-Type: application/json" -H "Accept: application/json" \
  -d '{"label":"production"}'

# 3. Fetch active alerts
curl -s "$BASE_URL/api/v1/alerts/active?country=US&per_page=25" \
  -H "Authorization: Bearer $API_KEY" -H "Accept: application/json"

Save the API key from step 2 immediately — it is shown once.

Auth model

Token Header Used for
Sanctum (register/login) Authorization: Bearer <sanctum> API keys, billing, logout
API key Authorization: Bearer <API_KEY> Alerts, usage, webhooks

Default key scopes: alerts:read, webhooks:write, usage:read.

HTTP Meaning
401 Missing or invalid credentials
402 No active subscription
403 Missing API key scope (error.details.required)
429 Rate or monthly quota — honor Retry-After

Successful data-plane responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (unix seconds). Defaults: 60 req/min and 100,000 req/month (per account; overridable).

Response conventions

Success

{
  "data": { },
  "meta": { }
}

Errors

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded",
    "details": { "retry_after": 12 }
  }
}
error.code HTTP Notes
missing_api_key / invalid_api_key 401
unauthenticated 401 Control plane
invalid_credentials 401 Login
subscription_required 402
insufficient_scope 403 details.required
not_found 404
validation_failed 422 Field → messages in details
invalid_bbox / invalid_points / invalid_webhook_url 422
webhook_limit_exceeded 422 Max webhooks per account
rate_limit_exceeded 429 details.retry_after
monthly_quota_exceeded 429 details.used, quota, retry_after
too_many_requests 429 Auth throttle

Alert shapes

Webhook bodies, show, geo endpoints, and ?include=full share the same full document.

Full resource includes geometry, bbox, and infos. Summary (default list/active/history) omits those and includes headline instead. Always present: id, cap_id, cancelled.

Timestamps are unix seconds (or null). When an alert is cancelled: message_type is "Cancel" and cancelled is true — upsert on cap_id and treat as inactive.

Field Values
severity Extreme, Severe, Moderate, Minor, Unknown
message_type Alert, Update, Cancel, Ack, Error, Unknown
urgency Immediate, Expected, Future, Past, Unknown
certainty Observed, Likely, Possible, Unlikely, Unknown
geo_type polygon, PUB, FIRE, MARINE, OFFSHORE, FIPS, NUTS2, NUTS3, EMMA, CITY, iso, unknown

Pagination & caching

List / active / history support:

Param Notes
country ISO country code, e.g. US
severity Exact match
event_type Exact match
updated_since Unix int — rows updated at/after this time
include full for full resource rows
per_page Max 100, default 25
cursor Cursor pagination

Pass If-None-Match with a previous ETag to receive 304 when unchanged.

After an initial bootstrap, prefer deltas:

curl -s "$BASE_URL/api/v1/alerts/active?country=US&updated_since=$LAST_SYNC_UNIX&per_page=100" \
  -H "Authorization: Bearer $API_KEY" -H "Accept: application/json"

History window is approximately 30 days.

Webhooks (overview)

Register an HTTPS URL with optional filters (country, severity, event_type). On create you receive a one-time secret under data.secret — store it; list endpoints never return it.

Deliveries are POST with header X-Alert-Signature: t=<unix>,v1=<hex_hmac>:

signed_payload = "{t}." + raw_request_body
expected_v1    = HMAC_SHA256(secret, signed_payload)  // hex

Reject if clock skew exceeds ~300 seconds; compare with constant-time equality using the raw body. Non-2xx responses are retried with backoff; after 20 consecutive failures the webhook is disabled. See the Webhooks group for payload fields and delivery history.

Downloads

Authenticating requests

This API uses Bearer tokens in the Authorization header.

Authorization: Bearer {YOUR_API_KEY}
Accept: application/json

Data plane (API key)

Use an API key for alerts, usage, and webhooks.

  1. Register or log in to receive a Sanctum control-plane token
  2. POST /api/v1/keys with that token to issue an API key (requires an active subscription)
  3. Call data-plane endpoints with Authorization: Bearer <API_KEY>

Scopes on newly issued keys default to alerts:read, webhooks:write, and usage:read. Pass a subset via scopes when creating a key.

HTTP Meaning
401 Missing/invalid API key
402 No active subscription
403 Missing required scope (error.details.required)
429 Per-minute rate limit or monthly quota — honor Retry-After

Control plane (Sanctum)

Use the token from POST /api/v1/auth/register or POST /api/v1/auth/login for:

Login revokes prior control-plane tokens for that user. Logout deletes the current Sanctum token.

Public metadata routes (/regions, /event-types, /severity-levels, /status) require no authentication.

Metadata

Public catalog and health endpoints. No authentication required.

List regions

Distinct ISO country codes present in the alert read model.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/regions" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/regions"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/regions'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        "CA",
        "CN",
        "IR",
        "US"
    ]
}
 

Request      

GET api/v1/regions

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

List event types

Distinct event types present in the alert read model.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/event-types" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/event-types"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/event-types'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        "Flood",
        "Thunderstorm",
        "Wind"
    ]
}
 

Request      

GET api/v1/event-types

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

List severity levels

Distinct severity values present in the alert read model.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/severity-levels" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/severity-levels"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/severity-levels'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        "Extreme",
        "Minor",
        "Moderate",
        "Severe",
        "Unknown"
    ]
}
 

Request      

GET api/v1/severity-levels

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Service status

Lightweight health check with the latest alert update timestamp.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/status" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/status"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/status'
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": {
        "status": "ok",
        "latest_alert_updated_at": 1724592000
    }
}
 

Request      

GET api/v1/status

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Alerts

Query active and historical severe weather alerts. Requires scope alerts:read.

List / active / history default to summary rows; pass include=full for the full document (geometry, bbox, infos). Supports cursor pagination and If-None-Match / ETag → 304.

Alerts by location

requires authentication

Point query returning full alert documents. Optional bbox CSV (min_lat,min_lng,max_lat,max_lng) switches to a bounding-box search. Response meta may include degraded / degraded_reasons (e.g. geocoder issues).

Example request:
curl --request GET \
    --get "http://localhost/api/v1/alerts/by-location?lat=39.0&lng=-76.6&iso=US&bbox=architecto" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"lat\": -89,
    \"lng\": -179,
    \"iso\": \"gz\",
    \"bbox\": \"architecto\"
}"
const url = new URL(
    "http://localhost/api/v1/alerts/by-location"
);

const params = {
    "lat": "39.0",
    "lng": "-76.6",
    "iso": "US",
    "bbox": "architecto",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "lat": -89,
    "lng": -179,
    "iso": "gz",
    "bbox": "architecto"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/alerts/by-location'
payload = {
    "lat": -89,
    "lng": -179,
    "iso": "gz",
    "bbox": "architecto"
}
params = {
  'lat': '39.0',
  'lng': '-76.6',
  'iso': 'US',
  'bbox': 'architecto',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200, Success):


{
    "data": [],
    "meta": {
        "degraded": false,
        "degraded_reasons": []
    }
}
 

Request      

GET api/v1/alerts/by-location

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

lat   string     

numeric Latitude. Example: 39.0

lng   string     

numeric Longitude. Example: -76.6

iso   string  optional    

Optional ISO country override. Example: US

bbox   string  optional    

Optional bbox CSV: min_lat,min_lng,max_lat,max_lng. Example: architecto

Body Parameters

lat   number     

Must be between -90 and 90. Example: -89

lng   number     

Must be between -180 and 180. Example: -179

iso   string  optional    

Must be 2 characters. Example: gz

bbox   string  optional    

Example: architecto

Batch alerts by locations

requires authentication

Up to 50 points per request (counts as one usage hit). Returns matching alert ids per point (not full documents). No single ETag / 304 on this endpoint.

Example request:
curl --request POST \
    "http://localhost/api/v1/alerts/by-locations" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"points\": [
        {
            \"lat\": \"39.0\",
            \"lng\": \"-76.6\",
            \"ref\": \"device-1\"
        }
    ]
}"
const url = new URL(
    "http://localhost/api/v1/alerts/by-locations"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "points": [
        {
            "lat": "39.0",
            "lng": "-76.6",
            "ref": "device-1"
        }
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/alerts/by-locations'
payload = {
    "points": [
        {
            "lat": "39.0",
            "lng": "-76.6",
            "ref": "device-1"
        }
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200, Success):


{
    "data": [
        {
            "ref": "device-1",
            "alert_ids": [
                7,
                12
            ]
        }
    ],
    "meta": {
        "degraded": false,
        "degraded_reasons": []
    }
}
 

Request      

POST api/v1/alerts/by-locations

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

points   object[]     

Array of points (max 50).

lat   numeric     

Latitude. Example: 39.0

lng   numeric     

Longitude. Example: -76.6

ref   string  optional    

optional Client reference id. Example: device-1

Alerts by bounding box

requires authentication

Returns full alert documents whose area intersects the bounding box.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/alerts/by-bbox?min_lat=38.7&max_lat=39.2&min_lng=-76.8&max_lng=-76.4" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"min_lat\": -89,
    \"max_lat\": -89,
    \"min_lng\": -180,
    \"max_lng\": -179
}"
const url = new URL(
    "http://localhost/api/v1/alerts/by-bbox"
);

const params = {
    "min_lat": "38.7",
    "max_lat": "39.2",
    "min_lng": "-76.8",
    "max_lng": "-76.4",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "min_lat": -89,
    "max_lat": -89,
    "min_lng": -180,
    "max_lng": -179
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/alerts/by-bbox'
payload = {
    "min_lat": -89,
    "max_lat": -89,
    "min_lng": -180,
    "max_lng": -179
}
params = {
  'min_lat': '38.7',
  'max_lat': '39.2',
  'min_lng': '-76.8',
  'max_lng': '-76.4',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200, Success):


{
    "data": [],
    "meta": {
        "degraded": false,
        "degraded_reasons": []
    }
}
 

Example response (422, Invalid bbox):


{
    "error": {
        "code": "invalid_bbox",
        "message": "min_* must be less than or equal to max_*",
        "details": {}
    }
}
 

Request      

GET api/v1/alerts/by-bbox

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

min_lat   string     

numeric Example: 38.7

max_lat   string     

numeric Example: 39.2

min_lng   string     

numeric Example: -76.8

max_lng   string     

numeric Example: -76.4

Body Parameters

min_lat   number     

Must be between -90 and 90. Example: -89

max_lat   number     

Must be between -90 and 90. Example: -89

min_lng   number     

Must be between -180 and 180. Example: -180

max_lng   number     

Must be between -180 and 180. Example: -179

Whether an alert covers given points

requires authentication

Useful after a webhook: check which devices fall inside an alert. Max 100 points. Prefer POST with a JSON body for large batches (avoids URL length limits). GET still accepts a pipe-separated points query string for small requests.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/alerts/12345/covers?points=39.0%2C-76.6%2Cdev1%7C38.9%2C-77.0" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"points\": [
        {
            \"lat\": \"39.0\",
            \"lng\": \"-76.6\",
            \"ref\": \"dev1\"
        }
    ]
}"
const url = new URL(
    "http://localhost/api/v1/alerts/12345/covers"
);

const params = {
    "points": "39.0,-76.6,dev1|38.9,-77.0",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "points": [
        {
            "lat": "39.0",
            "lng": "-76.6",
            "ref": "dev1"
        }
    ]
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/alerts/12345/covers'
payload = {
    "points": [
        {
            "lat": "39.0",
            "lng": "-76.6",
            "ref": "dev1"
        }
    ]
}
params = {
  'points': '39.0,-76.6,dev1|38.9,-77.0',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200, Success):


{
    "data": [
        {
            "lat": 39,
            "lng": -76.6,
            "ref": "dev1",
            "covered": true
        }
    ],
    "meta": {
        "degraded": false,
        "degraded_reasons": []
    }
}
 

Request      

GET api/v1/alerts/{id}/covers

POST api/v1/alerts/{id}/covers

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

Alert id. Example: 12345

Query Parameters

points   string  optional    

optional Pipe-separated lat,lng or lat,lng,ref (GET). Example: 39.0,-76.6,dev1|38.9,-77.0

Body Parameters

points   object[]  optional    

optional Array of points (POST, max 100).

lat   numeric     

Latitude. Example: 39.0

lng   numeric     

Longitude. Example: -76.6

ref   string  optional    

optional Client reference id. Example: dev1

Webhooks

Register HTTPS endpoints to receive signed POSTs when alerts change.

List webhooks

requires authentication

Secrets are never included in list responses.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/account/webhooks" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/account/webhooks"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/account/webhooks'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "url": "https://example.com/hooks/alerts",
            "filters": {
                "country": "US"
            },
            "active": true,
            "created_at": 1724586400
        }
    ]
}
 

Request      

GET api/v1/account/webhooks

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Register webhook

requires authentication

URL must be public HTTPS (SSRF guard blocks private/loopback). Filters are applied at dispatch (country → snapshot ISO, severity exact include, exclude_severity exact skip, event_type exact). Empty filters = all alerts. The secret is returned once in this response.

Example request:
curl --request POST \
    "http://localhost/api/v1/account/webhooks" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"url\": \"https:\\/\\/example.com\\/hooks\\/alerts\",
    \"filters\": {
        \"country\": \"US\",
        \"exclude_severity\": \"Minor\",
        \"severity\": \"Severe\",
        \"event_type\": \"Wind\"
    }
}"
const url = new URL(
    "http://localhost/api/v1/account/webhooks"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "url": "https:\/\/example.com\/hooks\/alerts",
    "filters": {
        "country": "US",
        "exclude_severity": "Minor",
        "severity": "Severe",
        "event_type": "Wind"
    }
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/account/webhooks'
payload = {
    "url": "https:\/\/example.com\/hooks\/alerts",
    "filters": {
        "country": "US",
        "exclude_severity": "Minor",
        "severity": "Severe",
        "event_type": "Wind"
    }
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (201, Created):


{
    "data": {
        "id": 1,
        "url": "https://example.com/hooks/alerts",
        "filters": {
            "country": "US",
            "severity": "Severe"
        },
        "active": true,
        "secret": "a1b2c3d4e5f6…",
        "created_at": 1724586400
    }
}
 

Example response (422, Invalid URL):


{
    "error": {
        "code": "invalid_webhook_url",
        "message": "URL host is not allowed",
        "details": {}
    }
}
 

Request      

POST api/v1/account/webhooks

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

url   string     

Public HTTPS callback URL. Example: https://example.com/hooks/alerts

filters   object  optional    

optional Delivery filters.

country   string  optional    

optional ISO country code (2 letters). Example: US

severity   string  optional    

optional Exact severity include (string or array). Example: Severe

exclude_severity   string  optional    

optional Exact severity to skip (string or array). Example: Minor

event_type   string  optional    

optional Exact event type. Example: Wind

List deliveries

requires authentication

Recent delivery attempts for a webhook (newest first, max 100).

Example request:
curl --request GET \
    --get "http://localhost/api/v1/account/webhooks/16/deliveries" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/account/webhooks/16/deliveries"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/account/webhooks/16/deliveries'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        {
            "id": 891234,
            "status": "delivered",
            "http_status": 200,
            "attempt": 1,
            "created_at": 1724592000
        }
    ]
}
 

Request      

GET api/v1/account/webhooks/{webhook_id}/deliveries

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

webhook_id   integer     

The ID of the webhook. Example: 16

webhook   integer     

Webhook id. Example: 1

Delete webhook

requires authentication

Example request:
curl --request DELETE \
    "http://localhost/api/v1/account/webhooks/16" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/account/webhooks/16"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/account/webhooks/16'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()

Example response (200, Deleted):


{
    "data": {
        "status": "deleted"
    }
}
 

Request      

DELETE api/v1/account/webhooks/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The ID of the webhook. Example: 16

webhook   integer     

Webhook id. Example: 1

List webhooks

requires authentication

Secrets are never included in list responses.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/webhooks" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/webhooks"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/webhooks'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "url": "https://example.com/hooks/alerts",
            "filters": {
                "country": "US"
            },
            "active": true,
            "created_at": 1724586400
        }
    ]
}
 

Request      

GET api/v1/webhooks

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Register webhook

requires authentication

URL must be public HTTPS (SSRF guard blocks private/loopback). Filters are applied at dispatch (country → snapshot ISO, severity exact include, exclude_severity exact skip, event_type exact). Empty filters = all alerts. The secret is returned once in this response.

Example request:
curl --request POST \
    "http://localhost/api/v1/webhooks" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"url\": \"https:\\/\\/example.com\\/hooks\\/alerts\",
    \"filters\": {
        \"country\": \"US\",
        \"exclude_severity\": \"Minor\",
        \"severity\": \"Severe\",
        \"event_type\": \"Wind\"
    }
}"
const url = new URL(
    "http://localhost/api/v1/webhooks"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "url": "https:\/\/example.com\/hooks\/alerts",
    "filters": {
        "country": "US",
        "exclude_severity": "Minor",
        "severity": "Severe",
        "event_type": "Wind"
    }
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/webhooks'
payload = {
    "url": "https:\/\/example.com\/hooks\/alerts",
    "filters": {
        "country": "US",
        "exclude_severity": "Minor",
        "severity": "Severe",
        "event_type": "Wind"
    }
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (201, Created):


{
    "data": {
        "id": 1,
        "url": "https://example.com/hooks/alerts",
        "filters": {
            "country": "US",
            "severity": "Severe"
        },
        "active": true,
        "secret": "a1b2c3d4e5f6…",
        "created_at": 1724586400
    }
}
 

Example response (422, Invalid URL):


{
    "error": {
        "code": "invalid_webhook_url",
        "message": "URL host is not allowed",
        "details": {}
    }
}
 

Request      

POST api/v1/webhooks

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

url   string     

Public HTTPS callback URL. Example: https://example.com/hooks/alerts

filters   object  optional    

optional Delivery filters.

country   string  optional    

optional ISO country code (2 letters). Example: US

severity   string  optional    

optional Exact severity include (string or array). Example: Severe

exclude_severity   string  optional    

optional Exact severity to skip (string or array). Example: Minor

event_type   string  optional    

optional Exact event type. Example: Wind

List deliveries

requires authentication

Recent delivery attempts for a webhook (newest first, max 100).

Example request:
curl --request GET \
    --get "http://localhost/api/v1/webhooks/16/deliveries" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/webhooks/16/deliveries"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/webhooks/16/deliveries'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        {
            "id": 891234,
            "status": "delivered",
            "http_status": 200,
            "attempt": 1,
            "created_at": 1724592000
        }
    ]
}
 

Request      

GET api/v1/webhooks/{webhook_id}/deliveries

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

webhook_id   integer     

The ID of the webhook. Example: 16

webhook   integer     

Webhook id. Example: 1

Delete webhook

requires authentication

Example request:
curl --request DELETE \
    "http://localhost/api/v1/webhooks/16" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/webhooks/16"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/webhooks/16'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()

Example response (200, Deleted):


{
    "data": {
        "status": "deleted"
    }
}
 

Request      

DELETE api/v1/webhooks/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The ID of the webhook. Example: 16

webhook   integer     

Webhook id. Example: 1

Usage

Monthly request usage against your account quota.

Get usage

requires authentication

Returns the current calendar month usage and quota.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/account/usage" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/account/usage"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/account/usage'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": {
        "period": "2026-09",
        "used": 12840,
        "persisted": 12000,
        "quota": 100000
    }
}
 

Request      

GET api/v1/account/usage

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Get usage

requires authentication

Returns the current calendar month usage and quota.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/usage" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/usage"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/usage'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": {
        "period": "2026-09",
        "used": 12840,
        "persisted": 12000,
        "quota": 100000
    }
}
 

Request      

GET api/v1/usage

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Account

Control-plane auth. Register/login return a Sanctum token used to manage API keys and billing. Data-plane calls (alerts, webhooks, usage) use an API key — not this token.

Register

Creates an account and returns a Sanctum control-plane token.

Example request:
curl --request POST \
    "http://localhost/api/v1/auth/register" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Acme Weather\",
    \"email\": \"[email protected]\",
    \"password\": \"|]|{+-\"
}"
const url = new URL(
    "http://localhost/api/v1/auth/register"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Acme Weather",
    "email": "[email protected]",
    "password": "|]|{+-"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/auth/register'
payload = {
    "name": "Acme Weather",
    "email": "[email protected]",
    "password": "|]|{+-"
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (201, Created):


{
    "data": {
        "user": {
            "id": 1,
            "name": "Acme Weather",
            "email": "[email protected]"
        },
        "token": "1|plainTextSanctumToken…"
    }
}
 

Request      

POST api/v1/auth/register

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

name   string     

Display name. Example: Acme Weather

email   string     

Unique email. Example: [email protected]

password   string     

Account password. Example: |]|{+-

Login

Returns a Sanctum control-plane token. Revokes prior control-plane tokens for the user.

Example request:
curl --request POST \
    "http://localhost/api/v1/auth/login" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"[email protected]\",
    \"password\": \"|]|{+-\"
}"
const url = new URL(
    "http://localhost/api/v1/auth/login"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "[email protected]",
    "password": "|]|{+-"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/auth/login'
payload = {
    "email": "[email protected]",
    "password": "|]|{+-"
}
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200, Success):


{
    "data": {
        "user": {
            "id": 1,
            "name": "Acme Weather",
            "email": "[email protected]"
        },
        "token": "2|plainTextSanctumToken…"
    }
}
 

Example response (401, Invalid credentials):


{
    "error": {
        "code": "invalid_credentials",
        "message": "Invalid credentials",
        "details": {}
    }
}
 

Request      

POST api/v1/auth/login

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string     

Example: [email protected]

password   string     

Example: |]|{+-

Current account

requires authentication

Returns the authenticated user plus subscription, limits, and resource counts. Use this to bootstrap the customer dashboard after login.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/auth/me" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/auth/me"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/auth/me'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": {
        "user": {
            "id": 1,
            "name": "Acme Weather",
            "email": "[email protected]",
            "created_at": "2026-10-01T12:00:00+00:00"
        },
        "subscription": {
            "status": "active",
            "interval": "monthly",
            "on_trial": false,
            "ends_at": null,
            "trial_ends_at": null,
            "stripe_price": "price_…"
        },
        "limits": {
            "rate_limit_per_minute": 60,
            "monthly_quota": 100000
        },
        "counts": {
            "api_keys": 2,
            "webhooks": 1
        }
    }
}
 

Request      

GET api/v1/auth/me

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Logout

requires authentication

Deletes the current Sanctum token.

Example request:
curl --request POST \
    "http://localhost/api/v1/auth/logout" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/auth/logout"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/auth/logout'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers)
response.json()

Example response (200, Logged out):


{
    "data": {
        "status": "logged_out"
    }
}
 

Request      

POST api/v1/auth/logout

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

List API keys

requires authentication

Secrets/tokens are never included in list responses — only metadata and prefix.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/keys" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/keys"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/keys'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Success):


{
    "data": [
        {
            "id": 1,
            "name": "production",
            "prefix": "sa_live_",
            "scopes": [
                "alerts:read",
                "webhooks:write",
                "usage:read"
            ],
            "last_used_at": null,
            "revoked_at": null,
            "created_at": 1724586400
        }
    ]
}
 

Request      

GET api/v1/keys

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Create API key

requires authentication

The plaintext token is returned once. Store it securely.

Example request:
curl --request POST \
    "http://localhost/api/v1/keys" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"label\": \"production\",
    \"scopes\": [
        \"alerts:read\",
        \"usage:read\"
    ]
}"
const url = new URL(
    "http://localhost/api/v1/keys"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "label": "production",
    "scopes": [
        "alerts:read",
        "usage:read"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/keys'
payload = {
    "label": "production",
    "scopes": [
        "alerts:read",
        "usage:read"
    ]
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (201, Created):


{
    "data": {
        "id": 1,
        "name": "production",
        "prefix": "sa_live_",
        "scopes": [
            "alerts:read",
            "webhooks:write",
            "usage:read"
        ],
        "token": "sa_live_…"
    }
}
 

Request      

POST api/v1/keys

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

label   string  optional    

optional Human-readable label. Example: production

scopes   string[]  optional    

optional Subset of known scopes. Defaults to all.

Revoke API key

requires authentication

Soft-revokes the key. It can no longer authenticate data-plane requests.

Example request:
curl --request DELETE \
    "http://localhost/api/v1/keys/16" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/keys/16"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/keys/16'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('DELETE', url, headers=headers)
response.json()

Example response (200, Revoked):


{
    "data": {
        "status": "revoked"
    }
}
 

Request      

DELETE api/v1/keys/{id}

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   integer     

The ID of the key. Example: 16

key   integer     

API key id. Example: 1

Billing

Stripe checkout and customer portal. Requires a Sanctum control-plane token. An active subscription is required before API keys can call the data plane.

Create checkout session

requires authentication

Returns a Stripe Checkout URL. success_url and cancel_url hosts must be allow-listed.

Example request:
curl --request POST \
    "http://localhost/api/v1/billing/checkout" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"interval\": \"monthly\",
    \"success_url\": \"https:\\/\\/app.example.com\\/billing\\/success\",
    \"cancel_url\": \"https:\\/\\/app.example.com\\/billing\\/cancel\"
}"
const url = new URL(
    "http://localhost/api/v1/billing/checkout"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "interval": "monthly",
    "success_url": "https:\/\/app.example.com\/billing\/success",
    "cancel_url": "https:\/\/app.example.com\/billing\/cancel"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/billing/checkout'
payload = {
    "interval": "monthly",
    "success_url": "https:\/\/app.example.com\/billing\/success",
    "cancel_url": "https:\/\/app.example.com\/billing\/cancel"
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('POST', url, headers=headers, json=payload)
response.json()

Example response (200, Success):


{
    "data": {
        "url": "https://checkout.stripe.com/c/pay/cs_test_…"
    }
}
 

Example response (422, Invalid return URL):


{
    "error": {
        "code": "invalid_return_url",
        "message": "success_url host is not allowed",
        "details": {
            "field": "success_url"
        }
    }
}
 

Request      

POST api/v1/billing/checkout

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

interval   string     

One of monthly or annual. Example: monthly

success_url   string     

Absolute URL after successful checkout. Example: https://app.example.com/billing/success

cancel_url   string     

Absolute URL if the customer cancels. Example: https://app.example.com/billing/cancel

Billing portal

requires authentication

Returns a Stripe Customer Portal URL for the authenticated user. Optional return_url host must be allow-listed (same rules as checkout). When omitted, returns to the API status endpoint.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/billing/portal?return_url=https%3A%2F%2Fapp.example.com%2Fapp%2Fbilling" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"return_url\": \"http:\\/\\/www.bailey.biz\\/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html\"
}"
const url = new URL(
    "http://localhost/api/v1/billing/portal"
);

const params = {
    "return_url": "https://app.example.com/app/billing",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "return_url": "http:\/\/www.bailey.biz\/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html"
};

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/billing/portal'
payload = {
    "return_url": "http:\/\/www.bailey.biz\/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html"
}
params = {
  'return_url': 'https://app.example.com/app/billing',
}
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers, json=payload, params=params)
response.json()

Example response (200, Success):


{
    "data": {
        "url": "https://billing.stripe.com/p/session/…"
    }
}
 

Example response (422, Invalid return URL):


{
    "error": {
        "code": "invalid_return_url",
        "message": "return_url host is not allowed",
        "details": {
            "field": "return_url"
        }
    }
}
 

Request      

GET api/v1/billing/portal

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

return_url   string  optional    

optional Absolute URL after leaving the portal. Example: https://app.example.com/app/billing

Body Parameters

return_url   string  optional    

Must be a valid URL. Example: http://www.bailey.biz/quos-velit-et-fugiat-sunt-nihil-accusantium-harum.html

Subscription status

requires authentication

Returns the Cashier default subscription summary for the authenticated user.

Example request:
curl --request GET \
    --get "http://localhost/api/v1/billing/subscription" \
    --header "Authorization: Bearer {YOUR_API_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost/api/v1/billing/subscription"
);

const headers = {
    "Authorization": "Bearer {YOUR_API_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());
import requests
import json

url = 'http://localhost/api/v1/billing/subscription'
headers = {
  'Authorization': 'Bearer {YOUR_API_KEY}',
  'Content-Type': 'application/json',
  'Accept': 'application/json'
}

response = requests.request('GET', url, headers=headers)
response.json()

Example response (200, Active):


{
    "data": {
        "status": "active",
        "interval": "monthly",
        "on_trial": false,
        "ends_at": null,
        "trial_ends_at": null,
        "stripe_price": "price_…"
    }
}
 

Example response (200, None):


{
    "data": {
        "status": "none",
        "interval": null,
        "on_trial": false,
        "ends_at": null,
        "trial_ends_at": null,
        "stripe_price": null
    }
}
 

Request      

GET api/v1/billing/subscription

Headers

Authorization        

Example: Bearer {YOUR_API_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json