Comment utiliser l'API Etsy : Guide d'intégration complet (2026)

Ashley Innocent

Ashley Innocent

20 March 2026

Comment utiliser l'API Etsy : Guide d'intégration complet (2026)

TL;DR

L'API Etsy permet aux développeurs de créer des applications qui interagissent avec la marketplace d'Etsy. Elle utilise l'authentification OAuth 2.0, des points d'accès RESTful pour les boutiques, les fiches produits, les commandes et la gestion des stocks, avec des limites de débit de 10 appels par seconde et par application. Ce guide couvre la configuration de l'authentification, les points d'accès principaux, l'intégration de webhooks et les stratégies de déploiement en production.

Introduction

Etsy traite plus de 13 milliards de dollars de ventes brutes de marchandises annuelles dans plus de 230 pays. Pour les développeurs qui créent des outils de commerce électronique, des systèmes de gestion des stocks ou des plateformes d'analyse, l'intégration de l'API Etsy n'est pas une option, c'est une nécessité.

Voici la réalité : les vendeurs gérant plusieurs canaux de vente perdent 15 à 20 heures par semaine en saisie manuelle de données. Une solide intégration de l'API Etsy automatise la synchronisation des fiches produits, le traitement des commandes et les mises à jour des stocks sur toutes les plateformes.

Ce guide vous accompagne tout au long du processus complet d'intégration de l'API Etsy. Vous apprendrez l'authentification OAuth 2.0, la gestion des boutiques et des fiches produits, le traitement des commandes, la gestion des webhooks et le dépannage des erreurs. À la fin, vous disposerez d'une intégration Etsy prête pour la production.

💡
Apidog simplifie les tests d'intégration API. Testez vos points d'accès Etsy, validez les flux OAuth, inspectez les charges utiles des webhooks et déboguez les problèmes d'authentification dans un seul espace de travail. Importez des spécifications API, simulez des réponses et partagez des scénarios de test avec votre équipe.

Qu'est-ce que l'API Etsy ?

Etsy fournit une API RESTful pour accéder aux données du marché et gérer les opérations des vendeurs. L'API gère :

Fonctionnalités clés

Fonctionnalité Description
Conception RESTful Méthodes HTTP standard avec réponses JSON
OAuth 2.0 Authentification sécurisée avec rafraîchissement des jetons d'accès
Webhooks Notifications en temps réel pour les événements de commande et de fiche produit
Limitation de débit 10 requêtes par seconde et par application (avec une allocation de rafale)
Support Sandbox Environnement de test pour le développement sans données réelles

Aperçu de l'architecture de l'API

Etsy utilise une structure d'API REST versionnée :

https://openapi.etsy.com/v3/application/

La version 3 (v3) est la norme actuelle, offrant un support OAuth 2.0 amélioré et des structures de points d'accès simplifiées par rapport à la v2.

Comparaison des versions de l'API

Version Statut Authentification Cas d'utilisation
V3 Actuelle OAuth 2.0 Toutes les nouvelles intégrations
V2 Dépréciée OAuth 1.0a Applications héritées uniquement
V1 Retirée N/A Ne pas utiliser

Migrez immédiatement toutes les intégrations V2 vers la V3. Etsy a annoncé la dépréciation de la V2 avec un retrait complet prévu pour fin 2026.

Premiers pas : Configuration de l'authentification

Étape 1 : Créez votre compte développeur Etsy

Avant d'accéder à l'API, vous avez besoin d'un compte développeur :

  1. Visitez le Portail des développeurs Etsy
  2. Connectez-vous avec votre compte Etsy (ou créez-en un)
  3. Accédez à Vos applications dans le tableau de bord des développeurs
  4. Cliquez sur Créer une nouvelle application

Étape 2 : Enregistrez votre application

Remplissez le formulaire d'enregistrement de l'application :

Après soumission, vous recevrez :

Note de sécurité : Stockez les informations d'identification dans des variables d'environnement, jamais dans le code :

# fichier .env
ETSY_KEY_STRING="votre_chaine_de_cle_ici"
ETSY_SHARED_SECRET="votre_secret_partage_ici"
ETSY_ACCESS_TOKEN="genere_via_oauth"
ETSY_REFRESH_TOKEN="genere_via_oauth"

Étape 3 : Comprendre le flux OAuth 2.0

Etsy utilise OAuth 2.0 pour l'authentification. Voici le flux complet :

