API Klarodesk

L’API permet à vos propres systèmes (CRM, ERP, intranet, scripts, Zapier, n8n, Make…) de lire et de modifier les données de VOTRE espace Klarodesk : tickets, contacts, base de connaissances et référentiels. Elle utilise OAuth2 (flux client credentials, RFC 6749 §4.4) : chaque application a ses propres identifiants, des droits limités, et peut être coupée à tout moment.

Disponible à partir du forfait Team (et pendant l’essai gratuit).

Démarrage en 3 étapes

  1. Dans Klarodesk, ouvrez Paramètres › API, puis « Nouveau client API ». Choisissez les droits, l’utilisateur au nom duquel l’application agit et, si possible, les adresses IP de vos serveurs.
  2. Copiez le client_id et le client_secret (affiché une seule fois) dans le coffre de secrets de votre application.
  3. Demandez un jeton, puis appelez l’API avec ce jeton :
# 1. Jeton d’accès
curl -X POST https://app.klarodesk.com/api/oauth/token \
  -u "$KLARODESK_CLIENT_ID:$KLARODESK_CLIENT_SECRET" \
  -d grant_type=client_credentials

# {"access_token":"kd_at_…","token_type":"Bearer","expires_in":3600,"scope":"tickets:read tickets:write"}

# 2. Appel de l’API
curl https://app.klarodesk.com/api/v1/tickets?limit=20 \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Authentification

Un jeton d’accès est valable 60 minutes. Redemandez-en un quand il expire (réponse 401) : il n’y a pas de jeton de rafraîchissement dans ce flux. Le jeton s’envoie dans l’en-tête Authorization: Bearer.

Avec un secret client

Envoyez client_id et client_secret en HTTP Basic (recommandé) ou dans le corps du formulaire (client_id, client_secret). Une seule méthode par requête.

Avec une clé publique (private_key_jwt, le plus sûr)

Aucun secret ne circule : vous enregistrez une clé PUBLIQUE (JWK, RS256 / ES256 / EdDSA) dans Klarodesk et votre application signe, à chaque demande de jeton, une assertion courte (RFC 7523) avec sa clé privée. L’assertion doit contenir iss = sub = client_id, aud = l’adresse des jetons, exp au plus 5 minutes plus tard et un jti unique (une assertion ne sert qu’une fois).

// Node.js 20+ — private_key_jwt (ES256)
import { SignJWT, importJWK } from "jose";
import { randomUUID } from "node:crypto";

const key = await importJWK(JSON.parse(process.env.KLARODESK_PRIVATE_JWK), "ES256");
const assertion = await new SignJWT({})
  .setProtectedHeader({ alg: "ES256" })
  .setIssuer(process.env.KLARODESK_CLIENT_ID)
  .setSubject(process.env.KLARODESK_CLIENT_ID)
  .setAudience("https://app.klarodesk.com/api/oauth/token")
  .setExpirationTime("2m")
  .setJti(randomUUID())
  .sign(key);

const res = await fetch("https://app.klarodesk.com/api/oauth/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "client_credentials",
    client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
    client_assertion: assertion,
  }),
});
const { access_token } = await res.json();

Le paramètre facultatif scope (droits séparés par des espaces) restreint le jeton à une partie des droits du client.

Droits (scopes)

  • tickets:read — Lire les tickets, leurs messages et pièces jointes
  • tickets:write — Créer des tickets, répondre, notes internes, statut, priorité, catégorie, tags, champs, assignation
  • contacts:read — Lire les fiches des demandeurs
  • contacts:write — Modifier les fiches des demandeurs
  • kb:read — Lire la base de connaissances (utilisateur administrateur requis)
  • kb:write — Ajouter, modifier, supprimer des articles (utilisateur administrateur requis)
  • settings:read — Lire catégories, tags et champs, statuts, équipes, utilisateurs

Au nom de qui agit l’application ?

Chaque client agit au nom d’un agent ou d’un administrateur que vous choisissez : les réponses et modifications apparaissent à son nom, avec SES droits (un agent ne peut pas toucher la base de connaissances). Désactiver cet utilisateur coupe immédiatement l’application.

Points d’accès

Adresse de base : https://app.klarodesk.com/api/v1. Corps des requêtes en JSON (Content-Type: application/json), 5 Mo au plus. Les champs acceptés sont ceux de l’interface Klarodesk (mêmes validations).

