API publique

L’API publique de Tikivio relie vos propres outils à votre espace d’assistance : lire, créer et mettre à jour des demandes, y répondre, retrouver vos demandeurs et vos agents, et recevoir des avis signés quand une demande change.

1. Créer une clé

Un administrateur de l’organisation crée la clé dans Paramètres › API (/o/<votre-organisation>/parametres/api) et choisit ses droits :

DroitCe qu’il permet
tickets:readvoir les demandes, leurs messages et la liste des agents
tickets:writecréer des demandes, changer leur statut, leur priorité ou leur responsable, et écrire des messages
contacts:readvoir les demandeurs (nom et adresse e-mail)
contacts:writeajouter des demandeurs

La clé n’est affichée qu’une fois : rangez-la dans les secrets de votre serveur, jamais dans une page web ni dans une application que vous distribuez. Elle agit au nom de l’administrateur qui l’a créée, avec au plus les droits que cette personne a encore. Elle se révoque à tout moment depuis le même écran, qui montre aussi les derniers appels reçus.

2. Premier appel

curl -s "https://app.tikivio.com/api/v1/tickets?limit=10" \
  -H "Authorization: Bearer $TIKIVIO_API_KEY"

Toutes les adresses commencent par https://app.tikivio.com/api/v1. Les échanges se font en JSON (UTF-8) ; les dates sont en UTC, au format 2026-11-02T08:30:00Z. La description complète de l’API, au format OpenAPI 3.1, est publique, à l’adresse https://app.tikivio.com/api/v1/openapi.json. Elle s’importe dans Postman, Insomnia ou un générateur de code.

3. Ce que permet l’API

AppelRôleDroit
GET /ticketsliste des demandes, les plus récentes d’abord ; filtres status (valeurs séparées par des virgules) et updated_sincetickets:read
POST /ticketscréer une demandetickets:write
GET /tickets/{référence}une demande, par sa référence (par exemple TIKI-000123)tickets:read
PATCH /tickets/{référence}changer le statut, la priorité ou le responsabletickets:write
GET /tickets/{référence}/messagesles messages d’une demandetickets:read
POST /tickets/{référence}/messagesajouter une réponse publique ou une note internetickets:write
GET /contactsles demandeurs ; filtre emailcontacts:read
POST /contactsajouter un demandeur, ou retrouver celui qui a déjà cette adressecontacts:write
GET /contacts/{id}un demandeurcontacts:read
GET /agentsles agents actifs, pour affecter une demandetickets:read
GET /organisationle nom de l’organisation de la clé et email_replies (voir « Créer une demande »)toute clé

Les listes rendent data et next_cursor : passez cursor=<next_cursor> pour la page suivante ; next_cursor vaut null à la dernière page. limit va de 1 à 200 (50 par défaut).

4. Créer une demande

curl -s -X POST "https://app.tikivio.com/api/v1/tickets" \
  -H "Authorization: Bearer $TIKIVIO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: commande-4521-retour" \
  -d '{"requester_email":"camille@exemple.fr","requester_name":"Camille Martin",
       "subject":"Retour de la commande 4521","body":"Bonjour, le colis est arrivé abîmé.",
       "priority":"normal"}'

Champs obligatoires : requester_email, subject et body (texte brut, 1 Mo au plus) ; priority vaut low, normal, high ou urgent. La réponse 201 rend la demande créée, avec sa référence, et email_replies : "available" si l’organisation a une boîte e-mail dont l’envoi est actif, "unavailable" sinon. Avec "unavailable", n’annoncez pas au demandeur qu’il recevra la réponse par e-mail. Pour le savoir avant de créer une demande, appelez GET /organisation, qui rend seulement name et email_replies.

Avec l’en-tête Idempotency-Key (1 à 255 caractères ASCII), un même envoi répété dans les 24 heures rend la même réponse sans créer de doublon (en-tête Idempotent-Replayed: true) ; la même clé avec un autre contenu est refusée (422).

5. Répondre et mettre à jour