1. L'utilisateur clique sur "Se connecter avec Etsy" dans votre application
2. Votre application redirige vers l'URL d'autorisation Etsy
3. L'utilisateur se connecte et accorde les permissions
4. Etsy redirige vers votre application avec le code d'autorisation
5. Votre application échange le code contre un jeton d'accès
6. Votre application utilise le jeton d'accès pour les appels API
7. Rafraîchissez le jeton lorsque le jeton d'accès expire (1 heure)

Étape 4 : Implémenter l'autorisation OAuth

Générez l'URL d'autorisation :

const generateAuthUrl = (clientId, redirectUri, state) => {
  const baseUrl = 'https://www.etsy.com/oauth/connect';
  const params = new URLSearchParams({
    client_id: clientId,
    redirect_uri: redirectUri,
    scope: 'listings_r listings_w orders_r orders_w shops_r',
    state: state, // Chaîne aléatoire pour la protection CSRF
    response_type: 'code'
  });

  return `${baseUrl}?${params.toString()}`;
};

// Utilisation
const authUrl = generateAuthUrl(
  process.env.ETSY_KEY_STRING,
  'https://votre-app.com/callback',
  crypto.randomBytes(16).toString('hex')
);

console.log(`Rediriger l'utilisateur vers : ${authUrl}`);

Portées requises

Demandez uniquement les autorisations dont votre application a besoin :

Portée Description Cas d'utilisation
listings_r Lire les fiches produits Afficher les produits, synchroniser les stocks
listings_w Écrire les fiches produits Créer/mettre à jour les produits
orders_r Lire les commandes Gestion des commandes, exécution
orders_w Écrire les commandes Mettre à jour le statut des commandes, ajouter le suivi
shops_r Lire les infos de la boutique Afficher le profil de la boutique, analyses
transactions_r Lire les transactions Rapports financiers
email Accéder à l'e-mail de l'acheteur Communication de commande

Étape 5 : Échanger le code contre un jeton d'accès

Gérez le rappel OAuth et échangez le code d'autorisation :

const exchangeCodeForToken = async (code, redirectUri) => {
  const response = await fetch('https://api.etsy.com/v3/public/oauth/token', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      client_id: process.env.ETSY_KEY_STRING,
      client_secret: process.env.ETSY_SHARED_SECRET,
      redirect_uri: redirectUri,
      code: code
    })
  });

  const data = await response.json();

  // Stockez-les en toute sécurité dans votre base de données
  return {
    access_token: data.access_token,
    refresh_token: data.refresh_token,
    expires_in: data.expires_in, // Généralement 3600 secondes (1 heure)
    user_id: data.user_id,
    scope: data.scope
  };
};

// Gérer la route de rappel
app.get('/callback', async (req, res) => {
  const { code, state } = req.query;

  // Vérifiez que l'état correspond à ce que vous avez envoyé (protection CSRF)
  if (state !== req.session.oauthState) {
    return res.status(400).send('Paramètre d\'état invalide');
  }

  try {
    const tokens = await exchangeCodeForToken(code, 'https://votre-app.com/callback');

    // Stocker les jetons dans la base de données associée à l'utilisateur
    await db.users.update(req.session.userId, {
      etsy_access_token: tokens.access_token,
      etsy_refresh_token: tokens.refresh_token,
      etsy_token_expires: Date.now() + (tokens.expires_in * 1000),
      etsy_user_id: tokens.user_id
    });

    res.redirect('/tableau-de-bord');
  } catch (error) {
    console.error('Échange de jetons échoué :', error);
    res.status(500).send('Authentification échouée');
  }
});

Étape 6 : Implémenter le rafraîchissement des jetons

Les jetons d'accès expirent après 1 heure. Implémentez un rafraîchissement automatique :

const refreshAccessToken = async (refreshToken) => {
  const response = await fetch('https://api.etsy.com/v3/public/oauth/token', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      client_id: process.env.ETSY_KEY_STRING,
      client_secret: process.env.ETSY_SHARED_SECRET,
      refresh_token: refreshToken
    })
  });

  const data = await response.json();

  // Mettre à jour les jetons stockés
  return {
    access_token: data.access_token,
    refresh_token: data.refresh_token, // Toujours enregistrer le nouveau jeton de rafraîchissement
    expires_in: data.expires_in
  };
};