MéthodeCheminDroitDescription
GET/ticketstickets:readListe des tickets (?viewId, ?source, ?tag, ?page, ?limit ≤ 100)
GET/tickets/{id}tickets:readTicket et ses messages
GET/tickets/{id}/attachments/{attachmentId}tickets:readPièce jointe (redirection vers un lien signé d’1 h)
POST/ticketstickets:writeCréer un ticket
POST/tickets/{id}/replytickets:writeRépondre au client ou ajouter une note interne
PUT/tickets/{id}/statustickets:writeChanger le statut
PUT/tickets/{id}/prioritytickets:writeChanger la priorité
PUT/tickets/{id}/categorytickets:writeChanger la catégorie
PUT/tickets/{id}/tagstickets:writeRemplacer les tags
PUT/tickets/{id}/custom-fieldstickets:writeRenseigner des champs personnalisés
POST/tickets/{id}/assigntickets:writeAssigner (ou retirer l’assignation)
GET/contactscontacts:readListe des contacts (?search, ?page, ?limit)
GET/contacts/{id}contacts:readFiche d’un contact
PATCH/contacts/{id}contacts:writeModifier une fiche contact
GET/kb/articleskb:readArticles de la base de connaissances
GET/kb/articles/{id}kb:readTexte complet d’un article
POST/kb/articleskb:writeAjouter un article (indexé pour l’IA)
PUT/kb/articles/{id}kb:writeModifier un article
DELETE/kb/articles/{id}kb:writeSupprimer un article
GET/categoriessettings:readCatégories de tickets
GET/ticket-fieldssettings:readTags et champs personnalisés
GET/ticket-statusessettings:readStatuts personnalisés
GET/teamssettings:readÉquipes
GET/userssettings:readUtilisateurs (administrateur requis)

Exemples

# Créer un ticket
curl -X POST https://app.klarodesk.com/api/v1/tickets \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -d '{"requesterEmail":"[email protected]","requesterName":"Rina","subject":"Commande 1042 non reçue","description":"Ma commande 1042 n’est pas arrivée.","priority":"high","processWithAI":true}'

# Répondre (note interne)
curl -X POST https://app.klarodesk.com/api/v1/tickets/$TICKET_ID/reply \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -d '{"body":"Colis retrouvé, livraison demain.","isInternal":true}'

# Résoudre
curl -X PUT https://app.klarodesk.com/api/v1/tickets/$TICKET_ID/status \
  -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" \
  -d '{"status":"resolved"}'

Erreurs

  • 400 — Requête invalide (détail dans error / details)
  • 401 — Jeton absent, expiré ou révoqué : redemandez un jeton
  • 403 — insufficient_scope (droit manquant), api_unavailable (forfait sans API, compte suspendu) ou droits de l’utilisateur insuffisants
  • 404 — Ressource ou point d’accès inconnu (jamais une donnée d’un autre espace)
  • 415 — Corps non JSON
  • 429 — Plus de 300 requêtes par minute pour ce client (en-tête Retry-After)

L’adresse des jetons répond selon OAuth2 : invalid_client (401, identifiants refusés — toujours la même réponse, quelle que soit la raison), invalid_scope, unsupported_grant_type, invalid_request (400). 20 échecs en 15 minutes depuis un même réseau bloquent ce client depuis ce réseau pendant 15 minutes (vos autres serveurs ne sont pas touchés).

Bonnes pratiques de sécurité

  • N’utilisez l’API que depuis un serveur : jamais dans une page web, une application mobile ou du code partagé (le secret y serait lisible).
  • Indiquez les adresses IP de vos serveurs : un jeton ou un secret volé ne sert alors à rien ailleurs (l’adresse est revérifiée à chaque appel).
  • N’accordez que les droits nécessaires, un client par application.
  • Renouvelez le secret régulièrement (Paramètres › API › Nouveau secret) : l’ancien reste valable 24 h, ou est coupé tout de suite en cas de fuite.
  • Pour les intégrations sensibles, préférez la clé publique (private_key_jwt) : aucun secret à protéger côté Klarodesk.
  • Chaque création, modification ou échec d’authentification apparaît dans le journal d’audit ; tous les administrateurs reçoivent un e-mail à la création d’un client.
  • Révoquez un jeton qui n’est plus utile : POST /api/oauth/revoke (RFC 7009) avec les mêmes identifiants et token=<jeton>.