Developer API
REST-Schnittstelle zur Anbindung externer Shop-Systeme an ElsenPlant. Bestellungen aus xt:Commerce, Gambio oder anderen Systemen automatisch importieren und den Bearbeitungsstatus in Echtzeit abfragen.
1. Authentifizierung
Alle API-Endpunkte erfordern ein gültiges JWT-Token im Authorization-Header.
Tokens werden über den Wave API-Key-Mechanismus ausgestellt.
curl -X POST https://www.elsenplant.com/api/token?key=YOUR_API_KEY
Das erhaltene Token bei allen weiteren Requests als Bearer-Token mitsenden:
Authorization: Bearer eyJ0eXAiOiJKV1Qi...
2. API-Endpunkte
| Methode | Endpunkt | Beschreibung |
|---|---|---|
| POST | /api/v1/imports/orders | Bestellungen importieren |
| GET | /api/v1/imports/orders | Import-Liste (paginiert) |
| GET | /api/v1/imports/orders/{ext_nr} | Import-Status abfragen |
| GET | /api/v1/orders/{ext_ref}/status | Auftragsstatus abfragen |
2.1 Bestellungen importieren
POST
/api/v1/imports/orders
Überträgt eine oder mehrere Bestellungen aus dem externen Shop an ElsenPlant.
Request-Body
{
"orders": [
{
"order_number": "XTC-20260220-4711",
"source": "xtcommerce",
"customer": {
"external_id": "CUST-1234",
"email": "max@example.com",
"first_name": "Max",
"last_name": "Mustermann",
"company": "Garten GmbH",
"phone": "+49 170 1234567",
"address": "Gartenweg 42",
"city": "München",
"postal_code": "80331",
"country": "Deutschland"
},
"items": [
{
"external_product_id": "ART-5001",
"sku": "TAX-OFF-120",
"name": "Taxus baccata",
"quantity": 10,
"unit_price_net": 45.50,
"tax_rate": 7,
"size_1": "100",
"size_2": "120",
"quality_1": "Sol",
"quality_2": "3xv"
}
],
"totals": {
"net": 455.00,
"tax": 31.85,
"gross": 486.85
},
"payment_method": "Vorkasse",
"payment_status": "paid",
"shipping_type": "spedition",
"customer_note": "Bitte Lieferung ab April",
"metadata": {
"tracking_id": "XT-TRACK-4711",
"campaign": "fruehling2026"
}
}
]
}
Pflichtfelder
| Feld | Typ | Beschreibung |
|---|---|---|
| order_number | string | Eindeutige Bestellnummer im Quellsystem |
| customer.email | string | E-Mail-Adresse des Kunden |
| customer.first_name | string | Vorname |
| customer.last_name | string | Nachname |
| customer.address | string | Straße und Hausnummer |
| customer.city | string | Stadt |
| customer.postal_code | string | Postleitzahl |
| items[].name | string | Produktname |
| items[].quantity | integer | Menge (min. 1) |
| items[].unit_price_net | float | Netto-Einzelpreis |
Optionale Felder
| Feld | Standard | Beschreibung |
|---|---|---|
| source | xtcommerce | Quellsystem-Kennung |
| customer.external_id | — | Kunden-ID im Quellsystem |
| customer.company | — | Firmenname |
| customer.phone | — | Telefonnummer |
| customer.country | Deutschland | Land |
| customer.is_critical NEU | null | Kunde als kritisch markieren (boolean) |
| has_shipping_address NEU | false | Abweichende Versandadresse vorhanden |
| shipping_first_name NEU | — | Versand: Vorname |
| shipping_last_name NEU | — | Versand: Nachname |
| shipping_company NEU | — | Versand: Firma |
| shipping_address NEU | — | Versand: Straße und Hausnummer |
| shipping_apartment NEU | — | Versand: Adresszusatz |
| shipping_city NEU | — | Versand: Stadt |
| shipping_postal_code NEU | — | Versand: PLZ |
| shipping_country NEU | — | Versand: Land |
| shipping_phone NEU | — | Versand: Telefon |
| has_billing_address NEU | false | Abweichende Rechnungsadresse vorhanden |
| billing_first_name NEU | — | Rechnung: Vorname |
| billing_last_name NEU | — | Rechnung: Nachname |
| billing_company NEU | — | Rechnung: Firma |
| billing_email NEU | — | Rechnung: E-Mail |
| billing_address NEU | — | Rechnung: Straße und Hausnummer |
| billing_apartment NEU | — | Rechnung: Adresszusatz |
| billing_city NEU | — | Rechnung: Stadt |
| billing_postal_code NEU | — | Rechnung: PLZ |
| billing_country NEU | — | Rechnung: Land |
| billing_phone NEU | — | Rechnung: Telefon |
| items[].sku | — | Artikelnummer |
| items[].tax_rate | 7 | MwSt.-Satz (ganze Zahl: 7 oder 19) |
| items[].size_1 / size_2 | — | Sortiermaß (Höhe von/bis in cm) |
| items[].quality_1 / quality_2 | — | Qualitätsmerkmale (z.B. Sol, 3xv, mDb) |
| totals | — | Summen (net, tax, gross) |
| payment_method | — | Zahlungsart |
| is_paid | false | Bezahlstatus |
| shipping_type | — | Versandart: selbstabholung, eigenes_fahrzeug oder spedition |
| customer_note | — | Kundennotiz |
| metadata NEU | null | Beliebige Zusatzdaten als JSON-Objekt (Tracking-IDs, externe Referenzen, Custom-Felder) |
Validierungsregeln
| Feld | Typ | Max | Pflicht |
|---|---|---|---|
| orders | array | 50 Einträge | Ja |
| orders[].items | array | 100 Einträge | Ja |
| customer.first_name | string | 255 | Ja |
| customer.last_name | string | 255 | Ja |
| customer.address | string | 500 | Ja |
| customer.city | string | 255 | Ja |
| customer.postal_code | string | 20 | Ja |
| customer.company | string | 255 | Nein |
| customer.phone | string | 50 | Nein |
| customer.country | string | 100 | Nein |
| customer.is_critical NEU | boolean | — | Nein |
| has_shipping_address NEU | boolean | — | Nein |
| shipping_first_name NEU | string | 255 | Nein |
| shipping_last_name NEU | string | 255 | Nein |
| shipping_company NEU | string | 255 | Nein |
| shipping_address NEU | string | 255 | Nein |
| shipping_apartment NEU | string | 255 | Nein |
| shipping_city NEU | string | 255 | Nein |
| shipping_postal_code NEU | string | 20 | Nein |
| shipping_country NEU | string | 255 | Nein |
| shipping_phone NEU | string | 50 | Nein |
| has_billing_address NEU | boolean | — | Nein |
| billing_first_name NEU | string | 255 | Nein |
| billing_last_name NEU | string | 255 | Nein |
| billing_company NEU | string | 255 | Nein |
| billing_email NEU | 255 | Nein | |
| billing_address NEU | string | 255 | Nein |
| billing_apartment NEU | string | 255 | Nein |
| billing_city NEU | string | 255 | Nein |
| billing_postal_code NEU | string | 20 | Nein |
| billing_country NEU | string | 255 | Nein |
| billing_phone NEU | string | 50 | Nein |
| items[].name | string | 500 | Ja |
| items[].quantity | integer | 99.999 | Ja |
| items[].unit_price_net | numeric | 999.999,99 | Ja |
| items[].tax_rate | integer | 100 | Nein |
| items[].sku | string | 100 | Nein |
| items[].description | string | 2.000 | Nein |
| items[].note | string | 1.000 | Nein |
| totals.net / tax / gross | numeric | 9.999.999,99 | Nein |
| payment_method | string | 100 | Nein |
| shipping_type | string | in: selbstabholung, eigenes_fahrzeug, spedition | Nein |
| customer_note | string | 5.000 | Nein |
| metadata NEU | object | — | Nein |
Limits pro Request: Maximal 50 Bestellungen mit je maximal 100 Positionen.
Adresslogik NEU
Standardmäßig gilt: Kundenadresse = Versandadresse = Rechnungsadresse.
Nur wenn has_shipping_address: true werden die shipping_*-Felder als abweichende Versandadresse verwendet.
Nur wenn has_billing_address: true werden die billing_*-Felder als abweichende Rechnungsadresse verwendet.
Abwärtskompatibilität: Die bisherigen Felder has_delivery_address, delivery_name,
delivery_address, delivery_city, delivery_postal_code und delivery_country
werden weiterhin akzeptiert und automatisch auf die neuen shipping_*-Felder gemappt.
delivery_name wird in shipping_first_name + shipping_last_name aufgeteilt.
Tax-Rate-Normalisierung: Wird tax_rate als Dezimalwert (z.B. 0.07) übergeben, wird automatisch auf Ganzzahl normalisiert (7).
Response (201 Created)
{
"success": true,
"imported": [
{
"id": 42,
"external_order_number": "XTC-20260220-4711",
"status": "new",
"received_at": "2026-02-20T15:10:00+00:00"
}
],
"duplicates": [],
"errors": []
}
Duplikat-Erkennung: Bestellungen mit identischer Kombination aus
source + order_number werden als Duplikate erkannt und nicht erneut importiert.
Sie erscheinen im duplicates-Array der Response.
2.2 Import-Liste abrufen
GET
/api/v1/imports/orders
Paginierte Liste der eigenen Importe. Optional filterbar nach Status.
| Parameter | Beschreibung |
|---|---|
| status | Filter: new, processing, completed, failed, duplicate |
| page | Seite (Standard: 1, 25 Einträge pro Seite) |
2.3 Import-Status abfragen
GET
/api/v1/imports/orders/{external_order_number}
Gibt den vollständigen Import inkl. Items anhand der externen Bestellnummer zurück.
2.4 Auftragsstatus abfragen
GET
/api/v1/orders/{external_reference}/status
Aktuellen Bearbeitungsstatus eines übernommenen Auftrags abfragen.
{
"external_reference": "XTC-20260220-4711",
"order_status": "Bestätigt",
"order_status_id": 3
}
Auftragsstatus-Werte
| ID | Name | Beschreibung |
|---|---|---|
| 1 | Anfrage | Kundenanfrage eingegangen |
| 2 | Bearbeitung | Auftrag wird bearbeitet |
| 3 | Angebot erstellt | Angebot wurde dem Kunden gesendet |
| 4 | Bestätigt | Kunde hat bestätigt |
| 5 | Versendet | Ware wurde versendet |
| 6 | Abholbereit | Ware steht zur Abholung bereit |
| 7 | Storniert | Auftrag wurde storniert |
3. Datenmodell & Feldmappings
Mapping der Felder zwischen xt:Commerce und ElsenPlant:
| xt:Commerce | Import API | ElsenPlant Order |
|---|---|---|
| orders_id | order_number | external_reference |
| customers_id | customer.external_id | — |
| customers_email_address | customer.email | |
| customers_firstname | customer.first_name | first_name |
| customers_lastname | customer.last_name | last_name |
| customers_company | customer.company | company |
| — | customer.is_critical NEU | customers.is_critical |
| products_name | items[].name | order_items[].display |
| products_model | items[].sku | — |
| products_quantity | items[].quantity | order_items[].quantity |
| products_price | items[].unit_price_net | order_items[].unit_price_net |
| products_tax | items[].tax_rate | order_items[].tax_rate |
| — | metadata NEU | metadata |
4. Fehlercodes
| HTTP Status | Bedeutung |
|---|---|
| 200 | Erfolg (nur Duplikate oder GET-Anfrage) |
| 201 | Import(e) erfolgreich erstellt |
| 401 | Nicht authentifiziert (Token fehlt oder ungültig) |
| 403 | Keine Berechtigung (Zugriff auf fremde Ressource) |
| 404 | Ressource nicht gefunden |
| 422 | Validierungsfehler |
| 429 | Rate Limit (max. 60 Requests/Minute) |
5. Workflow-Beispiel
Kompletter Ablauf zur Anbindung eines xt:Commerce-Shops:
TOKEN=$(curl -s -X POST https://www.elsenplant.com/api/token?key=YOUR_KEY | jq -r .token)
curl -X POST https://www.elsenplant.com/api/v1/imports/orders \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"orders": [{
"order_number": "XTC-20260220-4711",
"customer": {
"email": "max@example.com",
"first_name": "Max",
"last_name": "Mustermann",
"address": "Gartenweg 42",
"city": "München",
"postal_code": "80331"
},
"items": [{
"name": "Taxus baccata",
"quantity": 10,
"unit_price_net": 45.50
}]
}]
}'
curl https://www.elsenplant.com/api/v1/orders/XTC-20260220-4711/status \
-H "Authorization: Bearer $TOKEN"
Datenfluss
Alter Shop POST /api/v1/imports/orders ElsenPlant
Import-Staging (Status: new)
Admin prüft im Import-Dashboard
Kunde zuordnen/anlegen
Als Order übernehmen (Status: completed)
Weiter im bestehenden Workflow:
Preisanfrage → Abruf → Angebot → Versand
Alter Shop GET /api/v1/orders/{'{ref}'}/status Aktuellen Status abfragen
6. Demo-Shop
Testen Sie die API interaktiv mit unserem Demo-Shop. Die Seite simuliert eine fiktive „Online Baumschule“ mit 10 vordefinierten Bestellungen, die Sie per Klick an ElsenPlant senden und deren Status in Echtzeit abfragen können.
Hinweise
- Jeder API-Key ist an einen Benutzer gebunden. Importe und Statusabfragen sind auf den eigenen Account beschränkt.
- Die API ist auf 60 Requests pro Minute pro API-Key begrenzt.
- Pro Request maximal 50 Bestellungen mit je 100 Positionen.
- MwSt.-Sätze werden als Ganzzahl erwartet (7, 19). Dezimalwerte werden automatisch normalisiert.
- Bestellungen werden nicht sofort als Auftrag übernommen, sondern landen im Import-Staging zur manuellen Prüfung.
- Duplikate (gleiche
source+order_number) werden erkannt und nicht erneut importiert.
Fragen zur API-Integration? Kontakt aufnehmen