// Middleware pour s'assurer d'un jeton valide avant les appels API
const ensureValidToken = async (userId) => {
  const user = await db.users.findById(userId);

  // Vérifier si le jeton expire dans les 5 minutes
  if (user.etsy_token_expires < Date.now() + 300000) {
    const newTokens = await refreshAccessToken(user.etsy_refresh_token);

    await db.users.update(userId, {
      etsy_access_token: newTokens.access_token,
      etsy_refresh_token: newTokens.refresh_token,
      etsy_token_expires: Date.now() + (newTokens.expires_in * 1000)
    });

    return newTokens.access_token;
  }

  return user.etsy_access_token;
};

Étape 7 : Effectuer des appels API authentifiés

Incluez le jeton d'accès dans chaque requête :

const makeEtsyRequest = async (endpoint, options = {}) => {
  const accessToken = await ensureValidToken(options.userId);

  const response = await fetch(`https://openapi.etsy.com/v3/application${endpoint}`, {
    ...options,
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'x-api-key': process.env.ETSY_KEY_STRING,
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      ...options.headers
    }
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Erreur API Etsy : ${error.message}`);
  }

  return response.json();
};

Points d'accès pour la gestion de la boutique

Récupération des informations sur la boutique

Récupérez les détails de la boutique, les politiques et les paramètres :

const getShopInfo = async (shopId) => {
  const response = await makeEtsyRequest(`/shops/${shopId}`, {
    method: 'GET'
  });

  return response;
};

// Utilisation
const shop = await getShopInfo(12345678);
console.log(`Boutique : ${shop.title}`);
console.log(`Devise : ${shop.currency_code}`);
console.log(`Nombre d'annonces : ${shop.num_listings_active}`);

Réponse attendue de la boutique

{
  "shop_id": 12345678,
  "shop_name": "MyHandmadeShop",
  "title": "Bijoux et accessoires faits main",
  "announcement": "Bienvenue ! Livraison gratuite pour les commandes de plus de 50 $",
  "currency_code": "USD",
  "is_vacation": false,
  "vacation_message": null,
  "sale_message": "Merci de soutenir les petites entreprises !",
  "digital_sale_message": null,
  "created_timestamp": 1609459200,
  "updated_timestamp": 1710950400,
  "num_listings_active": 127,
  "num_listings_sold": 1543,
  "gaussian_alphas": {
    "overall": 4.8,
    "last_30_days": 4.9
  },
  "vacation_autoreply": null,
  "url": "https://www.etsy.com/shop/MyHandmadeShop",
  "image_url_760x100": "https://i.etsystatic.com/.../banner_760x100.jpg"
}

Récupération des sections de la boutique

Organisez les fiches produits par sections :

const getShopSections = async (shopId) => {
  const response = await makeEtsyRequest(`/shops/${shopId}/sections`, {
    method: 'GET'
  });

  return response;
};

// Exemple de réponse
{
  "count": 5,
  "results": [
    {
      "shop_section_id": 12345,
      "title": "Colliers",
      "rank": 1,
      "num_listings": 23
    },
    {
      "shop_section_id": 12346,
      "title": "Boucles d'oreilles",
      "rank": 2,
      "num_listings": 45
    }
  ]
}

Gestion des fiches produits

Création d'une nouvelle fiche produit

Créez une fiche produit avec des images et des variations :

const createListing = async (shopId, listingData) => {
  const payload = {
    title: listingData.title,
    description: listingData.description,
    price: listingData.price.toString(), // Doit être une chaîne
    quantity: listingData.quantity,
    sku: listingData.sku || [],
    tags: listingData.tags.slice(0, 13), // Max 13 tags
    category_id: listingData.categoryId,
    shop_section_id: listingData.sectionId,
    state: listingData.state || 'active', // active, inactive, draft
    who_made: listingData.whoMade, // i_did, someone_else, collective (je l'ai fait, quelqu'un d'autre, collectif)
    when_made: listingData.whenMade, // 2020_2026, 2010_2019, etc. (2020_2026, 2010_2019, etc.)
    is_supply: listingData.isSupply, // true pour les fournitures d'artisanat
    item_weight: listingData.weight || null,
    item_weight_unit: listingData.weightUnit || 'g',
    item_length: listingData.length || null,
    item_width: listingData.width || null,
    item_height: listingData.height || null,
    item_dimensions_unit: listingData.dimensionsUnit || 'mm',
    is_private: listingData.isPrivate || false,
    recipient: listingData.recipient || null, // men, women, unisex, etc. (hommes, femmes, unisexe, etc.)
    occasion: listingData.occasion || null, // birthday, wedding, etc. (anniversaire, mariage, etc.)
    style: listingData.style || [] // Max 2 styles
  };

  const response = await makeEtsyRequest(`/shops/${shopId}/listings`, {
    method: 'POST',
    body: JSON.stringify(payload)
  });

  return response;
};

// Exemple d'utilisation
const listing = await createListing(12345678, {
  title: 'Collier Phase de Lune en Argent Sterling',
  description: 'Collier en argent sterling fait à la main représentant les phases de la lune...',
  price: 89.99,
  quantity: 15,
  sku: ['LUNE-COLLIER-001'],
  tags: ['collier lune', 'argent sterling', 'phase de lune', 'bijoux célestes'],
  categoryId: 10623, // Bijoux > Colliers
  sectionId: 12345,
  state: 'active',
  whoMade: 'i_did',
  whenMade: 'made_to_order', // fait sur commande
  isSupply: false,
  weight: 25,
  weightUnit: 'g'
});

Téléchargement d'images de fiches produits

Les images sont téléchargées séparément après la création de la fiche produit :

const uploadListingImage = async (listingId, imagePath, imagePosition = 1) => {
  // Lire le fichier image en base64
  const fs = require('fs');
  const imageBuffer = fs.readFileSync(imagePath);
  const base64Image = imageBuffer.toString('base64');

  const payload = {
    image: base64Image,
    listing_image_id: null,
    position: imagePosition,
    is_watermarked: false,
    alt_text: 'Collier phase de lune en argent sterling fait main' // Pour l'accessibilité
  };

  const response = await makeEtsyRequest(`/listings/${listingId}/images`, {
    method: 'POST',
    body: JSON.stringify(payload)
  });

  return response;
};

// Télécharger plusieurs images
const uploadListingImages = async (listingId, imagePaths) => {
  const results = [];

  for (let i = 0; i < imagePaths.length; i++) {
    const result = await uploadListingImage(listingId, imagePaths[i], i + 1);
    results.push(result);
  }

  return results;
};

Mise à jour de l'inventaire des fiches produits

Mettez à jour la quantité pour les fiches produits existantes :

const updateListingInventory = async (shopId, listingId, inventory) => {
  const payload = {
    products: inventory.products.map(product => ({
      sku: product.sku,
      quantity: product.quantity
    })),
    is_over_selling: inventory.isOverSelling || false, // est_en_survente
    on_property: inventory.onProperty || []
  };

  const response = await makeEtsyRequest(
    `/shops/${shopId}/listings/${listingId}/inventory`,
    {
      method: 'PUT',
      body: JSON.stringify(payload)
    }
  );

  return response;
};

// Utilisation
await updateListingInventory(12345678, 987654321, {
  products: [
    { sku: 'LUNE-COLLIER-001', quantity: 10 },
    { sku: 'LUNE-COLLIER-002', quantity: 5 }
  ],
  isOverSelling: false
});

Récupération des fiches produits

Récupérez toutes les fiches produits ou filtrez par statut :

const getListings = async (shopId, options = {}) => {
  const params = new URLSearchParams({
    limit: options.limit || 25, // Max 100
    offset: options.offset || 0
  });

  if (options.state) {
    params.append('state', options.state); // active, inactive, draft, sold_out (actif, inactif, brouillon, épuisé)
  }

  const response = await makeEtsyRequest(
    `/shops/${shopId}/listings?${params.toString()}`,
    { method: 'GET' }
  );

  return response;
};

// Obtenir une seule fiche produit
const getListing = async (listingId) => {
  const response = await makeEtsyRequest(`/listings/${listingId}`, {
    method: 'GET'
  });

  return response;
};

Suppression d'une fiche produit

Supprimez une fiche produit de votre boutique :

const deleteListing = async (listingId) => {
  const response = await makeEtsyRequest(`/listings/${listingId}`, {
    method: 'DELETE'
  });

  return response;
};

Gestion des commandes

Récupération des commandes

Récupérez les commandes avec des options de filtrage :

const getOrders = async (shopId, options = {}) => {
  const params = new URLSearchParams({
    limit: options.limit || 25,
    offset: options.offset || 0
  });

  if (options.status) {
    params.append('status', options.status); // open, completed, cancelled (ouvert, terminé, annulé)
  }

  if (options.minLastModified) {
    params.append('min_last_modified', options.minLastModified);
  }

  const response = await makeEtsyRequest(
    `/shops/${shopId}/orders?${params.toString()}`,
    { method: 'GET' }
  );

  return response;
};

// Obtenir une seule commande
const getOrder = async (shopId, orderId) => {
  const response = await makeEtsyRequest(`/shops/${shopId}/orders/${orderId}`, {
    method: 'GET'
  });

  return response;
};

Structure de la réponse de la commande

{
  "order_id": 1234567890,
  "user_id": 98765432,
  "shop_id": 12345678,
  "buyer_user_id": 11223344,
  "creation_timestamp": 1710864000,
  "last_modified_timestamp": 1710950400,
  "completed_timestamp": 1710950400,
  "state": "complete", // état : terminé
  "user_id_fob": null,
  "is_guest": false, // est_invité : faux
  "name": "Jeanne Dupont",
  "email": "jeanne.dupont@email.com",
  "buyer_phone_number": "+33-1-23-45-67-89",
  "total_price": "89.99",
  "total_shipping_cost": "5.95",
  "total_tax": "7.65",
  "grand_total": "103.59",
  "currency_code": "USD",
  "payment_method": "credit_card", // méthode_de_paiement : carte_de_crédit
  "shipping_address": { // adresse_de_livraison
    "name": "Jeanne Dupont",
    "address_line1": "123 Rue Principale",
    "address_line2": "Appt 4B",
    "city": "Paris",
    "state": "Île-de-France",
    "zip": "75001",
    "country": "FR",
    "phone": "+33-1-23-45-67-89"
  },
  "listings": [
    {
      "listing_id": 987654321,
      "title": "Collier Phase de Lune en Argent Sterling",
      "sku": ["LUNE-COLLIER-001"],
      "quantity": 1,
      "price": "89.99"
    }
  ]
}

Mise à jour du statut de la commande

Marquez les commandes comme terminées et ajoutez le suivi :

const updateOrderStatus = async (shopId, orderId, trackingData) => {
  const payload = {
    carrier_id: trackingData.carrierId, // usps, fedex, ups, etc. (transporteur : la poste, fedex, ups, etc.)
    tracking_code: trackingData.trackingCode, // code_de_suivi
    should_send_bcc_to_buyer: trackingData.notifyBuyer || true // doit_envoyer_cc_a_l'acheteur
  };

  const response = await makeEtsyRequest(
    `/shops/${shopId}/orders/${orderId}/shipping`,
    {
      method: 'POST',
      body: JSON.stringify(payload)
    }
  );

  return response;
};

// Utilisation
await updateOrderStatus(12345678, 1234567890, {
  carrierId: 'laposte', // La Poste
  trackingCode: '9400111899223456789012',
  notifyBuyer: true // notifier l'acheteur
});

ID de transporteurs courants

Transporteur ID Transporteur
USPS usps
FedEx fedex
UPS ups
DHL dhl_express
Postes Canada canada_post
Royal Mail royal_mail
Australia Post australia_post

Limitation de débit et quotas

Comprendre les limites de débit

Etsy applique des limites de débit pour protéger la stabilité de l'API :

Dépasser les limites entraîne des réponses HTTP 429 (Too Many Requests).

Implémentation de la gestion des limites de débit

Utilisez l'attente exponentielle pour les nouvelles tentatives :

const makeRateLimitedRequest = async (endpoint, options = {}, maxRetries = 3) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await makeEtsyRequest(endpoint, options);

      // Vérifier les en-têtes de limite de débit
      const remaining = response.headers.get('x-etsy-quota-remaining'); // quota restant
      const resetTime = response.headers.get('x-etsy-quota-reset'); // temps de réinitialisation

      if (remaining < 100) {
        console.warn(`Quota faible restant : ${remaining}, réinitialisation à ${resetTime}`);
      }

      return response;
    } catch (error) {
      if (error.message.includes('429') && attempt < maxRetries) {
        // Attente exponentielle : 1s, 2s, 4s
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Limite de débit atteinte. Nouvelle tentative dans ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
};

En-têtes de limite de débit

Etsy inclut ces en-têtes dans chaque réponse :

En-tête Description
x-etsy-quota-remaining Appels restants dans l'heure actuelle
x-etsy-quota-reset Horodatage Unix de réinitialisation du quota
x-etsy-limit-remaining Appels restants dans la seconde actuelle
x-etsy-limit-reset Horodatage Unix de réinitialisation de la limite par seconde

Enregistrez toujours ces en-têtes pour la surveillance et le débogage.

Intégration des webhooks

Configuration des webhooks

Etsy prend en charge les webhooks pour les notifications d'événements en temps réel :

  1. Accédez à Vos applications dans le tableau de bord des développeurs
  2. Sélectionnez votre application
  3. Cliquez sur Ajouter un Webhook
  4. Entrez l'URL de votre point d'accès HTTPS
  5. Sélectionnez les événements auxquels vous souhaitez vous abonner

Événements de webhook disponibles

Type d'événement Déclencheur Cas d'utilisation
v3/shops/{shop_id}/orders/create Nouvelle commande passée Envoyer une confirmation, commencer l'exécution
v3/shops/{shop_id}/orders/update Statut de la commande modifié Synchroniser le statut de la commande
v3/shops/{shop_id}/listings/create Nouvelle fiche produit créée Mettre à jour l'inventaire externe
v3/shops/{shop_id}/listings/update Fiche produit modifiée Synchroniser les données du produit
v3/shops/{shop_id}/listings/delete Fiche produit supprimée Supprimer des systèmes externes

Création du gestionnaire de webhooks

const express = require('express');
const crypto = require('crypto');
const app = express();

app.post('/webhooks/etsy', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['x-etsy-signature'];
  const payload = req.body;

  // Vérifier la signature du webhook
  const isValid = verifyWebhookSignature(payload, signature, process.env.ETSY_WEBHOOK_SECRET);

  if (!isValid) {
    console.error('Signature de webhook invalide');
    return res.status(401).send('Non autorisé');
  }

  const event = JSON.parse(payload.toString());

  // Acheminer vers le gestionnaire approprié
  switch (event.type) {
    case 'v3/shops/*/orders/create':
      await handleNewOrder(event.data); // gérer la nouvelle commande
      break;
    case 'v3/shops/*/orders/update':
      await handleOrderUpdate(event.data); // gérer la mise à jour de la commande
      break;
    case 'v3/shops/*/listings/create':
      await handleListingCreated(event.data); // gérer la création de la fiche produit
      break;
    case 'v3/shops/*/listings/update':
      await handleListingUpdated(event.data); // gérer la mise à jour de la fiche produit
      break;
    case 'v3/shops/*/listings/delete':
      await handleListingDeleted(event.data); // gérer la suppression de la fiche produit
      break;
    default:
      console.log('Type d\'événement non géré :', event.type);
  }

  // Accuser réception dans les 5 secondes
  res.status(200).send('OK');
});

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature, 'hex'),
    Buffer.from(expectedSignature, 'hex')
  );
}

