Assets
| Méthode | Chemin | Objet |
|---|---|---|
| POST | /assets | Importer une URL distante en tant qu'asset. |
| POST | /assets/uploads | Démarrer un téléversement direct. |
| POST | /assets/uploads/{uploadId}/complete | Finaliser un téléversement direct. |
| GET | /assets | Lister les assets. |
| GET/PATCH/DELETE | /assets/{id} | Lire, mettre à jour ou supprimer un asset. |
Catégories, mappings, packs, liens et étiquettes
| Méthode | Chemin | Objet |
|---|---|---|
| GET/POST | /categories | Lister ou créer des catégories plates. |
| GET/PATCH/DELETE | /categories/{id} | Lire, renommer ou supprimer une catégorie. |
| GET/POST | /mappings | Lister ou créer/mettre à jour des associations de produits Shopify. |
| GET/PUT/DELETE | /mappings/{id} | Lire, remplacer ou supprimer une association. |
| GET/POST | /packs | Lister ou créer des packs. |
| GET/DELETE | /packs/{id} | Lire ou supprimer un pack. |
| GET/POST | /links | Lister ou créer des liens. La création requiert un plan payant ; les limites de visites et l'expiration restent réservées à l'admin. |
| GET/POST | /license-key-tags | Lister ou créer des étiquettes de clés de licence. |
POST /mappings et PUT /mappings/{id} acceptent un objet facultatif notify_customers ({}, ou { "message": "…", "variant_ids": [ … ] }). Une fois l'écriture validée, Alva met en file d'attente une notification de mise à jour de produit pour les acheteurs du mapping que vous avez écrit — la même campagne que POST /products/{shopify_product_id}/notifications ci-dessous, avec les mêmes règles de note et la même limite de 7 jours par produit. Seules les vérifications portant sur le texte même de la note ont lieu avant l'écriture : une note vide, trop longue, qui utilise une variable inconnue ou mal formée, qui cite plus de cinq métachamps ou dont le texte contient un lien donne 422 invalid_message et rien n'est écrit. Tout autre refus est signalé dans la réponse sous data.notification avec created: false et un code error — jamais sous forme de 4xx, de sorte que l'écriture du mapping elle-même réussit. Cela comprend un problème de métachamp (invalid_message avec errors[] : un métachamp manquant, d'un type non pris en charge, trop long ou contenant un lien, ou une note trop longue une fois ses variables remplies), notification_cooldown avec next_available_at, too_many_active_notifications avec limit et active_notification_ids, no_eligible_recipients, email_disabled, et archive_not_queued lorsque la régénération des fichiers n'a pas pu être mise en file d'attente. Un mapping tout neuf n'a pas encore d'acheteurs et signale no_eligible_recipients. data.notification n'est présent que si vous avez envoyé l'indicateur. L'indicateur n'ajoute aucun coût de limite de débit : l'écriture du mapping coûte ses 2 jetons habituels. Rejouer la même Idempotency-Key renvoie la réponse stockée sans seconde campagne ; pour ne réessayer que la notification, appelez POST /products/{shopify_product_id}/notifications avec une clé neuve et variant_ids nommant les variantes du mapping écrit, ou les mêmes variant_ids que portait l'indicateur. Sans variant_ids, cet endpoint notifie les acheteurs de tous les mappings du produit, pas seulement de celui que vous avez écrit.
Un seul indicateur par produit, pas un par variante. L'indicateur n'envoie d'e-mail qu'aux acheteurs du mapping que vous avez écrit, mais il consomme la limite de 7 jours du produit entier. Si vous écrivez les mappings de variantes d'un produit un par un avec l'indicateur sur chacun, la première campagne occupe les 7 jours du produit, et les autres signalent donc notification_cooldown. Placez plutôt l'indicateur sur une seule écriture, la dernière, afin que la campagne attende aussi les régénérations mises en file d'attente par les écritures précédentes. Indiquez dans variant_ids chaque variante dont les acheteurs doivent être informés, y compris celles du mapping écrit lui-même : variant_ids remplace la portée par défaut au lieu de s'y ajouter.
Commandes et accès
| Méthode | Chemin | Objet |
|---|---|---|
| GET | /orders/{shopify_order_id} | Lire l'état de téléchargement d'une commande. |
| GET/POST | /orders/{shopify_order_id}/assignments | Lister ou créer des affectations au niveau produit. |
| GET | /orders/{shopify_order_id}/assignments/{purchaseId}/download-urls | Générer des URL de téléchargement. |
| POST | /orders/{shopify_order_id}/revoke | Désactiver l'accès. |
| POST | /orders/{shopify_order_id}/restore | Rétablir l'accès. |
| POST | /orders/{shopify_order_id}/grant-downloads | Accorder des téléchargements supplémentaires. |
| POST | /orders/{shopify_order_id}/resend | Renvoyer l'e-mail de livraison. |
L'endpoint download-urls renvoie 422 withdrawal_consent_required lorsque la boutique a activé le consentement au droit de rétractation UE et que la commande n'a pas encore d'enregistrement de consentement ; les URL de téléchargement sont émises dès que le client donne son consentement.
Les endpoints download-urls et resend renvoient 409 delivery_not_yet_released lorsque le produit a un délai de livraison du téléchargement configuré et que les fichiers de l'acheteur ne sont pas encore débloqués. La valeur error.details.release_at est l'instant ISO 8601 du déblocage, et l'endpoint grant-downloads libère la commande par anticipation.
Notifications de mise à jour de produit
Informez par e-mail les acheteurs d'un produit qu'il a été mis à jour — la même campagne qu'un marchand lance avec Notifier les clients sur la page d'un produit dans l'application — depuis votre propre système. Disponible sur toutes les formules payantes ; 403 forbidden signifie que l'API est désactivée pour l'application (l'interrupteur d'arrêt global) ou qu'Alva a désactivé la fonctionnalité — contactez-nous si vous recevez cette réponse. Dans le chemin, {shopify_product_id} est l'id numérique nu du produit (recommandé) ou un GID encodé en pourcentage en un seul segment de chemin (gid%3A%2F%2Fshopify%2FProduct%2F123) ; un gid://shopify/Product/123 littéral forme plusieurs segments de chemin et n'atteint pas la route.
| Méthode | Chemin | Objet |
|---|---|---|
| POST | /products/{shopify_product_id}/notifications | Mettre en file d'attente une campagne pour chaque acheteur éligible du produit (202). Envoyez { "dry_run": true } pour exécuter les mêmes vérifications et obtenir le nombre de destinataires, l'objet et la note rendue sans rien envoyer (200). Coûte 10 jetons de limite de débit dans les deux cas. |
| GET | /notifications/{notificationId} | Lire une campagne : statut, compteurs, waiting_for_archive, error. Les campagnes lancées depuis l'application apparaissent aussi. |
| POST | /notifications/{notificationId}/cancel | Annuler une campagne encore en file d'attente (200, statut cancelled). La limite de 7 jours du produit est conservée. |
Corps de la requête (chaque champ est facultatif ; {} notifie tout le produit sans note). message : une note en texte brut de 2 000 caractères maximum, affichée sous « Un message de {votre boutique} : » au-dessus du bouton de téléchargement. La note sert à décrire ce qui a changé dans le produit — corrections, nouveaux fichiers, ce qu'il faut télécharger à nouveau — et ne doit pas servir à des promotions ni à des remises. Elle peut utiliser {customer.first_name}, {shop.name}, {product.title} et {product.metafields.<namespace>.<key>} (jusqu'à cinq métachamps de type texte, nombre, date ou liste de texte ; les autres types sont refusés). Les liens sont interdits partout dans la note — adresses web, www., noms de domaine nus et adresses e-mail sont refusés, y compris dans la valeur d'un métachamp — et une variable inconnue est refusée plutôt que laissée en texte. Un message présent mais vide est refusé ; omettez le champ pour ne pas mettre de note. variant_ids : limite la campagne aux mappings qui desservent ces variantes (ids nus ou GID, 100 au maximum) ; omettez-le pour tout le produit. Un tableau vide donne 400 invalid_request, jamais « tout ». dry_run : voir le tableau.
Qui reçoit l'e-mail. Par défaut, chaque mapping du produit qui contient des fichiers, des packs ou des liens ; les mappings à clés uniquement et personnalisés sont ignorés. Un acheteur compte une seule fois, quel que soit le nombre de variantes ciblées qu'il a achetées, et le bouton ouvre son achat le plus récent. Les acheteurs qui se sont désabonnés des e-mails de mise à jour de produit sont ignorés et comptés dans opted_out_count.
Une campagne par produit tous les 7 jours, toutes variantes et toutes sources confondues — cet endpoint, l'indicateur notify_customers sur une écriture de mapping et le bouton du marchand lui-même. Pendant cette semaine, et tant qu'une campagne pour le produit est encore en file d'attente ou en cours d'envoi, la réponse est 429 notification_cooldown avec Retry-After (en secondes, jusqu'à sept jours) et error.details.next_available_at. Ce n'est pas le seau à jetons par clé : ne réessayez pas automatiquement — une boucle de nouvelles tentatives déclenchée sur 429 tournerait pendant une semaine. Planifiez le prochain appel à next_available_at. Annuler une campagne ne rend pas ses 7 jours au produit ; utilisez dry_run pour vérifier une note avant l'envoi. Une campagne qui échoue avec zéro envoi libère bien la limite, elle peut donc simplement être réessayée.
5 campagnes au maximum par boutique en même temps. Une boutique peut avoir au maximum 5 campagnes en file d'attente ou en cours d'envoi simultanément, tous produits et toutes sources confondus. Une sixième donne 429 too_many_active_notifications : error.details.limit est le plafond et error.details.active_notification_ids liste les campagnes de cette boutique en file d'attente ou en cours d'envoi, de la plus ancienne à la plus récente. Il n'y a pas de Retry-After ; interrogez régulièrement GET /notifications/{id} pour l'une d'elles et réessayez une fois qu'elle est terminée. Une simulation est refusée de la même manière. Lors d'une écriture de mapping, le refus est signalé dans data.notification, jamais sous forme de 4xx.
Un seul e-mail de mise à jour de produit par acheteur et par jour. Un acheteur reçoit au maximum un e-mail de mise à jour de produit d'une même boutique sur 24 heures, le décompte se faisant par adresse e-mail, toutes campagnes, tous produits et toutes sources confondus. La règle s'applique au moment où la campagne envoie : un acheteur qui en a déjà reçu un est ignoré, et un acheteur ignoré ne compte pas comme un échec. Les acheteurs ignorés ne sont comptés ni dans sent_count, ni dans failed_count, ni dans suppressed_count, de sorte que recipient_count peut être supérieur à leur somme. Une campagne dont tous les acheteurs ont été ignorés se termine en failed avec error: recipients_recently_notified et ne consomme pas les 7 jours du produit. Une campagne dont seuls certains acheteurs ont été ignorés se termine normalement et les consomme bien.
L'attente de l'archive. Si l'archive ZIP d'un mapping ciblé est en cours de régénération — vous venez de remplacer ses fichiers — la campagne attend la fin de la régénération afin qu'aucun acheteur ne télécharge l'ancienne archive : waiting_for_archive: true sur le 202 et sur le GET. Seul un mapping qui livre une archive ZIP fait attendre une campagne. Une régénération qui échoue, ou qui reste 60 minutes sans progresser pendant la génération (6 heures tant qu'elle attend encore de démarrer ou d'être relancée), décomptées à partir du dernier changement d'état de la régénération, et non du moment où la campagne a été créée, fait échouer la campagne avec zéro envoi (error vaut archive_build_failed ou archive_not_ready) et libère la limite ; corrigez les fichiers et réessayez.
Idempotence. Un 202 est rejoué pendant 24 heures sous la même clé (même id, pas de seconde campagne). Les refus ne sont jamais stockés, une nouvelle tentative avec la même clé après next_available_at est donc réévaluée. Utilisez une Idempotency-Key neuve par simulation : une clé rejouée renvoie l'aperçu stocké, et la même clé avec et sans dry_run donne 409 idempotency_conflict.
Statut sur GET. queued → processing → completed, failed ou cancelled. completed avec partial: true signifie que certains envois ont échoué ou ont été supprimés (voir sent_count, failed_count, suppressed_count), ou que l'envoi s'est arrêté en cours de route (voir ci-dessous). Sur failed, error est l'un de interrupted, worker_crashed, send_aborted, archive_build_failed, archive_not_ready, email_disabled, invalid_message, plan_required, notifications_suspended, notifications_switched_off, nothing_sent, recipients_recently_notified, no_eligible_recipients, failed. source vaut admin, api ou api_mapping.
Vérifications pendant l'envoi. Avant chaque lot de 500 e-mails au maximum, la campagne vérifie à nouveau la boutique. Elle s'arrête si l'abonnement est devenu inactif ou si la boutique est passée à la formule Free (plan_required), si les e-mails aux clients ont été désactivés (email_disabled), si l'envoi a été suspendu à la suite de plaintes (notifications_suspended) ou si Alva a désactivé les notifications (notifications_switched_off). Arrêtée avant qu'aucun acheteur n'ait reçu d'e-mail, la campagne est failed avec ce code error et les 7 jours du produit sont libérés. Arrêtée après l'envoi d'e-mails à certains acheteurs, elle est completed avec partial: true. nothing_sent signifie que tous les envois ont échoué et que personne n'a reçu d'e-mail ; cela libère aussi les 7 jours. no_eligible_recipients signifie qu'il ne restait plus personne à qui écrire au moment où la campagne a envoyé (chaque acheteur s'était désabonné ou avait perdu l'accès au téléchargement) : rien n'a donc été envoyé et les 7 jours sont libérés.
Refus. 402 plan_required (la boutique est sur la formule Free, ou son abonnement n'est pas actif), 403 forbidden (l'API est désactivée pour l'application ou Alva a désactivé la fonctionnalité — contactez-nous), 403 notifications_suspended (envoi suspendu à la suite de plaintes — contactez le support), 404 mapping_not_found (aucun mapping pour le produit, ou une variante qu'aucun mapping ne dessert ou que Shopify ne liste pas parmi les variantes du produit — error.details.unresolved_variant_ids), 409 multiple_mappings_match (error.details.ambiguous_variant_ids), 409 personalized_product, 422 invalid_message (error.details.errors[] nomme chaque règle enfreinte, error.details.max_length est le plafond), 422 email_disabled (les e-mails aux clients sont désactivés dans l'application), 422 no_downloadable_content, 422 no_eligible_recipients (error.details.opted_out_count), 429 notification_cooldown, 429 too_many_active_notifications (error.details.limit, error.details.active_notification_ids), 409 app_not_installed (la note fait appel à un métachamp ou vous avez envoyé variant_ids, et Alva n'a aucune session Shopify active pour la boutique, généralement parce que l'application a été désinstallée), 500 internal_error (par exemple lorsque Shopify n'a pas pu renvoyer les métachamps du produit pour la note ni confirmer les variantes demandées, ou que la création a attendu plus de 8 secondes derrière les autres créations de la boutique : chaque 500 de cet endpoint libère l'Idempotency-Key, réessayez donc la même requête avec la même clé ; si la tentative échouée a malgré tout mis la campagne en file d'attente, la nouvelle tentative est refusée avec 429 notification_cooldown au lieu d'en lancer une seconde). GET et cancel répondent 404 notification_not_found pour un id manquant ou étranger, et cancel répond 409 notification_not_cancellable avec error.details.status dès qu'une campagne a quitté la file d'attente. Consultez la page des erreurs pour savoir que faire dans chaque cas.
Santé et statut
| Méthode | Chemin | Objet |
|---|---|---|
| GET | /health | Vérifier la disponibilité de l'API. |
| GET | /ping | Vérifier l'authentification. |
| GET | /jobs/{jobId} | Lire l'état d'une tâche asynchrone. |
Documentation de l'API
Cet article vous a-t-il été utile ?
Dernière mise à jour 2026-10-20