Devis
Le cœur transactionnel de Cord. Créez des propositions, obtenez leurs liens publics et gérez-les.
Vue d’ensemble
L’objet Cotizacion (quote) représente une proposition commerciale adressée à un client. Avec l’API de Cord, vous pouvez injecter des devis directement depuis un ERP ou un CRM, ou créer des flux automatisés de panier d’achat.
Tous les devis créés via l’API sont consignés dans le journal d’audit (audit_log), automatiquement étiquetés comme provenant de votre clé API.
Créer un devis
Pour créer un devis en brouillon, effectuez un POST /api/v1/cotizaciones en envoyant le détail commercial.
Requête :
curl -X POST "https://cordhq.app/api/v1/cotizaciones" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-d '{
"cliente_id": "8f7b2c1e-4d3a-4b9f-a6e2-1c5d7e9f0a3b",
"terminos": "net30",
"vigencia_dias": 15,
"notas": "Annual project",
"base_currency": "EUR",
"items": [
{
"descripcion": "Annual license — Pro plan",
"cantidad": 12,
"precio_unitario": 500
}
]
}'
Chaque ligne de items exige descripcion, cantidad et precio_unitario — les noms des champs restent en espagnol quelle que soit la langue de la requête, car ils constituent le schéma canonique de l’API. producto_id est facultatif (il référence un produit de votre catalogue pour en reprendre le nom et le prix catalogue) et precio_negociado permet de saisir un prix remisé différent du prix catalogue. Il n’existe pas de champ sku : pour lier la ligne à un produit, utilisez son producto_id.
Champs du devis
| Champ | Détail |
|---|---|
items |
Obligatoire. Les lignes (voir le tableau suivant). |
cliente_id ou cliente |
Un client de votre annuaire, ou les données pour le créer (empresa, et en option email, contacto, telefono, rfc et fiscal). |
terminos |
contado, net7, net15, net30, net45, net60 ou net90 (N jours calendaires). Sans lui, les conditions du client ou celles de votre compte. |
vigencia_dias |
Nombre de jours de validité du devis à compter de son envoi. |
notas |
Notes pour le client. |
base_currency |
Devise de vente (ISO 4217). |
fiscal_currency |
Devise comptable ; si elle diffère de la devise de vente, la facture déclare le taux de change. |
iva_incluido |
true si les prix incluent déjà la taxe. |
descuento |
Remise sur le document avant taxes : { "tipo": "porcentaje", "valor": 10 } ou { "tipo": "monto", "valor": 2500 }. Cord calcule le montant et le répartit entre les lignes ; un montant est plafonné au sous-total. null la supprime. Voir Remises et coupons. |
cupon |
Le code d’un coupon de votre compte (par exemple, "WELCOME10"). Cord vérifie ses dates de validité, sa devise et ses utilisations ; s’il est présent, il l’emporte sur descuento. |
send |
true pour l’envoyer dès sa création. Clé secrète uniquement. |
| Champ de la ligne | Détail |
|---|---|
descripcion, cantidad, precio_unitario |
Obligatoires. |
producto_id |
Produit du catalogue. |
precio_negociado |
Prix final de la ligne, s’il diffère du prix catalogue. |
costo_unitario |
Coût interne pour calculer la marge. Le client ne le voit jamais. |
tax_rate |
Fraction de 0 à 1 (0.16, et non 16), validée par rapport à votre catalogue de taxes. 0 signifie exonérée volontairement. |
exemption_reason |
Uniquement avec un tax_rate de 0. Espagne : le motif d’exonération ou de non-assujettissement de Verifactu (E1–E6, N1, N2, S2). Reste de l’UE : le code VATEX de la facture électronique. |
clave_sat, clave_unidad_sat |
Mexique uniquement : clé de produit ou de service du SAT (8 chiffres) et clé d’unité de cette ligne. Elles l’emportent sur celles du produit ; une clé au format non valide répond 400. Ignorées hors du Mexique. |
curl -X POST "https://cordhq.app/api/v1/cotizaciones" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: quote-order-4471" \
-d '{
"cliente_id": "8f7b2c1e-4d3a-4b9f-a6e2-1c5d7e9f0a3b",
"terminos": "net45",
"base_currency": "MXN",
"cupon": "WELCOME10",
"items": [
{ "descripcion": "Gray cement CPC 30R", "cantidad": 400, "precio_unitario": 245,
"tax_rate": 0.16, "clave_sat": "30111601", "clave_unidad_sat": "H87" }
]
}'
Avec une clé publiable (celle de votre site), Cord ignore descuento, precio_negociado et costo_unitario : la seule remise acceptée est un cupon. Un coupon qui n’existe pas répond 404 avec code: "coupon_no_existe" ; un coupon inactif, expiré, épuisé, dans une autre devise ou limité par client sans client répond 409 avec coupon_inactivo, coupon_vencido, coupon_aun_no_vigente, coupon_agotado, coupon_agotado_cliente, coupon_moneda ou coupon_requiere_cliente.
base_currency est la devise dans laquelle le client voit et paie le devis (ISO 4217, par ex. MXN, USD, EUR, GBP). Elle est facultative — si vous l’omettez, Cord utilise la devise comptable de votre organisation —, mais l’API est indépendante du pays : un compte à Madrid, à Austin ou à Bogotá établit ses devis dans sa propre devise sans aucun paramètre supplémentaire.
Réponse réussie :
Cord vous renvoie l’id (UUID) du devis, son token public et le lien public (link_publico) déjà construit sous forme d’URL absolue, pour que vous puissiez l’envoyer immédiatement à votre client par WhatsApp, SMS ou un moteur d’e-mails externe. Si votre organisation dispose d’un domaine personnalisé actif, le lien utilise ce domaine au lieu de cordhq.app.
{
"data": {
"id": "2a9d8e4f-6b1c-4d7a-9e3f-5c8b1a2d4e6f",
"folio": "COT-00104",
"token": "9f3b6c2a7e1d4f8b0a5c3e7d1b9f2a46",
"link_publico": "https://cordhq.app/q/9f3b6c2a7e1d4f8b0a5c3e7d1b9f2a46",
"needs_approval": false
}
}
Si le devis nécessite une validation interne avant d’être envoyé (par exemple, une remise hors du seuil autorisé), needs_approval vaut true et motivo en décrit la raison.
Lister les devis
Vous pouvez récupérer l’historique paginé de vos devis ou filtrer par statut (par exemple, retrouver tous les devis sent ou paid).
Requête :
curl -X GET "https://cordhq.app/api/v1/cotizaciones?status=paid&limit=10" \
-H "Authorization: Bearer sk_live_tU..."
La valeur de status est l’état interne tel quel (en anglais, jamais traduit) : draft, sent, viewed, approved, rejected, expired, paid ou invoiced. Pour retrouver un devis par son numéro, utilisez folio=COT-00104 : la comparaison porte sur le numéro complet, sans tenir compte de la casse. Pour ne voir que les devis d’un client, utilisez cliente_id=<uuid>.
{
"data": [
{
"id": "2a9d8e4f-6b1c-4d7a-9e3f-5c8b1a2d4e6f",
"folio": "COT-00104",
"cliente": "Stark Industries",
"status": "paid",
"total": 6000,
"moneda": "MXN",
"terminos": "Net 30",
"terminos_codigo": "net30",
"vigencia": "10 sep 2026",
"creada": "20 ago 2026",
"link_publico": "https://cordhq.app/q/9f3b6c2a7e1d4f8b0a5c3e7d1b9f2a46",
"language": "es"
}
],
"meta": { "limit": 10, "offset": 0, "total": 1, "next_cursor": null }
}
Dates et conditions au format d’affichage
Dans la liste et le détail, terminos arrive sous forme de libellé dans la langue de votre compte (Paiement à réception ou Contado, Net 45) et vigencia et creada sous forme de dates d’affichage (10 sept. 2026), et non de dates ISO. Ne les analysez pas : pour comparer le délai, utilisez terminos_codigo (contado, net7, net15, net30, net45, net60 ou net90), qui ne change pas avec la langue ; pour l’horodatage exact de chaque changement, utilisez le created_at de l’historique des événements avec object_id.
Dans la liste, link_publico est aussi une URL absolue, comme dans la réponse de création. Pour le détail d’un seul devis (lignes, chronologie des événements, approbation), utilisez GET /api/v1/cotizaciones/{id}.
language est la langue dans laquelle le client reçoit le devis : es, en, pt, fr ou de. Il est en lecture seule : le devis la prend à l’envoi, du client ou, s’il n’en a pas, de votre organisation, et une nouvelle version la conserve. Il vaut null tant que le devis est un brouillon. Pour l’envoyer dans une autre langue, modifiez le language du client avant l’envoi.
Le détail contient aussi descuento : null s’il n’y en a pas, ou la remise sur le document avec sa définition, le coupon dont elle provient et le montant calculé avant taxes :
"descuento": { "tipo": "porcentaje", "valor": 10, "cupon": "WELCOME10", "monto": 9800, "moneda": "MXN" }
total inclut déjà la remise.
Proposer des lignes avec l’IA
POST /api/v1/cotizaciones/ia reçoit { "texto": "..." } (la commande du client, jusqu’à 6000 caractères) et renvoie les lignes rapprochées de votre catalogue, sans rien créer :
{ "data": { "moneda": "MXN", "items": [{ "id": "7e3c9a1f-2b4d-4c6e-8f0a-b1d3e5f7a9c2", "nombre": "Gray Cement 50kg", "unidad": "sack", "lista": 185, "negociado": null, "cantidad": 5 }] } }
id vaut null lorsque l’article ne figure pas dans votre catalogue. Les prix sont exprimés en moneda. Pour créer le devis, envoyez ces lignes à POST /api/v1/cotizaciones. Nécessite une clé avec le droit d’écriture et consomme une unité d’IA de votre offre : s’il n’en reste plus, vous recevez 429 avec code: "ai_quota_exceeded" ; si le texte ne contient aucun produit, 422 avec code: "no_items".
Changer le statut d’un devis
Avec une clé en écriture (write), vous pouvez faire avancer le devis dans son cycle de vie avec POST /api/v1/cotizaciones/{id} :
curl -X POST "https://cordhq.app/api/v1/cotizaciones/2a9d8e4f-6b1c-4d7a-9e3f-5c8b1a2d4e6f" \
-H "Authorization: Bearer sk_live_tU..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: approve-COT-00104" \
-d '{ "action": "approve" }'
action |
Depuis le statut | Résultat |
|---|---|---|
send |
draft |
Envoie le devis au client (e-mail et lien) dans la langue de ses documents, que le devis enregistre dans language. Avec l’offre Gratuite, consomme l’un des envois du mois. |
resend |
sent, viewed, expired |
Le renvoie au client. |
approve |
sent, viewed |
Le marque comme approuvé. |
reject |
sent, viewed |
Le marque comme refusé. |
mark_paid |
approved, invoiced |
Enregistre le paiement. Accepte un payment_method facultatif (par défaut transferencia). Les paiements en ligne en attente pour ce devis sont annulés. |
La réponse est { "data": { "ok": true, "status": "approved" } }. Si le devis n’est pas dans un statut auquel l’action peut s’appliquer, ou si une autre requête l’a modifié au même moment, vous recevez 409 avec code: "invalid_state" et rien n’est appliqué. Chaque changement est consigné dans le journal d’audit avec votre clé comme auteur et déclenche son événement de webhook.
L’émission de la facture n’est pas disponible par cette route : les factures se créent et s’émettent avec POST /api/v1/facturas et POST /api/v1/facturas/{id}.
Supprimer un brouillon
DELETE /api/v1/cotizaciones/{id} supprime un devis qui n’a jamais été envoyé (draft). Tout autre statut répond 409.