Bonnes pratiques pour les webhooks

  1. Vérifier les signatures - Empêche les webhooks falsifiés
  2. Retourner rapidement un 200 OK - Etsy réessaie sur les réponses non-200 dans les 5 secondes
  3. Traiter de manière asynchrone - Mettre en file d'attente les événements pour un traitement en arrière-plan
  4. Implémenter l'idempotence - Gérer les livraisons de webhooks en double
  5. Enregistrer tous les événements - Déboguer les problèmes avec une piste d'audit horodatée

Dépannage des problèmes courants

Problème : Échange de jetons OAuth échoue

Symptômes : Obtention d'erreurs 401 ou 403 lors de l'authentification.

Diagnostic :

// Vérifier la réponse d'erreur
const error = await response.json();
console.error('Erreur OAuth :', error);

Solutions :

  1. Vérifiez que l'URI de redirection correspond exactement (y compris https:// et la barre oblique finale)
  2. Confirmez que client_id et client_secret sont corrects
  3. Assurez-vous que le code d'autorisation n'a pas expiré (les codes expirent après 1 utilisation ou 5 minutes)
  4. Vérifiez que l'application est en mode production (les applications de développement ne peuvent accéder qu'aux comptes de test)

Problème : Limite de débit dépassée

Symptômes : Réception de réponses HTTP 429.