curl -s -X POST "https://app.tikivio.com/api/v1/tickets/TIKI-000123/messages" \
  -H "Authorization: Bearer $TIKIVIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body":"Nous vous envoyons un nouveau colis aujourd’hui.","internal":false}'

curl -s -X PATCH "https://app.tikivio.com/api/v1/tickets/TIKI-000123" \
  -H "Authorization: Bearer $TIKIVIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"pending_requester","reason":"Nouveau colis envoyé"}'

Avec "internal": true, le message devient une note interne, jamais visible du demandeur. Statuts : new, open, pending_requester, pending_internal, resolved, closed. Pour affecter une demande, envoyez assignee_id (identifiant agt_… donné par GET /agents), ou null pour la retirer ; le motif facultatif reason est gardé dans l’historique.

6. Erreurs et plafond d’appels

Les erreurs suivent la norme RFC 9457 (application/problem+json, avec type, title, status et detail) :

  • 401 : clé absente ou invalide ;
  • 403 : droit manquant, ou organisation qui n’a pas accès à l’API ;
  • 404 : demande ou demandeur introuvable ;
  • 409 : la même requête est encore en cours ;
  • 422 : contenu refusé (champ manquant ou invalide) ;
  • 423 : organisation en lecture seule ;
  • 429 : trop d’appels.

Chaque clé a un plafond d’appels par minute. Les en-têtes RateLimit-Limit, RateLimit-Remaining et RateLimit-Reset l’indiquent à chaque réponse ; après un 429, attendez le délai donné par Retry-After. Les essais répétés de clés invalides depuis une même source sont bloqués un moment.

7. Avis d’événements (webhooks)

Dans le même écran, abonnez une adresse HTTPS de votre serveur à un ou plusieurs événements (10 abonnements actifs au plus) :

  • ticket.created : une nouvelle demande arrive, d’où qu’elle vienne (e-mail, widget, portail, agent ou API) ;
  • ticket.updated : le statut, la priorité, le responsable ou l’équipe d’une demande change ;
  • ticket.message_created : un nouveau message (réponse d’un agent, note interne ou réponse du demandeur).

Tikivio envoie un POST en JSON : id (evt_…, le même à chaque nouvel essai), type, created_at et data.ticket, l’état de la demande au moment de l’envoi. Répondez par un code 2xx en moins de 10 secondes ; sinon Tikivio réessaie 1 min, 5 min, 30 min, 2 h, 6 h puis 15 h plus tard, puis abandonne. Une adresse privée ou interne est refusée. Les derniers envois sont visibles dans l’écran.

Chaque envoi porte l’en-tête X-Signature: t=<horodatage>,v1=<signature> : la signature est le HMAC-SHA256, en hexadécimal, de <t>.<corps brut> avec le secret de l’abonnement (whsec_…, affiché une seule fois). Vérifiez-la avant tout traitement :

$corps = file_get_contents('php://input');
$parts = [];
foreach (explode(',', $_SERVER['HTTP_X_SIGNATURE'] ?? '') as $p) {
    [$k, $v] = array_pad(explode('=', $p, 2), 2, '');
    $parts[$k] = $v;
}
$t = $parts['t'] ?? '';
$attendu = hash_hmac('sha256', $t . '.' . $corps, $secret);
if (!hash_equals($attendu, $parts['v1'] ?? '') || abs(time() - (int) $t) > 300) {
    http_response_code(400);
    exit;
}

Un même événement peut arriver deux fois : gardez les id déjà traités.

8. Bon à savoir

  • Une action faite par l’API apparaît dans l’historique de la demande sous le nom de l’administrateur qui a créé la clé, avec la mention « par l’API ».
  • Rien ne se supprime par l’API dans cette version.
  • La version 1 ne reçoit que des ajouts compatibles (nouveaux champs, nouveaux appels) : ignorez les champs que vous ne connaissez pas.
  • Les demandes sont désignées par leur référence ; les autres objets par des identifiants opaques (ctc_…, agt_…), à garder tels quels.

Installer le widget · Sécurité et données : mode d’emploi