Risk API
Errors
HTTP status codes, error shape, and a fail-open recommendation for checkout.
Status codes
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Request body is missing a required field or has a malformed value. |
| 401 | invalid_key | The X-StaySignals-Key header is missing or the key is unknown. |
| 403 | key_mode_mismatch | You used a publishable key (pk_) where a secret key (sk_) is required, or vice versa. |
| 429 | rate_limited | Your project has exceeded its request quota. Retry with exponential backoff. |
| 5xx | service_error | Temporary server error. Safe to retry once; fail open after that. |
Error body
Every error response uses the same shape:
{
"error": {
"code": "invalid_request",
"message": "Field 'booking.check_in' is required.",
"request_id": "req_8b3c1d9e2f"
}
}Include request_id when you report an issue — it lets us trace the exact call on our side.
Fail open on checkout
Your checkout is a critical revenue path. A transient StaySignals outage or a slow network hop should not stop a real customer from booking.
Recommended default: on any 5xx or request timeout, treat the booking as allow and proceed with checkout. Missing some fraud detection for a few minutes is strictly better than turning away real customers at checkout.
A sketch of the pattern:
# Pseudocode.
response = POST /v1/risk (with your own timeout)
if response.status == 200:
action = response.body.suggested_action
elif response.status in (5xx, timeout):
action = "allow" # fail open
log_for_later(request_id, reason) # audit trail
else:
action = handle_4xx(response) # fix your requestSet a timeout that fits your checkout SLA and fail open when it fires. Log every fail-open event; you'll want to know if it becomes common.