Docs
Sign in

API overview

How the UnitX REST API works: addresses and versioning, authenticating with API keys or OAuth tokens, rate limits, errors and webhooks.

Everything you can do in UnitX goes through the same REST API that the app itself uses, so scripts and integrations can read and change your organization’s data under the same permission rules as people. This page covers what developers need to know first: addresses, authentication, limits, errors and webhooks.

What you can build#

  • Scripts and scheduled jobs that create or update records, using an API key.
  • Tools that act as the person using them, using an OAuth application.
  • Systems that react to changes in UnitX, using outgoing webhooks.
  • User provisioning from your identity provider, using SCIM.
  • Apps for other organizations, published through the Marketplace.

Addresses and versioning#

API operations live under /api/v1/ on your UnitX API address — for example /api/v1/projects. The version is part of the path. Within a version, changes are additive; a breaking change would come with a new version.

A few addresses keep their own shape because outside systems depend on them:

/openapi.json
The published OpenAPI specification. Public, no sign-in needed.
/oauth/…
OAuth authorization and token endpoints.
/scim/v2/…
SCIM provisioning endpoints.
/integrations/webhooks/…
Addresses that other systems post incoming webhooks to.

Tip

The OpenAPI specification describes every operation, its parameters and the credential it requires. Point your API client or code generator at /openapi.json.

Authentication#

Send a credential in the Authorization header as a bearer token:

Authorization: Bearer <credential>

CredentialActs asOrganization
API key (begins uxk_)The person or service account it belongs to, limited to its scopesFixed to the organization the key was created in
OAuth access tokenThe person who approved the application, limited to the approved scopesFixed to the organization it was approved in

With an API key or OAuth token you do not need to name the organization. If you send an X-Organization-Id header anyway, it must match the credential’s organization or the request is refused.

Permissions#

  • Every operation needs a permission, such as project.view. A request whose credential does not carry it is refused with 403.
  • An API key or token can only use permissions listed in its scopes. A service account’s key is also limited by the service account’s role.
  • Permissions narrowed by a scope such as “Their own records” describe a person, so they cannot be used by machine credentials.
  • Fields your organization has restricted through data classification are left out of responses for credentials without the required permission.

See Service accounts and API keys and OAuth applications for how to obtain each credential.

Rate limits#

Requests are counted in one-minute windows. Two limits apply at the same time, and reaching either one limits the request:

Counted perRequests per minute
Organization (all credentials and people together)1,000
API key300

Every response includes headers so a client can slow down before hitting the limit:

RateLimit-Limit
The limit that applies.
RateLimit-Remaining
Requests left in the current window.
RateLimit-Reset
Seconds until the window resets (a number of seconds, not a timestamp).

Over the limit, the API answers 429 with a Retry-After header giving the seconds to wait.

Requests and validation#

  • Send and receive JSON.
  • Unknown fields are rejected, not silently ignored. A misspelt field name fails with 400 and says which field was wrong.
  • Lists that can grow large, such as the activity feed and the audit trail, are fetched a page at a time with cursor and limit parameters. The specification shows which operations are paged.

Errors#

Errors share one shape, with a stable code you can program against:

{ "error": { "code": "not_found", "message": "…", "details": null, "requestId": "…" } }

details lists the individual problems when validation fails. Quote requestId when you contact support. Common codes:

StatusCode
400bad_request
401unauthorized
403forbidden
404not_found
409conflict
422unprocessable_entity
429rate_limited
5xxinternal_error or service_unavailable

Deprecations#

If an operation is ever scheduled for removal, its responses carry a Deprecation header, a Sunset header with the removal date when one is set, and a Link header pointing to what to use instead. Watch for these in your logs.

Webhooks#

Outgoing webhooks#

Add an endpoint under Integrations → Outgoing webhooks and UnitX sends each event to it as an HTTP POST with a JSON body:

{ "id": "…", "type": "…", "occurredAt": "2026-09-16T10:00:00.000Z", "data": { … } }

x-unitx-event
The event type.
x-unitx-delivery
A unique id for this delivery.
x-unitx-signature
sha256= followed by the hex HMAC-SHA256 of the raw request body, using the endpoint’s signing secret. Compute it yourself and compare before trusting the request.

Respond with a 2xx status to acknowledge. Failed deliveries are retried with increasing delays, up to five attempts, and each attempt is visible under Deliveries.

Incoming webhooks#

For systems connected under Integrations, UnitX can receive webhooks at an endpoint you create on the connection. Each request must carry a valid x-unitx-signature computed with that endpoint’s secret.

Provisioning with SCIM#

User provisioning uses the SCIM 2.0 standard at /scim/v2/Users and /scim/v2/Groups, authenticated with a SCIM credential rather than an API key. See SCIM provisioning.

Why do I get 403 when my key has the right scope?

For a service account’s key, the account’s role must also hold the permission, and not only under a scope such as “Their own records”. Check the role on the Roles screen. The account may also be disabled.

My API key stopped working suddenly.

It may have expired, been revoked, belonged to someone who was suspended or removed, or belonged to a service account that was disabled. Keys revoked for any of these reasons do not come back; create a new one.

Is there an SDK?

Generate a client from /openapi.json with the OpenAPI tooling for your language.

Still stuck? Search the docs with ⌘K, open Help inside UnitX, or contact support.