Public API
Authentication, limits, errors, pagination, custom fields on tickets and CRM, OpenAPI, API key scope, idempotency, and what is in-app only for InboxOps integrators.
Public API
InboxOps offers a versioned REST API under /api/v1. It is served from the same origin as the InboxOps web app you use to manage tickets (the URL where you sign in to your workspace).
The contract is published as OpenAPI 3 at /api/v1/openapi.json, and Swagger UI at /api/v1/docs. Those two URLs do not require an API key, so you can open them in a browser to explore the spec.
On https://docs.inboxops.app, this guide is listed under the API tab (with the RFC 7807 error reference). In examples below we use https://app.inboxops.app as a placeholder base URL—substitute your actual InboxOps app origin if your team uses a different hostname.
Authentication
Create an API key in InboxOps under Settings → API (workspace admins). Send it on every protected request:
Authorization: Bearer ixk_…your_secret_key…
Keys are opaque strings starting with ixk_. Store them as secrets; they are shown in full only once when created.
Key scope
When you create a key, you choose access:
| Scope | Effect |
|---|---|
| Read and write | All supported HTTP methods on /api/v1 (default for new keys). |
| Read only | GET and HEAD only. Any POST, PATCH, or DELETE returns 403 with Problem Details and code: insufficient_scope. |
Use read only for integrations that must not mutate tickets or CRM data.
Entitlement
The HTTP API and API keys require the api_webhooks entitlement (included on Growth and Business-style plans in typical packaging). Workspaces without that feature see an upgrade message in Settings → API and receive 403 from the API if a key is used.
Webhook endpoints use the same entitlement boundary: configure them in Settings → Webhooks in InboxOps.
Rate limits
The API applies per-workspace rate limiting (100 requests per minute by default). When exceeded, responses use status 429, Content-Type: application/problem+json, and include a Retry-After header (seconds until you should retry, typically 60).
Errors
Error responses use RFC 7807 Problem Details with Content-Type: application/problem+json:
{
"type": "https://docs.inboxops.app/api/problems/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Human-readable explanation",
"instance": "https://docs.inboxops.app/api/problems/instances/550e8400-e29b-41d4-a716-446655440000",
"code": "unauthorized"
}
The code field is a stable machine identifier (extension member). type and instance are URIs under https://docs.inboxops.app/api/problems/, on the same host as this documentation (https://docs.inboxops.app). Each type path resolves to a documentation page for that error code; see Public API errors. When present, instance pairs with the X-Request-Id response header (see Request correlation below and Instance URIs).
Request correlation
Every response includes X-Request-Id. You may supply your own correlation id using X-Request-Id or X-Correlation-ID (8–128 characters: letters, digits, ., _, -). If omitted or invalid, InboxOps generates a UUID. Use the same value when contacting InboxOps support or correlating with access logs.
Common cases:
| HTTP | Typical code |
|---|---|
| 400 | bad_request |
| 401 | unauthorized — missing/invalid Authorization or revoked key |
| 403 | forbidden — public API not enabled for the workspace |
| 403 | insufficient_scope — read-only key used for a mutating method |
| 404 | not_found |
| 405 | method_not_allowed |
| 409 | conflict — duplicate unique name (for example tag or company) in CRM |
| 409 | idempotency_conflict — same Idempotency-Key reused with a different JSON body (see below) |
| 429 | rate_limit_exceeded |
| 500 | internal_error |
| 503 | service_unavailable — for example attachment storage not configured |
Idempotency (create ticket)
POST /api/v1/tickets accepts an optional header:
Idempotency-Key: <your-key>
- At most 256 characters.
- If you send the same key with the same JSON body again, the API responds
201with the same ticket (no second create, no duplicate webhooks or audit entries for the replay). - If you reuse the key with a different body, the API responds
409withcode:idempotency_conflict. - Stored idempotency records expire after 7 days; after that, the same key can be used as a new create.
Pagination
List endpoints that paginate return data (array) and meta:
{
"data": [ … ],
"meta": {
"page": 1,
"per_page": 25,
"total": 42
}
}
Use page and per_page query parameters where the OpenAPI operation documents them.
Custom fields
Workspace admins define custom fields per record type (contacts, companies, tickets) in Settings → Custom fields. On the public API, values are exposed as a JSON object custom_fields keyed by each field’s stable field_key (snake_case), on:
- Tickets — GET by id, POST create, PATCH, and
ticket.created/ticket.updatedwebhook payloads (when custom fields change,changed_fieldsincludescustom_fields). The paginated GET /tickets list omitscustom_fieldsfor performance; fetch the ticket by id for values. Filtering the list: add query parameterscustom_field_+field_key(same key as incustom_fields). Combine with other list filters using AND. Use the literal value__empty__to match tickets with no stored value for that field. At most 10 distinct custom-field parameters per request; malformed keys, bad values for the field type, or duplicate keys return400(application/problem+json). Definitions scoped to selected mailboxes only match when the ticket’s inbox is linked to the definition (see OpenAPI GET /tickets). - Contacts — GET
/contacts/{id}, POST/contacts, PATCH/contacts/{id}. - Companies — GET
/companies/{id}, POST/companies, PATCH/companies/{id}.
Reading
- Active definitions that apply to the entity are always present in
custom_fields. Values arenull, a scalar, or (for multi-select) an array of strings, depending on the field type. - Ticket scope: fields limited to selected mailboxes do not appear on tickets outside those inboxes (the key is omitted).
- Archived definitions: if a value was stored before archive and the definition still matches scope (for example the same mailbox rule), the key may still appear on GET for legacy reads. Treat those keys as read-only through the API.
Writing (custom_fields on POST/PATCH)
- Only keys for active definitions that apply to that record may be sent. Unknown keys, keys for archived definitions, or ticket keys that do not apply to the ticket’s inbox return
400withapplication/problem+json(typicallycode:bad_request). - Select and multi-select values use the option’s internal UUID string(s), not labels.
- URLs must use the
https:scheme (normalized/stored like the app). - Numbers use the definition’s decimal places and half away from zero rounding at rest.
- Clearing: send
nullor an empty string/array as appropriate for the type to clear the stored value (same semantics as the in-app editor).
See CustomFieldsMap and resource schemas in /api/v1/openapi.json for the exact shape alongside each operation.
Ticket attachments
Message attachments are not separate top-level resources for download. Use GET /api/v1/attachments/{id}/download with a valid API key. The API responds with 307 Temporary Redirect to a presigned object URL (default validity 15 minutes). Clients must follow redirects (for example curl -L). The JSON representation of attachments never exposes raw storage keys.
OpenAPI as source of truth
Paths, parameters, request bodies, and response shapes are defined in /api/v1/openapi.json. The spec is validated in InboxOps’ release pipeline so it stays well-formed OpenAPI 3.x; the product always serves the spec that matches that release.
curl -sS "https://app.inboxops.app/api/v1/openapi.json" | head -c 400
const r = await fetch("https://app.inboxops.app/api/v1/openapi.json");
const spec = await r.json();
console.log(spec.info?.title, spec.openapi);
Versioning and deprecation
Today the contract is /api/v1. If we introduce breaking changes that cannot be carried as additive OpenAPI updates, we will ship a new path prefix (for example /api/v2) and publish:
- A minimum support window for
/api/v1after/api/v2is available. - Migration notes in this documentation and in the OpenAPI description.
Non-breaking additions (new optional fields, new endpoints) may land on /api/v1 without a version bump. Integrators should tolerate unknown JSON properties on responses.
Reporting and analytics
Reporting and analytics are not available through the public API. Metrics, dashboards, and compliance-style reports are in-app only for now. Automate ticket and customer data via the API; use the InboxOps UI for reporting.
Webhooks
Outbound webhook subscriptions and signing secrets are managed in the InboxOps UI, not via the public API. The API can trigger webhook deliveries when supported resources change (for example ticket updates), according to your workspace configuration.
Related
- Public API errors — RFC 7807
type/codereference - Home — documentation overview
Last updated 3 weeks ago
Built with Documentation.AI