TL;DR
Die Etsy API ermöglicht Entwicklern, Anwendungen zu erstellen, die mit dem Etsy-Marktplatz interagieren. Sie verwendet OAuth 2.0-Authentifizierung, RESTful-Endpunkte für Shops, Angebote, Bestellungen und Bestandsverwaltung, mit Ratenbegrenzungen von 10 Aufrufen pro Sekunde pro App. Dieser Leitfaden behandelt die Einrichtung der Authentifizierung, Kern-Endpunkte, Webhook-Integration und Strategien für die Bereitstellung in der Produktion.
Einleitung
Etsy wickelt jährliche Bruttowarenverkäufe von über 13 Milliarden US-Dollar in über 230 Ländern ab. Für Entwickler, die E-Commerce-Tools, Bestandsverwaltungssysteme oder Analyseplattformen erstellen, ist die Integration der Etsy API nicht optional – sie ist unerlässlich.
Hier ist die Realität: Verkäufer, die mehrere Vertriebskanäle verwalten, verlieren 15-20 Stunden pro Woche durch manuelle Dateneingabe. Eine solide Etsy API-Integration automatisiert die Angebotssynchronisierung, Auftragsabwicklung und Bestandsaktualisierungen über Plattformen hinweg.
Dieser Leitfaden führt Sie durch den gesamten Etsy API-Integrationsprozess. Sie lernen OAuth 2.0-Authentifizierung, Shop- und Angebotsverwaltung, Auftragsabwicklung, Webhook-Verwaltung und Fehlerbehebung. Am Ende verfügen Sie über eine produktionsreife Etsy-Integration.
Was ist die Etsy API?
Etsy bietet eine RESTful API für den Zugriff auf Marktplatzdaten und die Verwaltung von Verkäuferoperationen. Die API übernimmt:
- Abruf von Shop- und Profilinformationen
- Erstellung und Aktualisierung von Angeboten sowie Bestandsverwaltung
- Auftragsabwicklung und Verfolgung der Ausführung
- Zugriff auf Kunden- und Transaktionsdaten
- Versandprofile und Steuerberechnungen
- Verwaltung von Bild- und Medien-Uploads
Hauptmerkmale
| Merkmal | Beschreibung |
|---|---|
| RESTful Design | Standard-HTTP-Methoden mit JSON-Antworten |
| OAuth 2.0 | Sichere Authentifizierung mit Access Token-Aktualisierung |
| Webhooks | Echtzeitbenachrichtigungen für Bestell- und Angebotsereignisse |
| Ratenbegrenzung | 10 Anfragen pro Sekunde pro App (mit Spitzen-Guthaben) |
| Sandbox-Unterstützung | Testumgebung für die Entwicklung ohne Live-Daten |
Übersicht über die API-Architektur
Etsy verwendet eine versionierte REST API-Struktur:
https://openapi.etsy.com/v3/application/
Version 3 (v3) ist der aktuelle Standard und bietet im Vergleich zu v2 verbesserte OAuth 2.0-Unterstützung und vereinfachte Endpunktstrukturen.
API-Versionen im Vergleich
| Version | Status | Authentifizierung | Anwendungsfall |
|---|---|---|---|
| V3 | Aktuell | OAuth 2.0 | Alle neuen Integrationen |
| V2 | Veraltet | OAuth 1.0a | Nur Legacy-Anwendungen |
| V1 | Eingestellt | N/A | Nicht verwenden |
Migrieren Sie alle V2-Integrationen sofort auf V3. Etsy hat die V2-Veralterung mit der vollständigen Einstellung für Ende 2026 angekündigt.
Erste Schritte: Authentifizierung einrichten
Schritt 1: Etsy-Entwicklerkonto erstellen
Bevor Sie auf die API zugreifen können, benötigen Sie ein Entwicklerkonto:
- Besuchen Sie das Etsy Developer Portal
- Melden Sie sich mit Ihrem Etsy-Konto an (oder erstellen Sie eines)
- Navigieren Sie in Ihrem Entwickler-Dashboard zu Ihre Apps
- Klicken Sie auf Neue App erstellen
Schritt 2: Ihre Anwendung registrieren
Füllen Sie das Registrierungsformular für die App aus:
- App-Name: Klarer, aussagekräftiger Name (für Benutzer während OAuth sichtbar)
- App-Beschreibung: Erklären Sie, was Ihre App tut und wer sie verwendet
- Redirect-URI: Wohin Etsy Benutzer nach der Authentifizierung sendet (muss HTTPS verwenden)
- Produktion/Entwicklung: Beginnen Sie mit dem Entwicklungsmodus zum Testen
Nach der Übermittlung erhalten Sie:
- Key String: Ihre öffentliche API-Kennung
- Shared Secret: Ihr privater API-Schlüssel (niemals offenlegen)
Sicherheitshinweis: Speichern Sie Anmeldeinformationen in Umgebungsvariablen, niemals im Code:
# .env-Datei
ETSY_KEY_STRING="ihr_key_string_hier"
ETSY_SHARED_SECRET="ihr_shared_secret_hier"
ETSY_ACCESS_TOKEN="generiert_via_oauth"
ETSY_REFRESH_TOKEN="generiert_via_oauth"
Schritt 3: OAuth 2.0-Fluss verstehen
Etsy verwendet OAuth 2.0 zur Authentifizierung. Hier ist der vollständige Ablauf:
1. Benutzer klickt in Ihrer App auf "Mit Etsy verbinden"
2. Ihre App leitet zur Etsy-Autorisierungs-URL weiter
3. Benutzer meldet sich an und erteilt Berechtigungen
4. Etsy leitet mit Autorisierungscode zurück
5. Ihre App tauscht Code gegen Access Token aus
6. Ihre App verwendet Access Token für API-Aufrufe
7. Refresh Token, wenn Access Token abläuft (1 Stunde)
Schritt 4: OAuth-Autorisierung implementieren
Generieren Sie die Autorisierungs-URL:
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, // Zufälliger String für CSRF-Schutz
response_type: 'code'
});
return `${baseUrl}?${params.toString()}`;
};
// Verwendung
const authUrl = generateAuthUrl(
process.env.ETSY_KEY_STRING,
'https://ihre-app.com/callback',
crypto.randomBytes(16).toString('hex')
);
console.log(`Benutzer weiterleiten zu: ${authUrl}`);
Erforderliche Scopes
Fordern Sie nur die Berechtigungen an, die Ihre App benötigt:
| Scope | Beschreibung | Anwendungsfall |
|---|---|---|
listings_r |
Angebote lesen | Produkte anzeigen, Inventar synchronisieren |
listings_w |
Angebote schreiben | Produkte erstellen/aktualisieren |
orders_r |
Bestellungen lesen | Bestellverwaltung, Abwicklung |
orders_w |
Bestellungen schreiben | Bestellstatus aktualisieren, Sendungsverfolgung hinzufügen |
shops_r |
Shop-Informationen lesen | Shop-Profil anzeigen, Analysen |
transactions_r |
Transaktionen lesen | Finanzberichte |
email |
Käufer-E-Mail-Adresse zugreifen | Bestellkommunikation |
Schritt 5: Code gegen Access Token austauschen
Verwalten Sie den OAuth-Callback und tauschen Sie den Autorisierungscode aus:
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();
// Speichern Sie diese sicher in Ihrer Datenbank
return {
access_token: data.access_token,
refresh_token: data.refresh_token,
expires_in: data.expires_in, // Typischerweise 3600 Sekunden (1 Stunde)
user_id: data.user_id,
scope: data.scope
};
};
// Callback-Route verarbeiten
app.get('/callback', async (req, res) => {
const { code, state } = req.query;
// Überprüfen Sie, ob der Zustand mit dem gesendeten übereinstimmt (CSRF-Schutz)
if (state !== req.session.oauthState) {
return res.status(400).send('Ungültiger Zustands-Parameter');
}
try {
const tokens = await exchangeCodeForToken(code, 'https://ihre-app.com/callback');
// Token in Datenbank speichern, die mit dem Benutzer verknüpft ist
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('/dashboard');
} catch (error) {
console.error('Token-Austausch fehlgeschlagen:', error);
res.status(500).send('Authentifizierung fehlgeschlagen');
}
});
Schritt 6: Token-Refresh implementieren
Access Tokens laufen nach 1 Stunde ab. Implementieren Sie eine automatische Aktualisierung:
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();
// Gespeicherte Token aktualisieren
return {
access_token: data.access_token,
refresh_token: data.refresh_token, // Immer den neuen Refresh Token speichern
expires_in: data.expires_in
};
};
// Middleware zur Sicherstellung eines gültigen Tokens vor API-Aufrufen
const ensureValidToken = async (userId) => {
const user = await db.users.findById(userId);
// Prüfen, ob das Token innerhalb von 5 Minuten abläuft
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;
};
Schritt 7: Authentifizierte API-Aufrufe durchführen
Fügen Sie den Access Token in jede Anfrage ein:
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(`Etsy API Fehler: ${error.message}`);
}
return response.json();
};
Shop-Management-Endpunkte
Shop-Informationen abrufen
Shop-Details, Richtlinien und Einstellungen abrufen:
const getShopInfo = async (shopId) => {
const response = await makeEtsyRequest(`/shops/${shopId}`, {
method: 'GET'
});
return response;
};
// Verwendung
const shop = await getShopInfo(12345678);
console.log(`Shop: ${shop.title}`);
console.log(`Währung: ${shop.currency_code}`);
console.log(`Anzahl Angebote: ${shop.num_listings_active}`);
Erwartete Shop-Antwort
{
"shop_id": 12345678,
"shop_name": "MyHandmadeShop",
"title": "Handgemachter Schmuck & Accessoires",
"announcement": "Willkommen! Kostenloser Versand für Bestellungen über 50 $",
"currency_code": "USD",
"is_vacation": false,
"vacation_message": null,
"sale_message": "Vielen Dank für die Unterstützung kleiner Unternehmen!",
"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"
}
Shop-Kategorien abrufen
Angebote nach Kategorien organisieren:
const getShopSections = async (shopId) => {
const response = await makeEtsyRequest(`/shops/${shopId}/sections`, {
method: 'GET'
});
return response;
};
// Beispielantwort
{
"count": 5,
"results": [
{
"shop_section_id": 12345,
"title": "Halsketten",
"rank": 1,
"num_listings": 23
},
{
"shop_section_id": 12346,
"title": "Ohrringe",
"rank": 2,
"num_listings": 45
}
]
}
Angebotsverwaltung
Neues Angebot erstellen
Ein Produktangebot mit Bildern und Variationen erstellen:
const createListing = async (shopId, listingData) => {
const payload = {
title: listingData.title,
description: listingData.description,
price: listingData.price.toString(), // Muss ein String sein
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
when_made: listingData.whenMade, // 2020_2026, 2010_2019, etc.
is_supply: listingData.isSupply, // true für Bastelmaterial
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.
occasion: listingData.occasion || null, // birthday, wedding, etc.
style: listingData.style || [] // Max. 2 Stile
};
const response = await makeEtsyRequest(`/shops/${shopId}/listings`, {
method: 'POST',
body: JSON.stringify(payload)
});
return response;
};
// Verwendungsbeispiel
const listing = await createListing(12345678, {
title: 'Halskette mit Mondphasen aus Sterlingsilber',
description: 'Handgefertigte Halskette aus Sterlingsilber mit Mondphasen...',
price: 89.99,
quantity: 15,
sku: ['MOON-NECKLACE-001'],
tags: ['Mondkette', 'Sterlingsilber', 'Mondphase', 'himmlischer Schmuck'],
categoryId: 10623, // Schmuck > Halsketten
sectionId: 12345,
state: 'active',
whoMade: 'i_did',
whenMade: 'made_to_order',
isSupply: false,
weight: 25,
weightUnit: 'g'
});
Angebotsbilder hochladen
Bilder werden separat nach der Angebotserstellung hochgeladen:
const uploadListingImage = async (listingId, imagePath, imagePosition = 1) => {
// Bilddatei als Base64 lesen
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: 'Handgefertigte Halskette mit Mondphasen aus Sterlingsilber' // Für Barrierefreiheit
};
const response = await makeEtsyRequest(`/listings/${listingId}/images`, {
method: 'POST',
body: JSON.stringify(payload)
});
return response;
};
// Mehrere Bilder hochladen
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;
};
Angebotsbestand aktualisieren
Menge für bestehende Angebote aktualisieren:
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,
on_property: inventory.onProperty || []
};
const response = await makeEtsyRequest(
`/shops/${shopId}/listings/${listingId}/inventory`,
{
method: 'PUT',
body: JSON.stringify(payload)
}
);
return response;
};
// Verwendung
await updateListingInventory(12345678, 987654321, {
products: [
{ sku: 'MOON-NECKLACE-001', quantity: 10 },
{ sku: 'MOON-NECKLACE-002', quantity: 5 }
],
isOverSelling: false
});
Angebote abrufen
Alle Angebote abrufen oder nach Status filtern:
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
}
const response = await makeEtsyRequest(
`/shops/${shopId}/listings?${params.toString()}`,
{ method: 'GET' }
);
return response;
};
// Ein einzelnes Angebot abrufen
const getListing = async (listingId) => {
const response = await makeEtsyRequest(`/listings/${listingId}`, {
method: 'GET'
});
return response;
};
Angebot löschen
Ein Angebot aus Ihrem Shop entfernen:
const deleteListing = async (listingId) => {
const response = await makeEtsyRequest(`/listings/${listingId}`, {
method: 'DELETE'
});
return response;
};
Bestellverwaltung
Bestellungen abrufen
Bestellungen mit Filteroptionen abrufen:
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
}
if (options.minLastModified) {
params.append('min_last_modified', options.minLastModified);
}
const response = await makeEtsyRequest(
`/shops/${shopId}/orders?${params.toString()}`,
{ method: 'GET' }
);
return response;
};
// Eine einzelne Bestellung abrufen
const getOrder = async (shopId, orderId) => {
const response = await makeEtsyRequest(`/shops/${shopId}/orders/${orderId}`, {
method: 'GET'
});
return response;
};
Bestellungsantwort-Struktur
{
"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",
"user_id_fob": null,
"is_guest": false,
"name": "Jane Doe",
"email": "jane.doe@email.com",
"buyer_phone_number": "+1-555-0123",
"total_price": "89.99",
"total_shipping_cost": "5.95",
"total_tax": "7.65",
"grand_total": "103.59",
"currency_code": "USD",
"payment_method": "credit_card",
"shipping_address": {
"name": "Jane Doe",
"address_line1": "123 Main Street",
"address_line2": "Apt 4B",
"city": "New York",
"state": "NY",
"zip": "10001",
"country": "US",
"phone": "+1-555-0123"
},
"listings": [
{
"listing_id": 987654321,
"title": "Halskette mit Mondphasen aus Sterlingsilber",
"sku": ["MOON-NECKLACE-001"],
"quantity": 1,
"price": "89.99"
}
]
}
Bestellstatus aktualisieren
Bestellungen als abgeschlossen markieren und Sendungsverfolgung hinzufügen:
const updateOrderStatus = async (shopId, orderId, trackingData) => {
const payload = {
carrier_id: trackingData.carrierId, // usps, fedex, ups, etc.
tracking_code: trackingData.trackingCode,
should_send_bcc_to_buyer: trackingData.notifyBuyer || true
};
const response = await makeEtsyRequest(
`/shops/${shopId}/orders/${orderId}/shipping`,
{
method: 'POST',
body: JSON.stringify(payload)
}
);
return response;
};
// Verwendung
await updateOrderStatus(12345678, 1234567890, {
carrierId: 'usps',
trackingCode: '9400111899223456789012',
notifyBuyer: true
});
Gängige Spediteur-IDs
| Spediteur | Carrier ID |
|---|---|
| USPS | usps |
| FedEx | fedex |
| UPS | ups |
| DHL | dhl_express |
| Canada Post | canada_post |
| Royal Mail | royal_mail |
| Australia Post | australia_post |
Ratenbegrenzung und Quotas
Ratenbegrenzungen verstehen
Etsy erzwingt Ratenbegrenzungen, um die API-Stabilität zu schützen:
- Standardlimit: 10 Anfragen pro Sekunde pro App
- Spitzen-Guthaben: Bis zu 50 Anfragen in einer einzelnen Sekunde (kurze Spitzen)
- Quota-System: 10.000 Aufrufe pro Stunde pro App (wird stündlich zurückgesetzt)
Das Überschreiten der Limits führt zu HTTP 429 (Too Many Requests) Antworten.
Umgang mit Ratenbegrenzungen implementieren
Verwenden Sie exponentielles Backoff für Wiederholungsversuche:
const makeRateLimitedRequest = async (endpoint, options = {}, maxRetries = 3) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await makeEtsyRequest(endpoint, options);
// Ratenbegrenzungs-Header prüfen
const remaining = response.headers.get('x-etsy-quota-remaining');
const resetTime = response.headers.get('x-etsy-quota-reset');
if (remaining < 100) {
console.warn(`Niedriges Quota verbleibend: ${remaining}, setzt sich zurück um ${resetTime}`);
}
return response;
} catch (error) {
if (error.message.includes('429') && attempt < maxRetries) {
// Exponentielles Backoff: 1s, 2s, 4s
const delay = Math.pow(2, attempt) * 1000;
console.log(`Ratenbegrenzung. Wiederholung in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
};
Ratenbegrenzung-Header
Etsy enthält diese Header in jeder Antwort:
| Header | Beschreibung |
|---|---|
x-etsy-quota-remaining |
Verbleibende Aufrufe in der aktuellen Stunde |
x-etsy-quota-reset |
Unix-Zeitstempel, wann das Quota zurückgesetzt wird |
x-etsy-limit-remaining |
Verbleibende Aufrufe in der aktuellen Sekunde |
x-etsy-limit-reset |
Unix-Zeitstempel, wann das Limit pro Sekunde zurückgesetzt wird |
Protokollieren Sie diese Header immer zur Überwachung und Fehlerbehebung.
Webhook-Integration
Webhooks konfigurieren
Etsy unterstützt Webhooks für Echtzeit-Ereignisbenachrichtigungen:
- Navigieren Sie in Ihrem Entwickler-Dashboard zu Ihre Apps
- Wählen Sie Ihre App aus
- Klicken Sie auf Webhook hinzufügen
- Geben Sie Ihre HTTPS-Endpunkt-URL ein
- Wählen Sie die Ereignisse aus, die Sie abonnieren möchten
Verfügbare Webhook-Ereignisse
| Ereignistyp | Auslöser | Anwendungsfall |
|---|---|---|
v3/shops/{shop_id}/orders/create |
Neue Bestellung aufgegeben | Bestätigung senden, Ausführung beginnen |
v3/shops/{shop_id}/orders/update |
Bestellstatus geändert | Bestellstatus synchronisieren |
v3/shops/{shop_id}/listings/create |
Neues Angebot erstellt | Externen Bestand aktualisieren |
v3/shops/{shop_id}/listings/update |
Angebot geändert | Produktdaten synchronisieren |
v3/shops/{shop_id}/listings/delete |
Angebot entfernt | Aus externen Systemen entfernen |
Webhook-Handler erstellen
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;
// Webhook-Signatur verifizieren
const isValid = verifyWebhookSignature(payload, signature, process.env.ETSY_WEBHOOK_SECRET);
if (!isValid) {
console.error('Ungültige Webhook-Signatur');
return res.status(401).send('Nicht autorisiert');
}
const event = JSON.parse(payload.toString());
// An den entsprechenden Handler weiterleiten
switch (event.type) {
case 'v3/shops/*/orders/create':
await handleNewOrder(event.data);
break;
case 'v3/shops/*/orders/update':
await handleOrderUpdate(event.data);
break;
case 'v3/shops/*/listings/create':
await handleListingCreated(event.data);
break;
case 'v3/shops/*/listings/update':
await handleListingUpdated(event.data);
break;
case 'v3/shops/*/listings/delete':
await handleListingDeleted(event.data);
break;
default:
console.log('Unbehandelter Ereignistyp:', event.type);
}
// Empfang innerhalb von 5 Sekunden bestätigen
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')
);
}
Best Practices für Webhooks
- Signaturen verifizieren - Verhindert gefälschte Webhooks
- Schnell 200 OK zurückgeben - Etsy versucht bei Nicht-200-Antworten innerhalb von 5 Sekunden erneut
- Asynchron verarbeiten - Ereignisse für die Hintergrundverarbeitung in eine Warteschlange stellen
- Idempotenz implementieren - Doppelte Webhook-Zustellungen behandeln
- Alle Ereignisse protokollieren - Probleme mit einem zeitgestempelten Audit-Trail debuggen
Fehlerbehebung bei häufigen Problemen
Problem: OAuth-Token-Austausch schlägt fehl
Symptome: Erhalten von 401- oder 403-Fehlern während der Authentifizierung.
Diagnose:
// Fehlerantwort prüfen
const error = await response.json();
console.error('OAuth-Fehler:', error);
Lösungen:
- Stellen Sie sicher, dass die Redirect-URI exakt übereinstimmt (einschließlich https:// und nachfolgendem Schrägstrich)
- Bestätigen Sie, dass client_id und client_secret korrekt sind
- Stellen Sie sicher, dass der Autorisierungscode nicht abgelaufen ist (Codes verfallen nach 1 Verwendung oder 5 Minuten)
- Überprüfen Sie, ob die App im Produktionsmodus ist (Entwicklungs-Apps können nur auf Testkonten zugreifen)
Problem: Ratenbegrenzung überschritten
Symptome: Erhalten von HTTP 429-Antworten.
Lösungen:
- Implementieren Sie eine Anfragewarteschlange mit Ratenbegrenzung
- Verwenden Sie exponentielles Backoff für Wiederholungsversuche
- Fassen Sie Anfragen, wo möglich, zusammen (z. B. mehrere Angebote in einem Aufruf abrufen)
- Überwachen Sie Quota-Header und drosseln Sie proaktiv
// Einfacher Ratenbegrenzer
class RateLimiter {
constructor(requestsPerSecond = 9) { // Unter dem 10/s Limit bleiben
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;
}
}
// Verwendung
const etsyRateLimiter = new RateLimiter(9);
const result = await etsyRateLimiter.add(() => makeEtsyRequest('/shops/12345/listings'));
Problem: Angebotserstellung schlägt mit Validierungsfehlern fehl
Symptome: 400 Bad Request mit Validierungsfehlermeldungen.
Häufige Ursachen:
- Ungültige category_id: Verwenden Sie die Kategorien-API von Etsy, um gültige IDs zu erhalten
- Preisformat: Muss ein String sein, keine Zahl
- Tag-Limit: Maximal 13 Tags pro Angebot
- Erforderliche Felder fehlen: title, description, price, quantity, who_made, when_made
Lösung:
// Vor dem Senden validieren
const validateListing = (data) => {
const errors = [];
if (!data.title || data.title.length < 5) {
errors.push('Titel muss mindestens 5 Zeichen lang sein');
}
if (typeof data.price !== 'string') {
errors.push('Preis muss ein String sein');
}
if (data.tags && data.tags.length > 13) {
errors.push('Maximal 13 Tags erlaubt');
}
if (!['i_did', 'someone_else', 'collective'].includes(data.whoMade)) {
errors.push('Ungültiger Wert für who_made');
}
return errors;
};
Problem: Webhooks kommen nicht an
Symptome: Bestellungen werden verarbeitet, aber der Webhook-Endpunkt empfängt nichts.
Diagnose:
- Überprüfen Sie die Webhook-Zustellungsprotokolle im Entwickler-Dashboard
- Verifizieren Sie, dass der Endpunkt innerhalb von 5 Sekunden 200 OK zurückgibt
- Testen Sie den Endpunkt manuell mit curl
Lösungen:
- Sicherstellen, dass HTTPS mit gültigem SSL-Zertifikat verwendet wird
- Etsy Webhook-IPs in der Firewall zulassen
- Überprüfen Sie die Signaturüberprüfungslogik
- Verwenden Sie Webhook-Testtools während der Entwicklung
Problem: Bilder können nicht hochgeladen werden
Symptome: Angebot wird erstellt, aber Bilder geben Fehler zurück.
Lösungen:
- Überprüfen Sie, ob das Bild ein gültiges Format (JPEG, PNG, GIF) hat
- Überprüfen Sie die Dateigröße (max. 20 MB pro Bild)
- Stellen Sie sicher, dass die Base64-Kodierung korrekt ist
- Bestätigen Sie, dass das Angebot existiert, bevor Sie Bilder hochladen
- Laden Sie Bilder nacheinander hoch, nicht parallel
Checkliste für die Produktionsbereitstellung
Vor der Live-Schaltung:
- [ ] Wechseln Sie vom Entwicklungs- zum Produktions-App-Modus
- [ ] Aktualisieren Sie alle Redirect-URIs auf Produktions-URLs
- [ ] Implementieren Sie eine sichere Token-Speicherung (verschlüsselte Datenbank)
- [ ] Fügen Sie eine Logik zur automatischen Token-Aktualisierung hinzu
- [ ] Richten Sie Ratenbegrenzung und Anfragewarteschlange ein
- [ ] Konfigurieren Sie den Webhook-Endpunkt mit HTTPS
- [ ] Implementieren Sie eine umfassende Fehlerbehandlung
- [ ] Fügen Sie Protokollierung für alle API-Aufrufe hinzu
- [ ] Richten Sie die Überwachung der Quota-Nutzung ein
- [ ] Erstellen Sie ein Handbuch für häufige Probleme
- [ ] Testen Sie mit mehreren Shop-Konten
- [ ] Dokumentieren Sie den OAuth-Fluss für das Benutzer-Onboarding
Überwachung und Alarmierung
Verfolgen Sie diese Metriken:
// Beispielmetriken zur Verfolgung
const metrics = {
apiCalls: {
total: 0,
successful: 0,
failed: 0,
rateLimited: 0
},
quotaUsage: {
current: 0,
limit: 10000,
resetTime: null
},
oauthTokens: {
active: 0,
expiring_soon: 0,
refresh_failures: 0
},
webhooks: {
received: 0,
processed: 0,
failed: 0
}
};
// Alarm bei hoher Fehlerquote
const failureRate = metrics.apiCalls.failed / metrics.apiCalls.total;
if (failureRate > 0.05) { // Mehr als 5% Fehlerquote
sendAlert('Etsy API Fehlerquote über 5%');
}
// Alarm bei niedrigem Quota
if (metrics.quotaUsage.current < 500) {
sendAlert('Etsy API Quota unter 500 Aufrufen verbleibend');
}
Praktische Anwendungsfälle
Mehrkanal-Bestandssynchronisierung
Ein Verkäufer von Wohnaccessoires nutzt die Etsy API, um den Bestand über Etsy, Shopify und Amazon hinweg zu synchronisieren:
- Herausforderung: Manuelle Bestandsaktualisierungen führten zu Überverkäufen
- Lösung: Zentrales Bestandssystem mit Etsy API-Webhooks
- Ergebnis: Keine Überverkäufe, 12 Stunden/Woche Zeitersparnis
Implementierungsfluss:
- Etsy-Webhook löst bei Bestellerstellung aus
- Zentrales System reduziert den Bestand
- API-Aufrufe aktualisieren Shopify- und Amazon-Mengen
- Bestätigung wird in der Datenbank protokolliert
Automatisierte Auftragsabwicklung
Ein Print-on-Demand-Unternehmen automatisiert die Auftragsabwicklung:
- Herausforderung: Über 50 tägliche Bestellungen erforderten manuelle Dateneingabe
- Lösung: Etsy API-Integration mit Fulfillment-Anbieter
- Ergebnis: Bestellungen werden innerhalb von 5 Minuten automatisch an die Produktion weitergeleitet
Wichtige Integrationspunkte:
- Webhook lauscht auf
orders/create-Ereignisse - Bestelldetails werden an die API des Druckanbieters gesendet
- Sendungsverfolgungsnummer wird zurückgegeben und über die Etsy API aktualisiert
- Kunde erhält automatische Versandbenachrichtigung
Analyse-Dashboard
Ein Analysetool für Verkäufer aggregiert Daten aus mehreren Shops:
- Herausforderung: Verkäufern mit mehreren Shops fehlte eine einheitliche Berichterstattung
- Lösung: OAuth-basierte Datenaggregation über mehrere Shops
- Ergebnis: Echtzeit-Dashboard mit Verkaufs-, Traffic- und Konversionsmetriken
Über die API gesammelte Daten:
- Shop-Statistiken (Angebote, Verkäufe, Umsatz)
- Bestellhistorie und Trends
- Angebotsleistungsmetriken
- Kundenbewertungsdaten
Fazit
Die Etsy API bietet umfassenden Zugriff auf die Marktplatzfunktionalität. Wichtige Erkenntnisse:
- OAuth 2.0-Authentifizierung erfordert eine sorgfältige Token-Verwaltung und automatische Aktualisierung
- Ratenbegrenzung (10 Anfragen/Sek., 10.000/Stunde) erfordert proaktive Überwachung und Warteschlangenbildung
- Webhooks ermöglichen eine Echtzeit-Bestell- und Bestandsynchronisierung
- Eine ordnungsgemäße Fehlerbehandlung und Wiederholungslogik sind für die Zuverlässigkeit in der Produktion unerlässlich
- Apidog optimiert API-Tests und Teamzusammenarbeit für Etsy-Integrationen
FAQ-Bereich
Wofür wird die Etsy API verwendet?
Die Etsy API ermöglicht es Entwicklern, Anwendungen zu erstellen, die mit dem Etsy-Marktplatz interagieren. Gängige Anwendungsfälle sind die Bestandsverwaltung über mehrere Vertriebskanäle hinweg, die automatisierte Auftragsabwicklung, Analyse-Dashboards, Tools zur Angebotserstellung und Kundenbeziehungsmanagementsysteme.
Wie erhalte ich einen Etsy API-Schlüssel?
Erstellen Sie ein Konto im Etsy Developer Portal, navigieren Sie zu Ihre Apps und klicken Sie auf Neue App erstellen. Nach der Registrierung erhalten Sie einen Key String (öffentliche Kennung) und ein Shared Secret (privater Schlüssel). Speichern Sie beides sicher mithilfe von Umgebungsvariablen.
Ist die Etsy API kostenlos nutzbar?
Ja, die Etsy API ist für Entwickler kostenlos. Es gelten jedoch Ratenbegrenzungen: 10 Anfragen pro Sekunde und 10.000 Aufrufe pro Stunde pro App. Höhere Limits erfordern die Genehmigung von Etsy für spezifische Anwendungsfälle.
Welche Authentifizierung verwendet die Etsy API?
Etsy verwendet OAuth 2.0 zur Authentifizierung. Benutzer autorisieren Ihre App über die Etsy-Autorisierungsseite, und Ihre App erhält einen Access Token (gültig für 1 Stunde) und einen Refresh Token (zum Abrufen neuer Access Tokens).
Wie gehe ich mit Etsy API-Ratenbegrenzungen um?
Implementieren Sie eine Anfragewarteschlange, um unter 10 Anfragen pro Sekunde zu bleiben. Überwachen Sie den Header x-etsy-quota-remaining, um die stündliche Nutzung zu verfolgen. Verwenden Sie exponentielles Backoff, wenn Sie HTTP 429 (Too Many Requests) Antworten erhalten.
Kann ich die Etsy API ohne einen Live-Shop testen?
Ja. Apps im Entwicklungsmodus können sich mit Test-Shops verbinden, um Integrationstests durchzuführen. Erstellen Sie ein Test-Etsy-Konto und verwenden Sie es zur Authentifizierung Ihrer Entwicklungs-App, ohne Live-Daten zu beeinflussen.
Wie funktionieren Webhooks mit der Etsy API?
Etsy-Webhooks senden POST-Anfragen an Ihren HTTPS-Endpunkt, wenn Ereignisse auftreten (neue Bestellungen, Angebotsaktualisierungen). Konfigurieren Sie Webhooks in Ihrem App-Dashboard, implementieren Sie die Signaturüberprüfung und geben Sie innerhalb von 5 Sekunden 200 OK zurück.
Was passiert, wenn ein Etsy OAuth Token abläuft?
Access Tokens verfallen nach 1 Stunde. Verwenden Sie den Refresh Token, um vor dem Ablauf einen neuen Access Token zu erhalten. Implementieren Sie eine automatische Token-Aktualisierung in Ihrer Middleware, um Authentifizierungsfehler bei API-Aufrufen zu vermeiden.
Kann ich Angebotsbilder über die API hochladen?
Ja. Bilder werden als Base64-kodierte Strings in einem separaten API-Aufruf nach der Angebotserstellung hochgeladen. Jedes Bild darf bis zu 20 MB groß sein und muss im JPEG-, PNG- oder GIF-Format vorliegen.
Wie migriere ich von Etsy API V2 zu V3?
V3 verwendet OAuth 2.0 anstelle von OAuth 1.0a und hat eine andere Endpunktstruktur. Aktualisieren Sie den Authentifizierungsfluss, ändern Sie die Endpunktpfade von /v2/ zu /v3/application/ und testen Sie gründlich vor der Einstellung von V2 Ende 2026.
