REST API
Use the REST API to manage Inth organizations, members, projects, and API keys, run Code Audit scans, and work the Inbox from a server, script, or CI job.
- Base URL.
https://api.inth.com - OpenAPI spec.
https://api.inth.com/openapi.json - Status.
GET /health
To connect Codex or another MCP client with your Inth account, use Inth MCP instead.
Authentication
Every request carries a bearer token. There are two kinds.
Organization API keys are service credentials for CI jobs, servers, and integrations. They belong to an organization, not a person, and keep working when the person who created them leaves.
Create a key in Organization settings > API keys. Inth shows the inth_...
secret once. Store it like a deployment credential and never expose it in
client-side code. Each key has access to its organization.
User tokens belong to a person. They are issued through the OAuth device
authorization grant: a client requests a code, you approve it in the
dashboard, and the client receives an access token plus a refresh token bound
to your account. Requests act with your own organization memberships and
roles, and stop working when you leave an organization. The endpoints are
advertised in the authorization server metadata at
https://api.inth.com/.well-known/oauth-authorization-server; use the
device_authorization_endpoint and token_endpoint it lists with the
inth-cli client. The Inth CLI, which wraps this flow, is not released yet.
Some operations act on behalf of a person rather than an organization and
accept only a user token: creating an organization, inviting or changing
members, creating, rolling, or deleting API keys, starting or unlocking Code
Audit scans, and changing Inbox findings. A scan spends credits and a status
change names who made it, so both are attributed to a person. An organization
API key belongs to one organization and cannot found another, so
POST /v1/organizations answers 403 to a key.
The request answers 201 with the new organization's id, slug, name,
and your owner role, and sets up billing on the free plan. Slugs are 3 to 20
characters of lowercase letters and numbers, with single hyphens between
groups. A taken slug answers 409 with CONFLICT.
See rate limits for the request limits and API key caps that apply to each kind of token.
Scopes
Each endpoint requires a scope. A token carries the scopes it was issued with, and a request still needs the membership role behind the token to allow the action.
| Scope | Grants |
|---|---|
organizations.read | List the organizations you belong to. |
organizations.write | Create organizations you will own. |
projects.read | Read projects and their consent configuration. |
projects.write | Create, update, and delete projects and their consent configuration. |
members.read | List organization members and pending invitations. |
members.write | Invite people, cancel invitations, change roles, and remove members. |
api-keys.read | List organization API keys. |
api-keys.write | Create, roll, and delete organization API keys. |
code-audit.read | Read connected repositories, scans, scan requests, and findings. |
code-audit.write | Start scans and spend credits to unlock reports. |
inbox.read | Read Inbox findings and evidence. |
inbox.write | Update finding status and create GitHub issues. |
billing.read | Read the plan, credit balance, and top-up settings. |
A user token carries the scopes you approved at sign-in, and GET /v1/me
lists them in scopes. Organization API keys hold a fixed set:
organizations.read, projects.read, projects.write, api-keys.read,
inbox.read, and billing.read. A key cannot create
organizations, manage members, create keys, start or unlock scans, or change
Inbox findings. Code Audit scopes are excluded from organization API keys,
so these routes return 403 INSUFFICIENT_SCOPE before invoking Dashboard sync.
A request whose token lacks the scope answers 403 with the error code
INSUFFICIENT_SCOPE and names the missing scope in a header:
Resources
Every resource is top-level and every ID is global. A resource carries its own
id, name, and slug where it has one; references to other resources are
prefixed, such as organizationId on a project.
The organization is a query parameter, not part of the path or the body.
Lists and creates of organization-owned resources take an optional
organizationId. Listing or creating top-level organizations does not use it:
Without it an OAuth token uses the account's saved Dashboard organization. If
that choice is unavailable and the account has multiple organizations, supply
organizationId explicitly to avoid acting in the wrong organization. A user
token with one organization uses that organization, and an organization
API key always acts in its own. A resource fetched by ID, such as a member,
scan, or Inbox item, resolves its own organization; one outside your
memberships answers 404, the same as an unknown ID. Consent settings live on
the project as a consent object: read them with GET /v1/projects/{id} and
change them with the same PATCH that renames the project.
Code Audit and the Inbox
A scan runs on the production branch of a repository the Inth GitHub App is
connected to. The first scan of a repository is a free preview: the report
shows a subset of the findings and reports how many are locked and what
unlocking costs in credits. Starting a scan answers 202 with the scan once
the workflow has created it, or with a scan request to poll when that takes
longer than a few seconds.
The repository decides the organization. Read the findings with
GET /v1/code-audit/scans/{scanId}/issues. A free preview answers the visible
findings plus lockedCount and unlockCredits;
POST /v1/code-audit/scans/{scanId}/unlock spends the credits, and answers
402 with INSUFFICIENT_CREDITS when the balance is short. Check the balance
first with GET /v1/billing.
Every scan also files its findings into the Inbox. Read them with
GET /v1/inbox, and set a status with PATCH /v1/inbox/{itemId}, sending
back the version you read so two people cannot overwrite each other.
Responses
Every endpoint wraps its result in a stable envelope:
List endpoints return data as an array plus a pagination object. Pass
pagination.nextCursor as the cursor query parameter to fetch the next page.
Cursors are opaque and specific to the endpoint and filters that returned them.
Do not decode them or reuse them with another endpoint or filter set.
For example:
Errors use the same envelope with success: false and a machine-readable
error.code. Validation errors may include an error.details array.
Every response carries an X-Request-Id header. Include it when reporting an issue.
Stability
Changes within v1 are additive. Clients should ignore fields they do not
recognize. Breaking changes use a new version prefix.
Treat resource IDs as opaque strings.
Endpoints
System
- Health check:
GET /health - Get the calling credential:
GET /v1/me
API keys
- List API keys:
GET /v1/api-keys - Create API key:
POST /v1/api-keys - Delete API key:
DELETE /v1/api-keys/{keyId} - Roll API key:
POST /v1/api-keys/{keyId}/roll
Billing
- Get billing:
GET /v1/billing
Code Audit
- List connected repositories:
GET /v1/code-audit/repositories - Get scan request:
GET /v1/code-audit/scan-requests/{preparationId} - List scans:
GET /v1/code-audit/scans - Start scan:
POST /v1/code-audit/scans - Get scan:
GET /v1/code-audit/scans/{scanId} - Get scan issues:
GET /v1/code-audit/scans/{scanId}/issues - Unlock scan report:
POST /v1/code-audit/scans/{scanId}/unlock
Inbox
- List Inbox items:
GET /v1/inbox - Get Inbox item:
GET /v1/inbox/{itemId} - Update Inbox item status:
PATCH /v1/inbox/{itemId} - Create GitHub issue:
POST /v1/inbox/{itemId}/github-issue
Members
- List invitations:
GET /v1/invitations - Invite member:
POST /v1/invitations - Cancel invitation:
DELETE /v1/invitations/{invitationId} - List members:
GET /v1/members - Remove member:
DELETE /v1/members/{memberId} - Update member role:
PATCH /v1/members/{memberId}
Organizations
- List organizations:
GET /v1/organizations - Create organization:
POST /v1/organizations - Get organization:
GET /v1/organizations/{organizationId}
Projects
- List projects:
GET /v1/projects - Create project:
POST /v1/projects - Get project:
GET /v1/projects/{projectId} - Delete project:
DELETE /v1/projects/{projectId} - Update project:
PATCH /v1/projects/{projectId} - List regions:
GET /v1/regions