Capturia mesure ses publicités et la fréquentation du site avec le pixel Meta et Google Analytics. Tu peux refuser en tout temps. En savoir plus

EN

Journal des changements

Historique des changements de l'API Capturia v1, daté et catégorisé.

  1. Ajoutév1

    La référence de l'API et le spec OpenAPI existent en anglais

    Les pages de référence en anglais (/en/developers/api/v1/reference) décrivent chaque endpoint, paramètre, schéma et réponse en anglais, recherche de la doc comprise. Le spec anglais est publié à côté du spec français : /openapi.en.yaml, /openapi.en.json et la collection Postman /postman-collection.en.json. Le contrat ne change pas : mêmes chemins, mêmes champs, mêmes valeurs ; seuls les textes descriptifs sont traduits. La collection Postman française (/postman-collection.json) est maintenant servie sur api.capturia.io, comme le spec.

  2. Modifiév1

    Connecteur pour assistants IA : get_todays_bookings dit qui a pris et annulé chaque rendez-vous (changement non rétrocompatible)

    Changement non rétrocompatible du connecteur MCP. get_todays_bookings accepte range (today par défaut, upcoming pour les prochains, recent pour les plus récents, annulations comprises) et contact_id (les rendez-vous d'une fiche, recent par défaut). Chaque rendez-vous porte origin (qui l'a pris), cancel_origin et cancelled_at (qui l'a annulé, et quand), meeting_type, et sous untrusted_user_content le type de rendez-vous, l'hôte et les noms de qui l'a pris ou annulé. Le champ source n'est plus retourné : il nommait « automation » un rendez-vous pris par l'agent dans la conversation, et origin le remplace. date vaut null hors de range: today. L'outil suit maintenant le forfait comme l'écran des rendez-vous : un compte dont le forfait n'inclut pas le module Rendez-vous et calendriers reçoit un refus qui renvoie à « Mon forfait », et une lecture du forfait en panne est à retenter. Le résultat reste borné à 20 rendez-vous, avec total_count et has_more. search_contacts, get_pipeline_summary et get_todays_bookings publient aussi leur schéma de sortie (outputSchema).

  3. Modifiév1

    Étapes du pipeline : chaque étape nomme son pipeline, les étapes masquées sont marquées, les fiches archivées ne comptent plus

    GET /v1/pipeline/stages rend désormais les étapes de tous les pipelines du compte avec leur pipeline : pipeline_id et pipeline (id, name, is_default). Un compte à deux pipelines peut avoir deux étapes du même nom ; le pipeline les distingue. Les étapes sont triées par pipeline, dans l'ordre du tableau de bord, puis par stage_order. Une étape masquée sur le pipeline du tableau de bord reste listée, avec is_hidden: true : ses contacts existent et comptent. contact_count ne compte plus les contacts archivés ni fusionnés, comme l'écran Pipeline. Un drapeau d'étape absent (is_default, is_won, is_lost) se lit maintenant false au lieu de null. Le connecteur MCP (get_pipeline_summary) rend les mêmes champs.

  4. Modifiév1

    Webhooks : l'auteur d'un événement dit s'il vient d'un assistant IA ou de l'API, et n'invente plus de membre

    Le champ data.actor des événements gagne via : ai_assistant quand le geste vient d'un assistant IA branché au connecteur (Claude, ChatGPT), api_key quand il vient de l'API publique, null sinon. Quand aucun membre n'a agi (système, automatisation, intégration), type et id valent désormais null ; ils annonçaient auparavant un membre de l'équipe sans identifiant. Une écriture faite par une clé API est nommée par sa clé dans name (par exemple Clé API « Zapier », ou Assistant IA — clé API « Zapier » quand la clé passe par le connecteur), jamais Système.

  5. Modifiév1

    POST /v1/contacts : courriel ou téléphone, jamais une deuxième fiche, aucun consentement implicite

    Un contact se crée désormais avec un courriel ou un téléphone : l'un des deux suffit. Le courriel est enregistré en minuscules, et la personne est cherchée parmi toutes les identités du compte (courriels et téléphones principaux et secondaires, sans égard à la casse). Une personne déjà connue retourne 409 duplicate_contact avec la fiche existante dans data et les champs concernés dans details.conflicting_fields, que la correspondance vienne du courriel ou du téléphone ; un courriel et un téléphone portés par deux fiches différentes retournent 409 duplicate_resource. Le contact créé porte la source api, et aucun consentement implicite (texto ou courriel) ne lui est plus inscrit : une intégration ne nomme personne qui aurait rencontré ce contact. Pour un lead qui vient de remplir ton formulaire, avec son consentement, utilise POST /v1/leads/capture.

  6. Modifiév1

    DELETE /v1/contacts/{id} exige le scope contacts:delete

    Supprimer un contact exige maintenant le scope contacts:delete, distinct de contacts:write, comme dans le tableau de bord où la suppression est une permission à part. Seule une personne qui peut supprimer des prospects dans Capturia peut accorder ce scope à une clé ; il n'est inclus que dans le preset Intégration complète. Une clé qui n'a que contacts:write reçoit 403 insufficient_scope sur cette route.

  7. Modifiév1

    /v1/bookings sert l'agenda de ton compte (changement non rétrocompatible)

    Changement non rétrocompatible. Les routes /v1/bookings servent désormais l'agenda de ton compte : les rendez-vous que ton équipe tient sur tes calendriers (page de réservation, tableau de bord, agents IA, automatisations). Elles lisaient et écrivaient auparavant les rencontres de tes projets de livraison avec Capturia.

    GET /v1/bookings liste les rendez-vous de l'agenda (archivés exclus). Le filtre project_id disparaît ; event_type_id et contact_id s'ajoutent à from, to et status (confirmed, cancelled, completed, no_show). Un filtre illisible est refusé en 400 validation_error. Chaque rendez-vous porte event_type_id, contact_id, host_id et meeting_link ; project_id, assigned_to_id, video_provider et zoom_join_url ne sont plus retournés.

    POST /v1/bookings réserve par le même service que ta page de réservation, avec les règles du calendrier (hôtes, heures, fenêtre de réservation, agenda Google de l'hôte, questions requises, un seul rendez-vous à venir par fiche et par calendrier). Le corps exige event_type_id (un calendrier de ton compte) et start_datetime, plus contact_id ou guest_name + guest_email. Facultatifs : guest_phone, host_id, timezone, notes, form_responses (une entrée par identifiant de question, de la forme { value } ; un refus de formulaire liste les questions du calendrier dans details.questions). project_id n'existe plus, et end_datetime est refusé : la durée est celle du calendrier. L'heure demandée est tenue ou refusée avec sa raison dans details.reason, jamais remplacée : 400 validation_error (slot_in_past, outside_window, off_cadence, contact_or_guest_required, contact_without_email), 404 resource_not_found (details.field : event_type_id, contact_id, host_id), 409 duplicate_resource (already_booked), 422 business_rule_violation (calendar_without_hosts, host_not_on_calendar, host_unavailable, slot_unavailable, contact_archived, lead_not_qualified), 503 service_unavailable (réessaie après Retry-After).

    DELETE /v1/bookings/{id} annule comme au tableau de bord : l'événement est retiré de l'agenda de l'hôte, qui est avisé. Un rendez-vous déjà annulé répond maintenant 422 business_rule_violation (already_cancelled) au lieu de 409 already_cancelled ; un rendez-vous tenu ou marqué absent, 422 (booking_not_cancellable). Un rendez-vous introuvable répond 404 resource_not_found.

    Le connecteur pour assistants IA suit le même changement : get_todays_bookings lit l'agenda du compte, et book_meeting y réserve (start_datetime, puis contact_id ou guest_name + guest_email, event_type_id et form_responses facultatifs ; project_id et end_datetime ne sont plus acceptés). Le connecteur n'annule jamais un rendez-vous.

  8. Ajoutév1

    GET /v1/usage : nouveau compteur status_unknown

    Chaque bucket et les totaux de GET /v1/usage portent désormais status_unknown : le nombre de requêtes dont l'issue n'a pas été enregistrée. C'est le cas d'une réponse encore en cours au moment de l'agrégation (le bucket horaire courant est recalculé toutes les quelques minutes, et la requête y reprend alors son issue réelle), ou d'une issue dont l'enregistrement a échoué. Ces requêtes ne sont ni des succès ni des erreurs : exclus-les de tout calcul de taux d'erreur. Les familles status_2xx, status_4xx, status_5xx, rate_limited_count et status_unknown sont disjointes : une requête n'est jamais comptée dans deux d'entre elles.

  9. Modifiév1

    GET /v1/usage : status_2xx ne compte plus que les succès confirmés

    Jusqu'ici, une requête dont l'issue n'avait jamais été enregistrée pouvait être comptée comme un succès. Elle est maintenant comptée dans status_unknown. Les buckets historiques concernés sont corrigés une fois : leur status_2xx baisse d'autant, et status_unknown reprend l'écart. Les refus de la limite par adresse IP de /v1/events et /v1/leads/capture passent aussi de status_4xx à rate_limited_count, comme les refus du quota horaire de la clé : un refus d'un limiteur de débit est toujours dans rate_limited_count et ne consomme pas le quota. Un refus métier en 429 (déclencheur appelé trop souvent, quota d'envois de test, plafond d'abonnements webhook) reste une erreur status_4xx et consomme le quota. Enfin, la référence disait à tort que rate_limited_count était un sous-ensemble de status_4xx : les deux familles ont toujours été distinctes, cette correction de la documentation ne change aucun calcul.

  10. Modifiév1

    GET /v1/conversations/{id}/messages : content ne contient plus les marqueurs de pilotage internes

    Les agents IA rythment leurs réponses avec des marqueurs internes ([PAUSE:3s] pour envoyer en plusieurs bulles, [INPUT:email] pour demander un champ au visiteur). Ils n'ont jamais fait partie du contrat et se retrouvaient pourtant dans le champ content. Ils en sont retirés : une réponse envoyée en plusieurs bulles t'arrive maintenant en paragraphes séparés par une ligne vide. Ce changement s'applique aussi aux messages déjà en base, donc la valeur de content change une fois pour les messages d'agent existants. Conséquence à connaître : un message qui ne portait QUE du pilotage devient une chaîne vide. La ligne reste présente dans la page, avec ses id, role et created_at, pour ne pas fausser total_count, has_more ni le curseur de pagination. Si ton intégration teste la présence d'un message avec if (!content), ajuste-la pour tester la présence de l'objet.

  11. Ajoutév1

    Sous-domaine dédié api.capturia.io + sunset legacy 2027-05-03

    L'API publique est désormais servie sur https://api.capturia.io/v1/* (convention enterprise alignée Stripe/Twilio/GitHub). Bundle OpenAPI auto-discoverable à api.capturia.io/openapi.{yaml,json}. L'ancien host app.capturia.io/api/v1/* reste actif jusqu'au 2027-05-03 ; chaque réponse legacy porte les headers IETF Deprecation, Sunset et Link successor-version. Au sunset, le legacy bascule en HTTP 308 Permanent Redirect vers le nouveau host. Pas de 410 Gone — tes intégrations continueront à fonctionner même si tu oublies de migrer (avec un round-trip d'overhead).

  12. Ajoutév1

    Spec OpenAPI 3.1 publique + Postman + types TS

    L'API expose désormais une spec OpenAPI 3.1 servable à /openapi.yaml (235KB) et /openapi.json (289KB). Collection Postman (/postman-collection.json) téléchargeable, importable dans Insomnia 2023+ via la spec OpenAPI directement. Types TypeScript générés au build (lib/api/v1/openapi-types.ts). Validation requêtes contre la spec en mode shadow par défaut.

  13. Ajoutév1

    Endpoint GET /v1/usage + observability headers

    Endpoint programmatique /v1/usage retourne les aggregations consommation (filtrables par bucket_type et range). Chaque réponse émet désormais X-Request-ID ULID, Capturia-Request-ID (alias), Capturia-Version: v1, et Vary: Accept-Language, Accept-Encoding.

  14. Ajoutév1

    Pagination cursor opaque + headers Deprecation/Sunset legacy

    Tous les GET collection acceptent désormais ?cursor= opaque base64url avec tiebreaker id pour tri stable. Format legacy total_count + cursor ISO accepté en parallèle 12 mois (sunset 2027-05-03). Headers Deprecation (RFC 9745) + Sunset (RFC 8594) + Link rel=deprecation annoncent le retrait.

  15. Ajoutév1

    Header Idempotency-Key sur POST/PUT/DELETE

    Toutes les routes mutantes acceptent un header optionnel Idempotency-Key (regex [a-zA-Z0-9_-]{1,64}). TTL 24h via Vercel KV. Replay verbatim retourne Idempotent-Replayed: true. Conflit (payload différent ou requête concurrente) → 409 idempotency_conflict.

  16. Ajoutév1

    Headers RFC 9331 + body 429 enrichi

    Émission parallèle des headers RateLimit-Limit/Remaining/Reset/Policy (RFC 9331) et X-RateLimit-* (legacy, sunset 2027-05-03). Body 429 inclut désormais details.limit_type (per_key ou brute_force) et details.retry_after_seconds actionnable.