Skip to content

The integration API

For whoever is connecting a billing platform, a portal, or anything else clients sign in to.

This is how clients reach the desk as themselves without the desk holding their password. The platform they are already signed in to calls the desk on their behalf, scoped to one brand and one client.

The full endpoint-by-endpoint reference lives in docs/blesta-api.md; this page is the shape of it, and the decisions behind it.

The base

https://your-desk.example.com/api/v1/integration

(/api/v1/blesta remains as an alias for one release.)

JSON in and out, except creating a ticket or reply with files (multipart) and downloading an attachment (a file stream). Send Accept: application/json.

Authentication

A per-brand token, created in the desk under API keys, sent as a bearer token:

Authorization: Bearer <token>

The token belongs to one brand, can be rotated, can be given an expiry, and is limited to the routes on this page, calling any staff route with it answers 403.

It must never reach a browser. The platform’s server holds it and makes the calls.

What scopes a request

Every client route carries the client’s id in your system in the URL, and the desk resolves that to the client record for this brand. So a token cannot be used to read another customer’s tickets: the identifier is part of the path, and the brand is part of the token.

Responses carry only customer-safe data: no internal notes, no activity log, no AI summary, no staff email addresses, no database ids.

Identifiers

ThingIdentifier
ClientYour id for them, as a string (external_id)
TicketA 14-digit ticket number, random rather than sequential
Reply, attachmentA ULID
DepartmentAn integer id

Store the ULIDs if you need a stable reference to a reply or a file.

The usual flow

  1. PUT /clients/{external_id} with their current name and email when they open the support area. Creates the record the first time and keeps it in step afterwards.
  2. GET /departments for the selector, which also carries everything the form needs: the priorities this department offers with their warnings, its custom fields, whether guests are allowed, whether CC is allowed, the captcha configuration, and the file rules (what may be attached, how many, how large).
  3. GET /clients/{id}/tickets for the list, GET …/tickets/{number} for one thread.
  4. POST …/tickets to open, POST …/tickets/{number}/replies to reply, POST …/close to close.
  5. Offer a secure credentials form posting to …/tickets/{number}/secrets rather than letting people paste passwords into a reply.

Beyond tickets

The same signed API carries the rest of the desk’s client-facing surface, and a platform can use as much or as little as it likes:

Chat identityGET /chat?external_id= mints a short-lived token that makes a widget session verified, which is the only thing that attaches a chat to an account
AnnouncementsThe brand’s live notices for a placement, and dismissals
StatusThe public feed, so a platform can render its own status page
ReportsThe public bug and security intake, with its types and their custom fields
Knowledge suggestions“These might help” while somebody types a new ticket
RatingsThe satisfaction question and its answer, in the portal
SummaryCounts for a dashboard widget, for the client and for staff
Mass mail audiencesThe two lookups a platform answers so the desk can build lists from your data

Guests

A parallel set of endpoints for people with no account: list the departments that allow guests, open a ticket, follow it through a signed link, reply, close, download attachments. The link carries a token; no account is created.

Errors

Ordinary HTTP: 422 with a errors object for validation, 403 for a token used outside its scope, 404 for something that is not there or not this client’s, 429 with retry_after when a limit is hit.

Show the returned message to the customer: a refused attachment names exactly which kinds are accepted, and a rate limit says when to try again.

Limits

Rate limits per client and per address, and the brand’s own submission limits. Attachments are decided by the brand: GET /departments tells you the count, size and kinds allowed, and the desk enforces exactly what it advertises.

Building against it

  • Read the department payload rather than hard-coding. Priorities, custom fields, the captcha and the file rules all travel with it, and the desk’s answer is the truth.
  • Never match a client by email address. Pass your own id; the desk’s whole identity model depends on it.
  • Handle 429 properly. A retry storm during an outage is how a portal turns a bad morning into a worse one.

See Writing a platform adapter for the other direction: what the desk asks your system for.