Solutions :

  1. Implémentez une file d'attente de requêtes avec limitation de débit
  2. Utilisez l'attente exponentielle pour les nouvelles tentatives
  3. Regroupez les requêtes lorsque c'est possible (par exemple, récupérer plusieurs fiches produits en un seul appel)
  4. Surveillez les en-têtes de quota et ralentissez de manière proactive
// Limiteur de débit simple
class RateLimiter {
  constructor(requestsPerSecond = 9) { // Rester sous la limite de 10/s
    this.queue = [];
    this.interval = 1000 / requestsPerSecond;
    this.processing = false;
  }

  async add(requestFn) {
    return new Promise((resolve, reject) => {
      this.queue.push({ requestFn, resolve, reject });
      this.process();
    });
  }

  async process() {
    if (this.processing || this.queue.length === 0) return;

    this.processing = true;

    while (this.queue.length > 0) {
      const { requestFn, resolve, reject } = this.queue.shift();

      try {
        const result = await requestFn();
        resolve(result);
      } catch (error) {
        reject(error);
      }

      if (this.queue.length > 0) {
        await new Promise(r => setTimeout(r, this.interval));
      }
    }

    this.processing = false;
  }
}

// Utilisation
const etsyRateLimiter = new RateLimiter(9);
const result = await etsyRateLimiter.add(() => makeEtsyRequest('/shops/12345/listings'));

