Skip to content

Référence de l'API ​

Base : https://app.durum.ai/api/v1/ Authentification : en-tête Authorization: Bearer durum_sk_live_… (voir Authentification).

Conventions ​

  • Lecture : méthode GET, paramètres dans la chaîne de requête. from et to sont des dates YYYY-MM-DD, optionnelles sauf mention contraire. Sans période, la route applique sa propre fenêtre par défaut.
  • Écriture : méthode PUT ou POST selon la route, corps JSON avec Content-Type: application/json. Chaque écriture exige un scope write:*.
  • Réponse : 200 avec { "data": … }. Toute erreur renvoie { "error": "…" } avec le code HTTP correspondant. Les réponses portent Cache-Control: private, no-store.
  • Vos données seulement : le compte est déduit de la clé. Aucun paramètre ne permet d'en désigner un autre.
  • Champs retirés : voir Champs jamais renvoyés.

Index auto-documenté

GET https://app.durum.ai/api/v1 (avec ou sans barre oblique finale) renvoie sans authentification la liste des routes de lecture et d'écriture avec leur méthode, leur scope et leur chemin complet (/api/v1/dashboard/kpis), ainsi que base_url et le lien vers cette page.

GET https://app.durum.ai/api/v1/tools (clé requise) renvoie un manifeste JSON (tools[] avec name, method, path, scope, inputSchema) limité aux routes couvertes par les scopes de votre clé. Il ne recense pas toutes les routes (les routes d'appels et de créatifs en sont absentes) : l'index ci-dessus reste la liste de référence.

Dashboard ​

RouteScopeParamètres
GET /dashboard/kpisread:dashboardfrom, to
GET /dashboard/dailyread:dashboardfrom, to
GET /dashboard/breakdownsread:dashboardfrom, to, dim (défaut source ; valeurs source, campaign, product, rep)

Réponses :

  • kpis : un objet de KPI agrégés sur la période (notamment leads, applications, bookings, meetings, shows, no_shows, total_sales, revenue, ticket_moyen).
  • daily : un tableau, une ligne par jour : report_date, leads, applications, bookings, meetings, no_shows, sales, revenue, spend.
  • breakdowns : un tableau, une ligne par valeur de la dimension : dimension_key, leads, applications, bookings, shows, no_shows, sales, revenue.
bash
curl "https://app.durum.ai/api/v1/dashboard/breakdowns?from=2026-08-01&to=2026-08-31&dim=campaign" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Publicités ​

RouteScopeParamètres
GET /ads/spendread:adsfrom, to
GET /ads/campaignsread:adsfrom, to
GET /ads/rulesread:adsaucun
GET /ads/rules/runsread:adsrule_id, limit (entier, défaut 30, max 100)

Réponses :

  • spend : un tableau, une ligne par annonce et par plateforme : ad_id, ad_name, campaign_name, campaign_id, adset_name, adset_id, platform, total_spend, total_clicks, total_impressions, total_reach.
  • campaigns : un tableau, une ligne par campagne et par plateforme, trié par dépense décroissante : campaign_id, campaign_name, platform, total_spend, total_clicks, total_impressions, total_reach, nb_ads, nb_adsets.
  • rules : vos règles d'ads automatisées (libellé, type, campagne, état activé, mode simulation, paramètres, dernière exécution).
  • rules/runs : les dernières exécutions d'une règle.
bash
curl "https://app.durum.ai/api/v1/ads/rules/runs?rule_id=ID_DE_LA_REGLE&limit=10" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Attribution ​

RouteScopeParamètres
GET /attributionread:attributionfrom, to
GET /attribution/healthread:attributionaucun
GET /attribution/reportread:attributionfrom, to

Réponses :

  • attribution : un tableau, une ligne par annonce. Les colonnes sont préfixées out_ : identité (out_ad_id, out_ad_name, out_campaign_id, out_campaign_name, out_adset_id, out_adset_name, out_platform), média (out_total_spend, out_total_clicks, out_total_impressions, out_total_reach), résultats (out_leads, out_applications, out_bookings, out_meetings, out_meetings_present, out_meetings_no_show, out_sales, out_revenue, out_show_rate, out_close_rate, out_rep_names), répartition par modèle (out_sales_ft et out_revenue_ft premier contact, out_sales_lt et out_revenue_lt dernier contact, out_sales_assisted et out_revenue_assisted), ajustements (out_refund_amount, out_dispute_amount, out_net_revenue) et out_is_excluded.
  • health : un objet de santé de capture : verdict, events_pub_30j, pct_exact_id, pct_par_nom, pct_non_resolu, pixel_sessions_30j, pixel_derniere_activite, pixel_pct_avec_id, issues.
  • report : un tableau par source, campagne et annonce : out_source, out_campaign, out_ad_id, out_ad_name, out_spend, out_gross_revenue, out_refund_amount, out_dispute_amount, out_net_revenue, out_roi_gross, out_roi_net, out_touchpoints.
