Every request carries an API key as a Bearer token. A key belongs to one agency, holds a list of scopes, and can be limited to an IP range, an expiry date and an environment.
Authorization: Bearer lf_live_k3j9x2mqA7bC9dEfGhIjKlMnOpQrStUvWxYz0123
Keys are never accepted in a query string. A missing, unknown, revoked or expired key, a call from outside the key's IP allow-list, or a key used in the wrong environment all answer 401 as problem+json with a one-line reason.
| Prefix | Bound to | Issued by |
|---|---|---|
lf_live_… | A real agency | The agency's owner or manager, in Settings → API & webhooks |
lf_test_… | The sandbox agency only | Letfold, when a partner request is approved; delivered by a one-time link |
A test key can never reach a real agency and a live key can never reach the sandbox: the environment is checked on every call.
Each route is guarded by one scope, named resource:read or resource:write. A key that lacks the scope gets 403 naming it. Writes exist only where listed; there are no money writes and no property-identity writes in v1.
| Group | Scope | Grants |
|---|---|---|
| Agency & branches | agency:read | Read the agency profile and its branches |
| Properties | properties:read | Read properties, marketing details and photos |
| Landlords | landlords:read | Read landlords |
| Tenants | tenants:read | Read tenants |
| Leads (enquiries) | leads:read | Read enquiries |
leads:write | Create enquiries (POST /leads) | |
| Viewings | viewings:read | Read viewings |
viewings:write | Book viewings, change status and feedback | |
| Tenancies | tenancies:read | Read tenancies and rent schedules |
| Payments | payments:read | Read rent payments and arrears (read-only) |
| Maintenance | maintenance:read | Read repair tickets and their notes |
maintenance:write | Raise tickets, change status, add notes | |
| Contractors | contractors:read | Read contractors |
| Documents | documents:read | List documents and get short-lived download links |
documents:write | Upload documents | |
| Certificates & compliance | compliance:read | Read safety certificates |
compliance:write | Add safety certificates | |
| Tasks | tasks:read | Read tasks |
tasks:write | Create tasks | |
| Webhooks | webhooks:manage | Manage webhook endpoints and deliveries |
| Personal data | pii:read | Unmask email addresses, phone numbers and dates of birth |
Email addresses, phone numbers, dates of birth and postal addresses of landlords, tenants, leads, viewing attendees and contractors are masked unless the key holds pii:read: "m***@ellery.example", "07*** ***123", null for a date of birth. Every such representation carries "pii_masked": true|false so your code can tell. Ask for pii:read only when you have a lawful basis and a signed data processing agreement.
Roll issues a replacement with the same settings; the old key keeps working for 24 hours so you can switch without downtime. Revoke stops a key immediately (401 on the next call). Both are logged in the agency's audit trail, and every write the key makes is stamped source: api:<key name> there too.
Inside the agency, API writes are recorded against the agency's owner account with the key's name as the source. Branch-restricted staff accounts are never used, so a key sees the whole agency.