Problème : La création de fiches produits échoue avec des erreurs de validation

Symptômes : 400 Bad Request avec des messages d'erreur de validation.

Causes courantes :

  1. `category_id` invalide : Utilisez l'API des catégories d'Etsy pour obtenir des ID valides
  2. Format du prix : Doit être une chaîne, pas un nombre
  3. Limite de tags : Maximum 13 tags par fiche produit
  4. Champs obligatoires manquants : title, description, price, quantity, who_made, when_made

Solution :

// Valider avant d'envoyer
const validateListing = (data) => {
  const errors = [];

  if (!data.title || data.title.length < 5) {
    errors.push('Le titre doit contenir au moins 5 caractères');
  }

  if (typeof data.price !== 'string') {
    errors.push('Le prix doit être une chaîne');
  }

  if (data.tags && data.tags.length > 13) {
    errors.push('Maximum 13 tags autorisés');
  }

  if (!['i_did', 'someone_else', 'collective'].includes(data.whoMade)) {
    errors.push('Valeur who_made invalide');
  }

  return errors;
};

Problème : Les webhooks n'arrivent pas

Symptômes : Les commandes sont traitées mais le point d'accès du webhook ne reçoit rien.

Diagnostic :

  1. Vérifiez les journaux de livraison des webhooks dans le tableau de bord du développeur
  2. Vérifiez que le point d'accès renvoie 200 OK dans les 5 secondes
  3. Testez le point d'accès manuellement avec curl