bash
curl "https://app.durum.ai/api/v1/attribution?from=2026-08-01&to=2026-08-31" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Événements ​

RouteScopeParamètres
GET /eventsread:eventstype, from, to, limit (entier, défaut 50, max 200), cursor, rep
GET /events/summaryread:eventsfrom, to

type accepte lead, application, booking, no_show, sale, cancel, payment, sale_lost. Sans type, tous les événements sont renvoyés. sale regroupe les ventes et les paiements ; application inclut les candidatures qualifiées ; booking inclut les RDV marketing et de suivi. rep filtre sur le nom du rep assigné.

events renvoie un tableau du plus récent au plus ancien, une ligne par événement : id, event_type, event_datetime, contact_email, contact_name, contact_phone, contact_id, value, amount, product_key, product_name, assigned_user_name, is_paid, payment_status, booking_date, booking_time, utm_source, utm_campaign, utm_content, campaign_name, calendar_name, meta_ad_id, is_baseline, cancelled_at, has_more, counted, drop_reason, group_key, contact_seq.

Pagination par curseur : has_more vaut true sur les lignes quand une page suivante existe. Pour l'obtenir, rappelez la route avec cursor égal au event_datetime de la dernière ligne reçue (horodatage ISO 8601) : la page suivante ne contient que les événements strictement antérieurs.

events/summary renvoie un tableau par annonce et campagne : ad_name, campaign_name, leads, applications, bookings, sales, no_shows, cancellations, total_value.

bash
curl "https://app.durum.ai/api/v1/events?type=sale&from=2026-08-01&to=2026-08-31&limit=100" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

# page suivante
curl "https://app.durum.ai/api/v1/events?type=sale&from=2026-08-01&to=2026-08-31&limit=100&cursor=2026-08-14T15:02:11Z" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Ventes et finance ​

RouteScopeParamètres
GET /sales/summaryread:salesfrom, to
GET /sales/repsread:salesfrom, to
GET /sales/cycleread:salesfrom, to
GET /finance/pnlread:financefrom, to

Réponses :

  • sales/summary : un objet (KPI commerciaux, pipeline, no-show).
  • sales/reps : un tableau, une ligne par rep : rep_name, bookings, meetings, shows, no_shows, sales, revenue, close_rate, no_show_rate, ticket_moyen, contacts_met, contacts_closed.
  • sales/cycle : un objet : avg_days, median_days, p25_days, p75_days, sample_size, conversions, weekly_trend.
  • finance/pnl : un objet de P&L. En plus de la liste globale des champs jamais renvoyés, cette route retire tout champ dont le nom contient margin, profit, wholesale, markup, cost_of ou cogs.
bash
curl "https://app.durum.ai/api/v1/sales/reps?from=2026-08-01&to=2026-08-31" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Funnel ​

RouteScopeParamètres
GET /funnelread:funnelfrom, to

Renvoie un objet : étapes du funnel, conversion par source, campagne et produit, délais de conversion.

bash
curl "https://app.durum.ai/api/v1/funnel?from=2026-08-01&to=2026-08-31" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Contacts ​

RouteScopeParamètres
GET /contactsread:contactsfrom, to, limit (entier, défaut 100, max 500), offset (entier, défaut 0), search
GET /contacts/customersread:contactsaucun
GET /contacts/purchasesread:contactsfrom, to
GET /contacts/callsread:callsemail (obligatoire)

Réponses :

  • contacts : un tableau, une ligne par contact : email, total_events, event_types, first_event_date, last_event_date, name, phone, sources, assigned_user_name, value, form_titles, has_campaign, tags, form_response. Pagination par limit et offset.
  • contacts/customers : un tableau, une ligne par client : id, contact_email, contact_name, contact_phone, contact_id, first_event_type, first_event_date, latest_lead_date, first_payment_date, commission_status, commission_expires_at, total_revenue, total_purchases, total_commission, products, created_at.
  • contacts/purchases : un tableau, une ligne par achat : id, purchase_date, product_key, product_name, contact_email, contact_name, amount, commissionable, commission_rate, commission_amount, invoice_id.
  • contacts/calls : les appels des 365 derniers jours auxquels ce courriel a participé, avec l'analyse. Même objet que calls ci-dessous, plus contact_email. Sans email, la réponse est un tableau vide.
