Authentication
Every API request authenticates with an API key sent as a Bearer token. Keys are scoped to your organization and can be restricted to a subset of endpoints.
Bearer token
Send the key in the Authorization header, prefixed with Bearer. Live keys start with psk_live_, sandbox keys with psk_test_. The key is shown exactly once at creation — keep it in a secret manager, never in source or version control.
Authorization: Bearer psk_live_3f9a...Per-key allowlists
Each key carries an allowlist that limits which endpoints it can call. A key without the required scope gets a 403 forbidden. Issue least-privilege keys per integration and rotate them from the dashboard if one is ever exposed.
Rate limits
Responses carry X-RateLimit-* headers describing the current window. When you exceed the per-key rate you get 429 rate_limit_exceeded together with a Retry-After header: wait that long and retry. A used-up monthly quota is NOT a 429: plans without overage get 402 quota_exceeded (with X-Posty-Period-Resets-At), which retrying will not fix. Only billable calls (lookup, search, autocomplete, verify, batch submit) count toward the quota; usage reads and batch polling never return 402.
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum number of requests allowed in the current window. |
X-RateLimit-Remaining | How many requests you have left in the current window. |
X-RateLimit-Reset | Unix timestamp at which the window resets. |
Retry-After | Seconds to wait before retrying (present on 429 only). |
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1718700000
Retry-After: 12
Content-Type: application/json
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded, please slow down",
"request_id": "a1b2c3d4e5f6a7b8"
}
}Other response headers
| Header | Description |
|---|---|
X-Posty-Request-Id | Request identifier on every response (also error.request_id). Quote it when contacting support. |
X-Cache | HIT when served from cache, MISS when computed. Absent when the cache was bypassed. 200 responses only (postal-code lookup, autocomplete). |
X-Data-Attribution | Licence attribution for the data sources (OGL-ROU-1.0; ODbL-1.0 for OpenStreetMap when that source is enabled). If you display results, display this text too. |
Link | Always sent with X-Data-Attribution: <https://posty.ro/legal/data-sources>; rel="license". |
X-Posty-Period-Resets-At | On 402 quota_exceeded: RFC 3339 time at which the monthly quota resets. |
X-Posty-Grace-Period-Ends | On 402 payment_required: end of the past-due grace period. |
Idempotency-Key
For POST requests you can send an Idempotency-Key header (a UUID) to make retries safe against double processing. Replaying the same key with a different body returns 409 idempotency_conflict; the same key with the same body returns the original response.
curl -X POST https://api.posty.ro/v1/addresses/verify \
-H "Authorization: Bearer psk_live_xxx" \
-H "Idempotency-Key: 7c1f6e2a-9b3d-4e6f-8a1c-2d4f6e8a0b2c" \
-H "Content-Type: application/json" \
-d '{ "freeform": "Str. Mihai Viteazu 12, Cluj" }'