Solutions :

  1. Assurez-vous d'utiliser HTTPS avec un certificat SSL valide
  2. Ajoutez les adresses IP des webhooks Etsy à votre liste blanche dans le pare-feu
  3. Vérifiez la logique de vérification de signature
  4. Utilisez des outils de test de webhook pendant le développement

Problème : Le téléchargement d'images échoue

Symptômes : La fiche produit est créée mais les images renvoient des erreurs.

Solutions :

  1. Vérifiez que l'image est d'un format valide (JPEG, PNG, GIF)
  2. Vérifiez la taille du fichier (max 20 Mo par image)
  3. Assurez-vous que l'encodage base64 est correct
  4. Confirmez que la fiche produit existe avant de télécharger les images
  5. Téléchargez les images séquentiellement, pas en parallèle

Liste de contrôle pour le déploiement en production

Avant de passer en ligne :

Surveillance et alertes

Suivez ces métriques :

// Exemple de métriques à suivre
const metrics = {
  apiCalls: { // appels API
    total: 0,
    successful: 0, // réussis
    failed: 0, // échoués
    rateLimited: 0 // limités en débit
  },
  quotaUsage: { // utilisation du quota
    current: 0, // actuel
    limit: 10000,
    resetTime: null // temps de réinitialisation
  },
  oauthTokens: { // jetons OAuth
    active: 0, // actifs
    expiring_soon: 0, // expirant bientôt
    refresh_failures: 0 // échecs de rafraîchissement
  },
  webhooks: {
    received: 0, // reçus
    processed: 0, // traités
    failed: 0 // échoués
  }
};

// Alerte en cas de taux d'échec élevé
const failureRate = metrics.apiCalls.failed / metrics.apiCalls.total;

if (failureRate > 0.05) { // Plus de 5% de taux d'échec
  sendAlert('Taux d\'échec de l\'API Etsy supérieur à 5%');
}

// Alerte en cas de quota faible
if (metrics.quotaUsage.current < 500) {
  sendAlert('Quota API Etsy inférieur à 500 appels restants');
}

