Authentication
Every REST API request carries an API key as a bearer token. Keys belong to your workspace, act as the person who created them, and are either read-only or read-write.
GET /api/v1/entries HTTP/1.1Host: api.prophouse.devAuthorization: Bearer ph_live_xxxxxxxxxxxxCreate an API key
Section titled “Create an API key”Open API keys in the account dashboard at https://app.prophouse.dev/keys, enter a Name, pick a Scope, and click Create key. The full key is shown once; copy it then. The dashboard lists each key with its prefix, scope and last-used time, and Revoke disables it on the next request. See API keys for the dashboard side.
Hosted keys start with ph_live_. Treat them like passwords: keep them out of source control and pass them through an environment variable or a secret store.
Scopes
Section titled “Scopes”| Scope | What it allows |
|---|---|
read |
Every GET, plus POST /entries/search/image (search by image is a read that needs a request body). Search, browse, download, read comments, reviews and activity. |
write |
Everything read allows, plus every other POST, PUT, PATCH and DELETE: pushing, editing, commenting, reviewing, creating pull jobs, check-out locks. |
A read-scoped key that attempts a write gets 403 with the message This key is read-only. …. Write scope is available on every plan.
Identity and role
Section titled “Identity and role”A request made with a key acts as the person who created the key. Comments, check-outs, pushes and review decisions are attributed to that person, and the key carries that person’s current role in the workspace:
| Workspace role | In the API |
|---|---|
| Owner or admin | Admin. Can call endpoints marked Admin in this reference (webhooks, denylist, entry deletion, deprecation). |
| Member | Regular member. Admin-only endpoints return 403 FORBIDDEN. |
Role changes apply on the next request. If the creator leaves the workspace, every key they created stops working with 401.
To find out who a key is, call GET /auth/me:
{ "user": { "id": "<account_id>", "name": "Ada Artist", "email": "ada@example.com", "display_name": "Ada Artist", "role": "admin" }, "name": "Ada Artist", "org_id": "<workspace_id>", "org": { "id": "<workspace_id>", "name": "Northwind Games", "slug": "northwind" }, "scope": "write"}role is admin for workspace owners and admins, otherwise member. The user.id here is your account id. Payloads inside the library (comment authors, lock holders, reviewers) use library-local numeric user ids; call GET /members/me to get yours.
Device sign-in for apps
Section titled “Device sign-in for apps”If you are building an app or command-line tool that people sign into, use device authorization (RFC 8628 style) instead of asking them to paste a key. The app gets its own key, visible and revocable in the dashboard like any other.
-
Request a code. No authentication is needed.
Terminal window curl -X POST https://api.prophouse.dev/api/v1/auth/device/code \-H "Content-Type: application/json" \-d '{"client_name": "Asset sync script", "scopes": "write"}'{"device_code": "phd_...","user_code": "WXYZ-BCDF","verification_uri": "/device","verification_uri_complete": "/device?code=WXYZ-BCDF","expires_in": 900,"interval": 2}client_name(up to 80 characters) is what the person sees when approving and becomes part of the key’s name.scopesisread(the default) orwrite. -
Show the person the
user_codeand openhttps://api.prophouse.devfollowed byverification_uri_completein their browser. The URIs are relative on purpose. The person signs in to the dashboard, checks the code and approves or denies. -
Poll for the key every
intervalseconds until the code expires (15 minutes).Terminal window curl -X POST https://api.prophouse.dev/api/v1/auth/device/token \-H "Content-Type: application/json" \-d '{"device_code": "phd_..."}'Once approved, the response carries the key exactly once:
{"token": "ph_live_xxxxxxxxxxxx","token_id": "<key_id>","scope": "write","gateway_url": "https://api.prophouse.dev"}
Poll outcomes use the standard error envelope, so switch on error.code:
| Status | error.code |
Meaning and what to do |
|---|---|---|
| 400 | DEVICE_PENDING |
Not approved yet. Keep polling at details.interval seconds. |
| 429 | DEVICE_SLOW_DOWN |
You polled faster than allowed. Wait details.interval seconds before the next poll. |
| 400 | DEVICE_EXPIRED |
The code expired. Start again from step 1. |
| 400 | DEVICE_DENIED |
The person denied the request. Stop. |
| 401 | UNAUTHORIZED |
Unknown device code, or the key was already collected. |
| 400 | INVALID_REQUEST |
The body has no device_code. |
Requesting codes is rate limited; too many attempts in a short time make POST /auth/device/code return 429 (retry a few minutes later).
Authentication errors
Section titled “Authentication errors”| Status | When |
|---|---|
401 |
No Authorization header, unknown or revoked key, or the key’s creator is no longer a workspace member. |
403 |
A read-scoped key attempted a write, or a member called an admin-only endpoint. |
Authentication failures from the API front door have a short body such as {"error": "Unknown or revoked API key."}. See Errors and rate limits for both error shapes.
