logo
GuidePublic API

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:

ScopeEffect
Read and writeAll supported HTTP methods on /api/v1 (default for new keys).
Read onlyGET 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:

HTTPTypical code
400bad_request
401unauthorized — missing/invalid Authorization or revoked key
403forbidden — public API not enabled for the workspace
403insufficient_scope — read-only key used for a mutating method
404not_found
405method_not_allowed
409conflict — duplicate unique name (for example tag or company) in CRM
409idempotency_conflict — same Idempotency-Key reused with a different JSON body (see below)
429rate_limit_exceeded
500internal_error
503service_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 201 with 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 409 with code: 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:

  • TicketsGET by id, POST create, PATCH, and ticket.created / ticket.updated webhook payloads (when custom fields change, changed_fields includes custom_fields). The paginated GET /tickets list omits custom_fields for performance; fetch the ticket by id for values. Filtering the list: add query parameters custom_field_ + field_key (same key as in custom_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 return 400 (application/problem+json). Definitions scoped to selected mailboxes only match when the ticket’s inbox is linked to the definition (see OpenAPI GET /tickets).
  • ContactsGET /contacts/{id}, POST /contacts, PATCH /contacts/{id}.
  • CompaniesGET /companies/{id}, POST /companies, PATCH /companies/{id}.

Reading

  • Active definitions that apply to the entity are always present in custom_fields. Values are null, 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 400 with application/problem+json (typically code: 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 null or 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

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/v1 after /api/v2 is 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.