Skip to content

Quick start

This page assumes you already have a running FlowDesk installation. If you have not set one up yet, start with Installation → Requirements.

The examples below use https://api.example.com as the API address; replace it with your own installation’s. You get that address and your first user credentials from your FlowDesk administrator (the team that ran the installation).

Opening a request needs an API token; the JWT you get by signing in to the dashboard is not valid for it. Because the token is created from the dashboard, sign in there first. The Authentication page explains why these two credentials are separate.

This step depends on your installation’s authentication provider; find out which one is enabled from Configuration → Authentication or from the team that ran the installation.

If EmailPassword is enabled (it works as below): on a fresh installation the API creates the admin@shft.co user automatically on first boot, with a seeded password. That password is not published here; get it from the team that ran your installation. Change it immediately after the first sign-in.

Terminal window
curl -s -X POST https://api.example.com/v1/dashboard/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@shft.co",
"password": "<the-seeded-password-from-your-install-team>"
}'

If only Keycloak is enabled the endpoint above does not work: before a password-based sign-in the API checks that the EmailPassword provider is enabled, and rejects the request when it is not. Sign in from the dashboard instead, with a Keycloak realm user whose e-mail matches a FlowDesk user exactly; for details see Configuration → Authentication.

Expected response (200):

{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"accessTokenExpiresAt": "2026-08-13T10:15:00Z",
"refreshToken": "8f2c1a...",
"refreshTokenExpiresAt": "2026-08-20T10:00:00Z"
},
"error": null
}

You will use accessToken in the next step: for dashboard endpoints only, not for integration endpoints.

This step is done in the dashboard by an administrator (it needs the api-tokens:api-token-create:save permission). A token is bound to one or more pools, or to all of them (allPools: true): that scope decides which pools requests can be opened in with the token. Check your own installation’s pool ids in the dashboard (the Pools page); the 1 below is only an example.

Terminal window
curl -s -X POST https://api.example.com/v1/dashboard/api-tokens \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "First integration",
"scopes": ["tickets:read", "tickets:write"],
"poolIds": [1],
"allPools": false
}'

Expected response (201):

{
"success": true,
"data": { "id": 1, "token": "fd_ab12cd34ef...9f", "tokenPrefix": "fd_ab12c" },
"error": null
}

The token field appears in this response only. From then on the server stores only its hash; if you lose it, the only thing you can do is create a new token. Save the value to a secret manager now.

You can now call v1/integration/tickets with the API token:

Terminal window
curl -s -X POST https://api.example.com/v1/integration/tickets \
-H "Authorization: Bearer fd_ab12cd34ef...9f" \
-H "Content-Type: application/json" \
-d '{
"subject": "Test request",
"description": "The first request opened from the quick start guide.",
"priority": "High",
"requesterFullName": "Alex Morgan",
"requesterEmailAddress": "alex@example.com"
}'

The example above uses High for priority. For every value this field accepts and its validation rules, see Creating requests.

Expected response (202 Accepted):

{
"success": true,
"data": { "trackingKey": "TI1LL2-s20EICNKMwYbzr_jzpr_kzZN5bRjz8gdGYS8yZUsm6w6EScY9FKSjTxJV", "status": "queued" },
"error": null
}

trackingKey is not a human-readable format: it is a 64-character, URL-safe random string (it carries no FD-… style prefix and no predictable pattern). You cannot construct or guess one; use only the value the server returns.

This endpoint returns 202 immediately; pool assignment and the welcome e-mail run outside your request, in the background. The example above did not send a poolId, because the token you created in step 2 is bound to a single pool: in that case that one pool is assumed automatically. For the full pool-selection rules see the “Pool selection” section on Creating requests.

Send an Idempotency-Key header so you can safely retry after something like a network timeout: the same key with the same body does not open a second request, and returns the original response again.

Receiving a trackingKey does not mean the request was created: it means it was queued. Ask the endpoint below after a short delay (for example a 1s, 2s, 4s backoff):

Terminal window
curl -s https://api.example.com/v1/integration/tickets/by-tracking-key/TI1LL2-s20EICNKMwYbzr_jzpr_kzZN5bRjz8gdGYS8yZUsm6w6EScY9FKSjTxJV \
-H "Authorization: Bearer fd_ab12cd34ef...9f"

If the request has not been created yet this endpoint returns 404: that is not an error, it is the expected first state. Once the request exists, the same endpoint returns 200 with the request’s full body.

  • The full reference for every integration endpoint (listing, filtering, rate limits, error codes): API Reference
  • Opening requests automatically from incoming e-mail: E-mail settings
  • Setting up your own installation from scratch: Installation