Skip to the documentation

Authentication

Keys, scopes, the two kinds of key, and how to rotate one.

A server calls the API with a key in the Authorization header: Authorization: Bearer <key>. A key goes only in that header, never in a URL or query string, because URLs end up in logs.

Making a key

Keys are made in Settings, API keys. A key is shown once, when it is made; we keep only a hash, so a lost key cannot be recovered, only replaced. A key has a name, an owner, an access list, limits and an end date.

What a key looks like

A key is 53 characters: a prefix that says what it is, 43 random base62 characters (256 bits), and a 6-character checksum. A scanner can recognize a leaked key and check it offline, and a mistyped key is refused before any lookup.

PrefixKindActs as
lmp_PersonalThe person who made it. It can never do more than they can.
lmo_OrganizationThe org, within its scopes. Made by an admin and tied to them: it works only while they still administer the org.

Scopes

A key lists what it may do. Every endpoint names the one scope it needs, and a key without it is refused with 403 insufficient-scope. Writing a thing includes reading it. A key made with Full access carries every ordinary scope its kind may, including ones added later. It does not include running for another account. A key that lists scopes carries only those.

Running a match for a realtor

An agent that many realtors use holds one key. It is not signed in as them. A Livia admin ticks Run for another account (account:associate) when making that key. Only a Livia admin can tick it, and the key is checked again on every request: if they are no longer a Livia admin, naming an account is refused.

Send Livia-Account with the realtor's email, or their user id. The search, the match and anything else that key does are saved to that account, so the realtor signs in and sees them. Omit the header to act as the key's maker. A key without the scope that sends the header is refused (403 account-not-permitted), rather than quietly writing into the maker's account. An email or id with no Livia account is 404 account-unknown. The request does not create an account. The header is not a client. Clients are the people a realtor works for.

ScopeLets a keyKey kindsIncludesUsed by
search:readMatches, their runs, the homes they found and what they cost.PersonalOrganizationNothing17 endpoints
search:runStart, save, run, cancel and delete matches, and curate a match's shortlist. Includes reading them.PersonalOrganizationsearch:read11 endpoints
clients:readYour clients: their names, emails and notes.PersonalOrganizationNothing2 endpoints
clients:writeAdd and edit clients, and archive or restore them. Includes reading them.PersonalOrganizationclients:read3 endpoints
briefs:readWhat each client needs.PersonalOrganizationNothing4 endpoints
briefs:writeMake and change searches, including drafting one from words. Includes reading them.PersonalOrganizationbriefs:read6 endpoints
shares:readThe shortlists shared with clients, and what clients answered.PersonalOrganizationNothing4 endpoints
shares:writeGive a client access, share a shortlist, email it and stop sharing it. Includes reading shares.PersonalOrganizationshares:read7 endpoints
profile:readFor a personal key, your name, email and organization. For an organization key, the organization and the admin who made it.PersonalOrganizationNothing1 endpoint
org:readIts members and this month's usage.OrganizationNothing3 endpoints
audit:readWho did what in the organization.OrganizationNothing1 endpoint
members:writeInvite people, revoke invites, and change or remove members. Never the owner. Includes reading the organization.Organizationorg:read4 endpoints
org:writeThe name, the brand policy, client sign-in, and each person's monthly matches. Includes reading the organization.Organizationorg:read3 endpoints
account:associateSend Livia-Account with the realtor's email or user id. The match is saved to their account. Full access does not include this.PersonalOrganizationNothing0 endpoints

A signed-in browser session can call these endpoints too, as the person. A few endpoints belong only to the app and refuse a key; the reference marks them Browser-only.

Personal and organization keys

  • A personal key acts as its maker. Every search it starts is saved in that person's workspace and counts against their limit and the org's month.
  • An organization key is made by an admin for the whole org. Its searches land in its maker's workspace and count against the org's allowance, and the usage report lists them by key.
  • An org key is checked against its maker on every request. Demote or remove the admin and their org keys are revoked at once, with a line in the audit trail. A later re-promotion never brings a key back.
  • Both kinds may carry profile:read, so a script can call GET /api/v1/me and learn whose key it holds: the person for a personal key, the organization and its admin for an org key. Personal keys never carry the org's scopes.
  • No endpoint changes the owner. Ownership moves only in Settings, by the owner.

Limits and lifetime

LimitDefaultLeastMost
Requests a minute1201600
Requests a monthNone11,000,000
Lifetime3 months1 week5 years

What a refused call looks like

StatusCodeHeaderMeans
401unauthenticatedWWW-Authenticate: Bearer realm="livia-match"No key and no session.
401invalid-api-keyWWW-Authenticate: Bearer error="invalid_token"Misspelled, expired, revoked, or its maker lost admin. We never say which.
403insufficient-scopeWWW-Authenticate: Bearer error="insufficient_scope", scope="search:run"The key is live but lacks the scope named in the header.
403account-not-permittedLivia-AccountThe key may not name another account, or its maker is no longer a Livia admin.
400account-invalidLivia-AccountThe header is neither an email nor a user id.
404account-unknownLivia-AccountNo Livia account has that email or id. The call does not create one.
429rate-limited / monthly-cap-reachedRetry-AfterOver a limit. See Rate limits.

A call that presents a key never falls back to a browser session when the key is wrong. A server that sent a bad key hears so.

Rotating a key

A key's name, kind and end date never change, which keeps rotation honest: a new end date is a new key. To rotate without downtime:

  1. Make a new key with the same access under a new name, like crm-search-2. Names must be unique among live keys.
  2. Deploy it. Check GET /api/v1/me or any read with it.
  3. Revoke the old key. A revoked key is refused at once, and its name is free again.

Access and limits can change in place (Change access in Settings), and the change is in the audit trail with the old and new values. Make keys short-lived and rotate them on a schedule; a week to five years is allowed, three months is the default.

If a key leaks

Revoke it in Settings now. It stops working on its next request. Then read the audit trail and the usage report for what it did.