bash
curl "https://app.durum.ai/api/v1/contacts?search=exemple.com&limit=200&offset=0" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Appels ​

RouteScopeParamètres
GET /callsread:callsfrom, to, limit (entier, défaut 50, max 200), offset (entier, défaut 0)
GET /calls/transcriptread:callsid (entier, obligatoire)
GET /calls/recordingread:callsid (entier, obligatoire)

calls est le point d'entrée : un tableau des appels analysés, du plus récent au plus ancien, une ligne par appel : artifact_id, starts_at, title, duration_sec, call_analysis_id, summary, call_type, is_qualified, icp_fit_score, qualification_reasoning, next_step_type, next_step_summary, next_step_proposed, scorecard_total, rep_id, markers (tableau de { ts, label, status }). L'artifact_id sert d'id aux deux routes suivantes.

calls/transcript renvoie la transcription brute : un tableau de segments dans l'ordre, chacun avec idx, start_ms, end_ms, speaker_id, speaker_label, speaker_email, text, confidence. Si l'appel n'appartient pas à votre compte, la réponse est 403 forbidden. Sans id, la réponse est un tableau vide.

calls/recording ne renvoie pas le fichier : il renvoie des URL signées, valables une heure, à télécharger ensuite directement :

json
{
  "data": {
    "artifact_id": 1234,
    "content_type": "audio/mpeg",
    "expires_in": 3600,
    "audio_url": "https://…",
    "video_url": null,
    "has_video": false
  }
}

