Core concepts
Limits and conventions
Rate limiting, hotel codes, and the middleware order that shapes every failure.
6. Rate limiting#
Limits are per credential, not per IP — a partner behind a NAT pool cannot multiply its ceiling by adding egress addresses.
| Default | |
|---|---|
| Authenticated, per key | 300 requests/minute (per-key override available) |
| Unauthenticated (per IP) | 30 requests/minute |
Your effective limit is on /whoami as key.rate_limit_per_minute. On 429 the
response carries Retry-After and details.retry_after.
7. Hotel codes, never our ids#
Every identifier you send and receive is your code from the channel mapping
tables. Staylah's internal properties.id is never accepted and never returned
as a hotel code — those ids are unstable across data migrations and enumerable.
GET /mapping/hotels is the only authority on what your codes are, and is the
first call of any real integration.
8. Middleware order (why a failure looks the way it does)#
connectivity.log → runs first, so requests rejected by auth are still logged
connectivity.auth → resolves the key, verifies secret, state, IP, env, signature
throttle:connectivity → after auth, so the limiter keys on your credential
connectivity.scope → per-route, declared on each endpoint
Consequence worth knowing: a rejected request is still logged, so "we never saw your call" and "we rejected your call" are always distinguishable on our side.