Cas d'utilisation réels

Synchronisation des stocks multicanal

Un vendeur de décoration intérieure utilise l'API Etsy pour synchroniser les stocks entre Etsy, Shopify et Amazon :

Flux d'implémentation :

  1. Le webhook Etsy se déclenche à la création d'une commande
  2. Le système central décrémente l'inventaire
  3. Les appels API mettent à jour les quantités sur Shopify et Amazon
  4. La confirmation est enregistrée dans la base de données

Exécution automatisée des commandes

Une entreprise d'impression à la demande automatise le traitement des commandes :

Points d'intégration clés :

Tableau de bord analytique

Un outil d'analyse pour vendeurs agrège les données de plusieurs boutiques :

Données collectées via l'API :

Conclusion

L'API Etsy offre un accès complet aux fonctionnalités du marché. Points clés à retenir :

télécharger l'application

Section FAQ

À quoi sert l'API Etsy ?

L'API Etsy permet aux développeurs de créer des applications qui interagissent avec la marketplace d'Etsy. Les cas d'utilisation courants incluent la gestion des stocks sur plusieurs canaux de vente, l'exécution automatisée des commandes, les tableaux de bord analytiques, les outils de création de fiches produits et les systèmes de gestion de la relation client.

Comment obtenir une clé API Etsy ?

Créez un compte sur le Portail des développeurs Etsy, accédez à Vos applications et cliquez sur Créer une nouvelle application. Après l'enregistrement, vous recevrez une chaîne de clé (identifiant public) et un secret partagé (clé privée). Stockez les deux en toute sécurité à l'aide de variables d'environnement.

L'API Etsy est-elle gratuite ?

Oui, l'API Etsy est gratuite pour les développeurs. Cependant, des limites de débit s'appliquent : 10 requêtes par seconde et 10 000 appels par heure et par application. Des limites plus élevées nécessitent l'approbation d'Etsy pour des cas d'utilisation spécifiques.

Quelle authentification l'API Etsy utilise-t-elle ?

Etsy utilise OAuth 2.0 pour l'authentification. Les utilisateurs autorisent votre application via la page d'autorisation d'Etsy, et votre application reçoit un jeton d'accès (valide pendant 1 heure) et un jeton de rafraîchissement (pour obtenir de nouveaux jetons d'accès).

Comment gérer les limites de débit de l'API Etsy ?

Implémentez une file d'attente de requêtes pour rester en dessous de 10 requêtes par seconde. Surveillez l'en-tête x-etsy-quota-remaining pour suivre l'utilisation horaire. Utilisez l'attente exponentielle lors de la réception de réponses HTTP 429 (Too Many Requests).

Puis-je tester l'API Etsy sans une boutique réelle ?

Oui. Les applications en mode développement peuvent se connecter à des boutiques de test pour l'intégration. Créez un compte Etsy de test et utilisez-le pour authentifier votre application de développement sans affecter les données réelles.

Comment fonctionnent les webhooks avec l'API Etsy ?

Les webhooks Etsy envoient des requêtes POST à votre point d'accès HTTPS lorsque des événements se produisent (nouvelles commandes, mises à jour des fiches produits). Configurez les webhooks dans le tableau de bord de votre application, implémentez la vérification de signature et renvoyez un 200 OK dans les 5 secondes.

Que se passe-t-il lorsque le jeton OAuth Etsy expire ?

Les jetons d'accès expirent après 1 heure. Utilisez le jeton de rafraîchissement pour obtenir un nouveau jeton d'accès avant l'expiration. Implémentez un rafraîchissement automatique des jetons dans votre middleware pour éviter les échecs d'authentification lors des appels API.

Puis-je télécharger des images de fiches produits via l'API ?

Oui. Les images sont téléchargées sous forme de chaînes encodées en base64 dans un appel API distinct après la création de la fiche produit. Chaque image peut peser jusqu'à 20 Mo et doit être au format JPEG, PNG ou GIF.

Comment migrer de l'API Etsy V2 vers la V3 ?

La V3 utilise OAuth 2.0 au lieu d'OAuth 1.0a et possède une structure de point d'accès différente. Mettez à jour le flux d'authentification, modifiez les chemins des points d'accès de /v2/ à /v3/application/, et testez minutieusement avant le retrait de la V2 fin 2026.

Pratiquez le Design-first d'API dans Apidog

Découvrez une manière plus simple de créer et utiliser des API