Erreurs propres à calls/recording : 400 invalid_id (id absent ou non positif), 403 forbidden (appel d'un autre compte ou inexistant), 404 no_recording_available (aucun fichier audio ni vidéo).

bash
curl "https://app.durum.ai/api/v1/calls?from=2026-08-01&to=2026-08-31&limit=50" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

curl "https://app.durum.ai/api/v1/calls/transcript?id=1234" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

curl "https://app.durum.ai/api/v1/calls/recording?id=1234" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Parcours et points de contact ​

RouteScopeParamètres
GET /journeysread:journeysfrom, to, limit (entier, défaut 50, max 200), offset (entier, défaut 0), search (fragment de courriel)
GET /journeys/contactread:journeysemail (obligatoire), pageviews (true ou 1 pour inclure les pages vues)
GET /touchpointsread:journeysfrom, to, limit (entier, défaut 100, max 500), offset (entier, défaut 0), kind (web ou conversion)

Ces routes exposent l'UTM capté à chaque point de contact, pas seulement le premier ou le dernier.

  • journeys : un objet { coverage, paging, journeys }. coverage indique depuis quand les points de contact web existent (web_touchpoints_since) : avant cette date, l'absence de touch web ne signifie pas l'absence de visite. paging contient limit, offset, returned. Chaque élément de journeys : contact (email, phone, first_name, last_name), first_seen_at, last_seen_at, first_touch et last_touch (occurred_at, event_type, is_paid, platform, utm, ad_ids), touchpoint_counts (web, conversion, total), milestones (first_lead_at, first_booking_at, first_sale_at, revenue), event_types_seen. from et to filtrent sur la date de dernière activité du contact.
  • journeys/contact : un objet { contact, first_touch_at, last_touch_at, counts, touchpoints }. counts contient total, web, conversion, page_view. touchpoints est la chaîne chronologique complète : chaque point porte l'UTM (utm), les identifiants publicitaires et de clic captés à ce moment.
  • touchpoints : un objet { paging, touchpoints }, du plus récent au plus ancien, pour synchroniser vers votre entrepôt. Chaque point porte notamment utm, ad_ids, click_ids, channel, value, currency, product, is_imported. Un kind autre que web ou conversion renvoie 200 avec { "error": "invalid kind (web|conversion)", "touchpoints": [] }.

L'objet utm contient source, medium, campaign, content, term, campaign_name, adset_name, ad_name, channel, type, sequence, step.

bash
curl "https://app.durum.ai/api/v1/journeys/contact?email=jean@exemple.com&pageviews=true" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Créatifs ​

RouteScopeParamètres
GET /creatives/requestsread:creativesstatus, unnotified (1 ou true), limit (entier, défaut 50, max 200)

Les besoins créatifs sont les demandes que DURUM écrit quand il manque des créas. Sans status, la route renvoie les demandes en cours (open et partial) ; avec status, uniquement ce statut exact. unnotified=1 ne renvoie que les demandes jamais relayées à une équipe. Réponse : un tableau, de la plus ancienne à la plus récente, chaque élément avec id, reason, status, requested_count, filled_count, context, created_at, notified_at.

Le flux prévu pour un outil externe : lire avec unnotified=1, relayer à l'équipe, puis acquitter via POST /creatives/requests/ack (voir Écriture). L'acquittement pose seulement notified_at ; il ne ferme pas la demande.

bash
curl "https://app.durum.ai/api/v1/creatives/requests?unnotified=1" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

ICP et pixels ​

RouteScopeParamètres
GET /icp/criteriaread:icpaucun
GET /capi/pixelsread:capiaucun
  • icp/criteria : l'objet JSON de vos critères de client idéal.
  • capi/pixels : vos pixels Meta connectés et le pixel par défaut (configuration de routage). Les jetons d'accès ne sont jamais renvoyés : tout champ dont le nom contient access_token, secret ou api_key est retiré avant envoi.
bash
curl "https://app.durum.ai/api/v1/capi/pixels" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE"

Écriture ​

Les écritures prennent un corps JSON. Un corps invalide renvoie 400 avec le message de validation dans error. Elles n'agissent que sur votre compte.

RouteMéthodesScopeCorps
/goalsPUT, POSTwrite:goals{ "goals": [ { "metric_key": "…", "target_value": 0 } ] }
/sale-rulePUT, POSTwrite:settings{ "sale_rule": { … } }
/icpPUT, POSTwrite:icp{ "icp": { … } }
/ads/rules/enablePOST, PUTwrite:ads{ "rule_id": "…", "enabled": true }
/ads/rules/dry-runPOST, PUTwrite:ads{ "rule_id": "…", "dry_run": true }
/ads/rules/deletePOSTwrite:ads{ "rule_id": "…" }
/creatives/upload-urlPOSTwrite:creatives{ "content_type": "image/png", "label": "…" }
/creatives/importPOSTwrite:creatives{ "external_ref": "…", "creative": { … } }
/creatives/requests/ackPOSTwrite:creatives{ "ids": [ "uuid", … ] }

Une méthode non listée pour la route répond 405 method_not_allowed.

Objectifs, règle de vente, ICP ​

  • /goals : goals est un tableau d'objets { metric_key, target_value }. Chaque objectif est enregistré sur la période mensuelle. Le corps sans goals renvoie 400 missing goals object. En cas de succès, data vaut { "success": true }.
  • /sale-rule : sale_rule est l'objet de votre règle de comptage des ventes (comment une vente est comptée et dédoublonnée). Corps sans sale_rule : 400 missing sale_rule object.
  • /icp : icp remplace vos critères ICP. Corps sans icp : 400 missing icp object.
bash
curl -X PUT "https://app.durum.ai/api/v1/goals" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"goals":[{"metric_key":"revenue","target_value":100000}]}'

Règles d'ads ​

rule_id est obligatoire (sinon 400 missing rule_id). enabled et dry_run valent true sauf si vous envoyez explicitement false. Le mode simulation calcule sans agir sur Meta. La suppression est définitive. Une règle qui n'est pas la vôtre répond 403 forbidden. Armer une règle en réel (dry_run: false) demande un palier payant : sur le plan Découverte, le refus porte le code plan_free_no_autopilot (l'API elle-même y répond déjà 403 plan_free_no_api).

bash
curl -X POST "https://app.durum.ai/api/v1/ads/rules/dry-run" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"rule_id":"ID_DE_LA_REGLE","dry_run":true}'

Dépôt d'une créa en deux étapes ​

Un dépôt atterrit en réserve dans votre librairie créative : il ne publie rien, ne touche à aucun budget et ne parle à aucune régie. Le visuel ne peut pointer que vers un fichier déposé via l'autorisation émise à l'étape 1 : une URL étrangère est refusée.

Étape 1 : POST /creatives/upload-url. Corps : content_type obligatoire, parmi image/jpeg, image/png, image/webp, video/mp4 (sinon 400) ; label optionnel (étiquette lisible, nettoyée, 60 caractères max). Le chemin de stockage est composé côté serveur dans le dossier de votre compte. Réponse :

