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
| Thing | Identifier |
|---|---|
| Client | Your id for them, as a string (external_id) |
| Ticket | A 14-digit ticket number, random rather than sequential |
| Reply, attachment | A ULID |
| Department | An integer id |
Store the ULIDs if you need a stable reference to a reply or a file.
The usual flow
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.GET /departmentsfor 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).GET /clients/{id}/ticketsfor the list,GET …/tickets/{number}for one thread.POST …/ticketsto open,POST …/tickets/{number}/repliesto reply,POST …/closeto close.- Offer a secure credentials form posting to
…/tickets/{number}/secretsrather 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 identity | GET /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 |
| Announcements | The brand’s live notices for a placement, and dismissals |
| Status | The public feed, so a platform can render its own status page |
| Reports | The public bug and security intake, with its types and their custom fields |
| Knowledge suggestions | “These might help” while somebody types a new ticket |
| Ratings | The satisfaction question and its answer, in the portal |
| Summary | Counts for a dashboard widget, for the client and for staff |
| Mass mail audiences | The 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.