Phaze Enterprise API
Please note: This is an early v1 release of the Phaze Enterprise API. We may need to introduce breaking changes to this version in the future. For example, we plan to change how Phaze Relays are managed within an organization, which may affect parts of this API. Before introducing that change, we will email all customers who have created an API key to make sure they're aware of the expected change.
Overview
The Phaze Enterprise API is a REST interface for managing your enterprise from your own tools and automation. With an API key created in the Phaze Admin Panel, you can invite and manage members, organize them into organizations and groups, control who can reach which machines, and run the locations and relays that carry connections inside your network. This API is available to enterprises on a Phaze Enterprise plan.
Getting an API key
To get an API key, an account is required. Please sign up for an account at https://dashboard.phaze.app/signup. Once you create your enterprise, visit https://dashboard.phaze.app/settings, scroll down and choose "Create key." From there, name your key and provide an optional description and choose the expiry from the drop down. After clicking "Generate key," your key will appear at the top of the API Keys list. Copy that secret and store it somewhere safe. This will be the only time you can see the secret.
Authentication
Every request must carry an enterprise API key as a Bearer token in the Authorization header (Authorization: Bearer <key>).
Keys are created by enterprise admins in the Phaze Admin Panel and are scoped to a single enterprise. Every resource in this API is resolved within that enterprise, so an organization or user that belongs to another enterprise is reported as 404 not_found.
Unknown, revoked, or expired keys receive 401 unauthorized.
Rate limits
Limits are enforced per enterprise, so all keys of one enterprise share the same budget. Exceeding a limit returns 429 too_many_requests and starts a lockout during which every request in that scope is rejected.
| Scope | Limit | Lockout after exceeding |
|---|---|---|
| Default, all endpoints | 600 requests per minute | 1 minute |
Email sending: POST /invites and POST /invites/resend when send_email is true |
20 requests per 5 minutes | 5 minutes |
Rate limit headers
Every response includes the current rate limit state for its scope.
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum number of requests allowed in the current window |
X-RateLimit-Remaining |
Requests left in the current window, 0 while rejected |
Retry-After |
Seconds to wait before retrying. Only present on 429 responses |
Pagination
List endpoints accept the following query parameters. Out-of-range values are clamped rather than rejected. The response count is the total number of matching items, so offset + limit < count means more pages remain.
| Parameter | Default | Description |
|---|---|---|
limit |
50 |
Number of items per page, from 1 to 200 |
offset |
0 |
Number of items to skip, 0 or greater |
Requests
- The base URL is
https://public-api.phaze.app/enterprise/v1. All paths in this reference are relative to it. - Request bodies must be JSON and sent with
Content-Type: application/json. Other media types receive415. - Requests time out after 10 seconds.
PATCHendpoints are partial updates. Send only the fields to change; omitted fields keep their current value. A body with no updatable fields is rejected with400.- Bulk endpoints take an array of items with a per-endpoint maximum. Duplicates are rejected with
422. Where an endpoint can partially succeed, valid items are applied and the rest are returned underrejectedwith areason.
Audit logging
Key security changes are recorded in the enterprise's audit logs.
Responses
Every JSON response carries a status field with the HTTP status text. Single resources are returned under data. Lists return an array under data plus a count of the total items matching the query across all pages. 204 No Content responses have no body.
// single resource
{ "status": "OK", "data": { ... } }
// paginated resources
{ "status": "OK", "data": [ ... ], "count": 0 }
Errors
The API uses standard HTTP status codes. Unsuccessful responses carry an errors array where each item has a machine-readable code and a human-readable message. Validation failures return 422 with one item per invalid field, where field names the request body field.
// error
{ "status": "Not Found", "errors": [ { "code": "not_found", "message": "..." } ] }
// validation error
{ "status": "Unprocessable Entity", "errors": [ { "code": "validation_failed", "field": "role", "message": "..." } ] }
| Status | Code | When |
|---|---|---|
| 400 | bad_request |
Malformed JSON, invalid path or query parameter, or an empty update |
| 401 | unauthorized |
Missing, unknown, or expired API key |
| 403 | forbidden |
The operation is disabled for this enterprise |
| 403 | limit_reached |
A resource limit was hit, the message names the limit |
| 404 | not_found |
The resource does not exist in this enterprise |
| 405 | method_not_allowed |
Unsupported method for the path |
| 409 | conflict |
A resource with the same name already exists |
| 409 | org_not_empty |
The organization cannot be deleted while it has machines or relays |
| 409 | location_has_relays |
The location cannot be deleted while it has relays |
| 415 | unsupported_media_type |
Request body is not application/json |
| 422 | validation_failed |
One or more request body fields are invalid |
| 429 | too_many_requests |
Rate limit exceeded, see Retry-After |
| 500 | internal_server_error |
Unexpected server error |
Timestamps
Timestamps in request and response bodies are RFC 3339 strings in UTC, for example 2026-09-04T18:21:07Z.
Resource limits
Creating a resource beyond these limits fails with 403 limit_reached.
| Resource | Limit |
|---|---|
| Organizations per enterprise | 50 |
| Members per enterprise, pending invites included | 20000 |
| Members per organization | 5000 |
| Machines per organization | 5000 |
| Machine keys per organization | 200 |
| Groups per organization | 200 |
| Members per group | 500 |
| Locations per organization | 100 |
| Relays per organization | 200 |
Roles
Every member has one enterprise role, set with PUT /members/role, and a role in each organization they are assigned to, set with PUT /orgs/{org_id}/members/assign. The enterprise owner is always an admin.
Enterprise roles
| Role | Description |
|---|---|
member |
No access to the enterprise Admin Panel |
billing_manager |
Can view usage and invoices and manage payment methods in the enterprise Admin Panel |
admin |
Full access to the enterprise Admin Panel |
Organization roles
| Role | Description |
|---|---|
member |
No access to the organization Admin Panel |
it_support |
Read-only access to the organization's members, groups, machines and connections in the Admin Panel, and can connect to machines not assigned to a user or group without approval |
admin |
Full access to the organization Admin Panel, and can connect to machines not assigned to a user or group without approval |
| Connecting to a machine assigned to a user or group requires approval unless the connecting user is its assignee or a member of its group, whatever their role. |
SCIM
When directory sync (SCIM) is enabled for the enterprise, the identity provider owns the member lifecycle. Creating, resending, or deleting invites and deleting members return 403 forbidden. Role changes and organization assignments remain available unless SCIM group sync is also enabled, in which case the directory groups own enterprise roles, organization memberships and group memberships too, and changing member roles, assigning or unassigning organization members, and adding or removing group members return 403 forbidden.