json
{
  "data": {
    "asset_url": "https://…/creative-assets/…/mon-visuel-….png",
    "upload_url": "https://…",
    "token": "…",
    "path": "…/2026/09/mon-visuel-….png",
    "content_type": "image/png"
  }
}

Envoyez ensuite le fichier par PUT sur upload_url, avec le même Content-Type et le fichier binaire en corps. L'autorisation est à durée courte.

Étape 2 : POST /creatives/import. Corps : external_ref obligatoire (votre identifiant stable, 200 caractères max) et creative, un objet dont les champs reconnus sont angle, primary_text, headline, hook, cta, destination_url, asset_url (l'asset_url de l'étape 1, tel quel), asset_kind (image ou video), variant_label, visual_subtype, funnel, product, audience, video_script, source (objet libre de provenance). Réponse : { "id", "external_ref", "angle", "score", "en_attente" } où en_attente est le nombre de créas en réserve non publiées et score vaut null tant qu'il n'est pas calculé.

L'import est idempotent : rejouer le même external_ref met à jour la créa au lieu d'en créer une seconde. Une créa déjà publiée n'est jamais réécrite ; son id est simplement renvoyé.

bash
curl -X POST "https://app.durum.ai/api/v1/creatives/upload-url" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"content_type":"image/png","label":"offre-septembre"}'

curl -X PUT "UPLOAD_URL_RECUE" \
  -H "Content-Type: image/png" \
  --data-binary @offre-septembre.png

curl -X POST "https://app.durum.ai/api/v1/creatives/import" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"external_ref":"drive-2026-09-offre-1","creative":{"angle":"Économies d’impôt","headline":"Réduisez vos impôts","primary_text":"…","asset_url":"ASSET_URL_RECUE","asset_kind":"image"}}'

Acquittement des besoins créatifs ​

POST /creatives/requests/ack avec ids, un tableau non vide d'UUID de demandes (sinon 400 missing ids (array of request UUIDs)). Seules vos demandes jamais relayées sont marquées ; data est le nombre de demandes mises à jour. Rejouer le même lot est sans effet.

bash
curl -X POST "https://app.durum.ai/api/v1/creatives/requests/ack" \
  -H "Authorization: Bearer durum_sk_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"ids":["3f2a…","9c1d…"]}'

Champs jamais renvoyés ​

Avant envoi, chaque réponse est parcourue à tous les niveaux d'imbrication et tout champ dont le nom contient l'un des fragments suivants est retiré :

  • identifiants et secrets : access_token, refresh_token, api_key, apikey, secret, signing, service_role, password, webhook_secret, encryption, tokenenc, bearer ;
  • internes d'IA : model, model_name, provider, prompt, system_prompt, temperature, embedding ;
  • coûts internes : cost, cost_estimate, token_count, tokens_used, price_input, price_output ;
  • marges : gross_margin, net_profit, net_profit_after_ads, wholesale, markup, platform_fee, margin_pct, agency_margin, contribution_margin.

Toute valeur texte ressemblant à un identifiant de modèle d'IA est remplacée par DURUM.ai. finance/pnl ajoute ses propres fragments (voir Ventes et finance).

Codes de réponse ​

CodeCorpsSignification
200{ "data": … }succès
400{ "error": "…" }paramètre ou corps invalide ; error contient le message (par exemple missing rule_id, invalid_id, external_ref is required)
401{ "error": "invalid_or_missing_api_key" }clé absente, invalide, révoquée ou expirée
403{ "error": "insufficient_scope", "required": "…" }la clé ne porte pas le scope exigé
403{ "error": "plan_free_no_api" }l'espace de travail est sur le plan Découverte : l'API REST et le serveur MCP exigent un palier payant
403{ "error": "forbidden" }la ressource n'appartient pas à votre compte
404{ "error": "unknown_route", "route": "/api/v1/…" }route inconnue
404{ "error": "not_found" }compte ou objet introuvable pour cette écriture
404{ "error": "no_recording_available" }calls/recording sans fichier
405{ "error": "method_not_allowed" }méthode non prise en charge pour cette route
429{ "error": "rate_limited", "retry_after_seconds": 60 }limite de débit dépassée
429{ "error": "too_many_failed_attempts", "retry_after_seconds": 60 }trop d'échecs d'authentification depuis votre adresse IP
500{ "error": "tenant_barrier" }réponse bloquée par la vérification de compte ; contactez DURUM
502{ "error": "upstream_error" }erreur interne lors de la lecture ou de l'écriture ; réessayez plus tard

Propulsé par DURUM.ai : attribution publicitaire et intelligence opérationnelle