# RentEngine Public API > JWT Bearer API for leasing: units, prospects, lockboxes, applications, webhooks, and reporting. Base URL: https://app.rentengine.io/api/public/v1 OpenAPI: https://app.rentengine.io/openApi/api/public/v1/openApiSpec.yaml Changelog: https://app.rentengine.io/openApi/api/public/v1/CHANGELOG.md Compatibility: https://app.rentengine.io/openApi/api/public/v1/compatibility.md Human docs: https://app.rentengine.io/developer/portal ## Auth Authorization: Bearer Create and revoke tokens in the developer portal. Tokens inherit the creating user's account permissions. Read-only keys (portal checkbox) may call GET/HEAD only; writes return `403` `read_only_token`. Existing keys without the claim keep full access. Endpoints that require a key answer a revoked one with `401` `api_key_revoked`. ## Pagination Query: `limit` and `page_number` (0-indexed). Most list endpoints default `limit` to 50 (max 100); notes, follow-ups, leasing events, and reporting default to 100 (max 2000). Legacy list endpoints return a JSON array. They also send: - `X-Has-More: true|false` - `X-Next-Page-Number: ` when another page exists Newer list endpoints (`GET /rental_application_groups`, follow-ups, notes, leasing events) wrap `{ data, page }`. ## Incremental sync `GET /units` and `GET /prospects` accept `updated_after` / `updated_before` (ISO-8601). `GET /rental_application_groups` already did. ## Errors Bearer-authenticated JSON errors for mapped statuses are `{ "error": string, "code": string, ... }`. Branch on `code` when present, not on the message text. Extra fields (`details`, `retryAfter`, `message`) are unchanged. Unmapped statuses may omit `code`. Codes: `validation_error` (400), `unauthorized` (401), `api_key_revoked` (401), `forbidden` (403), `read_only_token` (403), `not_found` (404), `conflict` (409), `unprocessable_entity` (422), `rate_limited` (429), `internal_error` (500), `service_unavailable` (503). Unauthenticated POSTs (`POST /showings/create`) are unchanged. ## Idempotency Bearer-authenticated POST endpoints accept an optional `Idempotency-Key` header (printable ASCII, 1–256 characters, no spaces). Keys are scoped to the authenticated user, HTTP method, and path, and are remembered for 24 hours. Unauthenticated POSTs (`POST /showings/create`) do not honor the header. - The first 2xx response for a given key is stored for 24 hours. - A retry with the same key and the same body returns that stored response (no second write). - The same key with a different body returns `422`. - A concurrent retry while the first request is still running returns `409`. - `4xx` and `5xx` are not stored, so a later retry with the same key is executed again. If you send `Idempotency-Key` and the idempotency store is unavailable, the API returns `503` rather than risk a duplicate write. ## Tracing On Bearer-authenticated routes, send `X-Request-Id` (printable ASCII, 1–128 chars, no spaces) and we echo it. An id that does not meet those constraints is ignored — read the value back off the response rather than assuming yours was echoed. If omitted, we return our internal request id used for tracing. It is the id in RentEngine logs. It is not an idempotency key — use `Idempotency-Key` to prevent duplicate writes. ## Compatibility Additive changes on `/api/public/v1`. Breaking changes get a new path prefix. See https://app.rentengine.io/openApi/api/public/v1/compatibility.md.