Zum Inhalt springen

Magento-REST-API-Adapter

Drop-in-kompatibel zu Magento 2

Zuletzt aktualisiert: 5. September 2026

Eine Drop-in-kompatible REST API für STOAR, die das Wire-Format von Magento 2 nachbildet — gleiche URL-Pfade, gleiche searchCriteria[…]-Abfragesyntax, gleiche Feldnamen in der Antwort, gleicher Auth-Ablauf. Bestehende Magento-Client-Bibliotheken sprechen ohne Änderung mit STOAR.

Der Adapter ist die erste Implementierung eines erweiterbaren API-Adapter-Frameworks: Dieselben Daten werden in unterschiedlichen Hersteller-Ausprägungen bereitgestellt (Magento jetzt, Shopify / WooCommerce / eigene Adapter später), ohne die Bestell-Geschäftslogik zu duplizieren.


Inhaltsverzeichnis #


Schnellstart #

# 1. Get an admin token
TOKEN=$(curl -s -X POST https://app.stoar.ai/rest/V1/integration/admin/token \
  -H 'Content-Type: application/json' \
  -d '{"username":"[email protected]","password":"your-password"}' \
  | tr -d '"')

# 2. List the most recent 5 orders
curl -s "https://app.stoar.ai/rest/V1/orders?searchCriteria[pageSize]=5" \
  -H "Authorization: Bearer $TOKEN" \
  | jq '.items[] | {entity_id, increment_id, status, grand_total}'

# 3. Fetch a single order
curl -s "https://app.stoar.ai/rest/V1/orders/123" \
  -H "Authorization: Bearer $TOKEN" \
  | jq

Authentifizierung #

Intern nutzt der Adapter persönliche Zugriffstokens von Laravel Sanctum, nach außen folgt der Ablauf jedoch exakt dem Magento-Kontrakt: Zugangsdaten per POST senden, eine Token-Zeichenkette erhalten, diese als Authorization: Bearer … mitschicken.

Token-Typ Endpunkt TTL Ability Einsatzzweck
Admin POST /rest/V1/integration/admin/token 4 h magento:admin Backend-Operationen (Bestellungen auflisten, erstatten, stornieren)
Kunde POST /rest/V1/integration/customer/token 1 h magento:customer Storefront-Integrationen

Alle /rest/V1/orders/*-Endpunkte erfordern magento:admin. Ein Kunden-Token liefert an diesen Endpunkten 403.

Token-Format

Ein erfolgreicher Token-Endpunkt gibt das rohe Token als JSON-quotierten Skalar zurück — exakt der Magento-Kontrakt:

HTTP/1.1 200 OK
Content-Type: application/json

"abc123def456…"

Verwende es in nachfolgenden Anfragen:

Authorization: Bearer abc123def456…

Tokens liegen in personal_access_tokens (Sanctums Standardtabelle) und lassen sich jederzeit widerrufen, indem du die entsprechende Zeile löschst oder im Code $user->tokens()->delete() aufrufst.


Endpunkte #

Alle Pfade sind relativ zu /rest/V1 (wortgleiches Magento-Präfix).

POST /rest/V1/integration/admin/token

Stellt ein Admin-Token aus admin_users-Zugangsdaten aus. Der Benutzername wird gegen die Spalte email oder name geprüft.

Anfrage

POST /rest/V1/integration/admin/token
Content-Type: application/json

{ "username": "[email protected]", "password": "secret" }

Antwort (200)

"3|EsTmpYnjA…"

Fehler

  • 400 — ungültige Zugangsdaten, inaktiver Benutzer oder fehlende Felder

POST /rest/V1/integration/customer/token

Stellt ein Kunden-Token aus stoar_shop_customers-Zugangsdaten aus. Der Benutzername ist die E-Mail-Adresse.

Anfrage

POST /rest/V1/integration/customer/token
Content-Type: application/json

{ "username": "[email protected]", "password": "secret" }

Antwort (200) — gleiche Struktur wie beim Admin-Token.

Fehler

  • 400 — ungültige E-Mail/Passwort, inaktiver Kunde, fehlende Felder

GET /rest/V1/orders

Listet Bestellungen mit voller Unterstützung für Magentos searchCriteria[…]-Abfragen — siehe Syntax der Search-Criteria-Abfragen weiter unten.

Authorization: Bearer-Admin-Token.

Antwort (200)

{
  "items": [
    { /* full order object — see Response shape */ }
  ],
  "search_criteria": {
    "filter_groups": [...],
    "sort_orders":   [...],
    "page_size":     20,
    "current_page":  1
  },
  "total_count": 150
}

Standardwerte

  • pageSize steht standardmäßig auf 20, begrenzt auf 500
  • currentPage steht standardmäßig auf 1
  • Keine Filter → alle Bestellungen, neueste zuerst (sortiert nach id DESC)

GET /rest/V1/orders/{id}

Ruft eine einzelne Bestellung mit allen Relationen ab: Positionen, Zahlungen, Statusverläufe, Rechnungs- und Lieferadresse.

Authorization: Bearer-Admin-Token.

Antwort (200) — siehe Antwortstruktur.

Fehler

  • 404{ "message": "No such entity with %fieldName = %fieldValue", "parameters": ["entity_id", "99999"] }

POST /rest/V1/orders/{id}/cancel

Storniert eine offene oder bezahlte Bestellung. Löst denselben Ablauf aus wie die Admin-Oberfläche: setzt den Status auf cancelled, schreibt eine Statusverlaufs-Zeile und gibt Bestandsreservierungen frei (sofern die Bestellung eine session_id besitzt).

Authorization: Bearer-Admin-Token.

Anfrage: leerer Body.

Antwort (200)true

Fehler

  • 404 — unbekannte Bestell-ID
  • 422 — Bestellung befindet sich in einem Status, der keine Stornierung erlaubt (z. B. delivered, refunded)

GET /rest/V1/orders/{id}/comments

Listet den Statusverlauf der Bestellung auf (Magento nennt diese Einträge „Comments“).

Authorization: Bearer-Admin-Token.

Antwort (200)

{
  "items": [
    {
      "entity_id":            42,
      "parent_id":            123,
      "comment":              "Payment confirmed",
      "status":               "paid",
      "created_at":           "2026-04-10T12:00:00+00:00",
      "is_customer_notified": false,
      "is_visible_on_front":  false,
      "extension_attributes": { "old_status": "pending", "changed_by": "system" }
    }
  ],
  "search_criteria": { "filter_groups": [], "sort_orders": [], "page_size": 1, "current_page": 1 },
  "total_count":     1
}

POST /rest/V1/orders/{id}/comments

Hängt einen Statusverlaufs-Kommentar an, ohne den Bestellstatus zu ändern.

Authorization: Bearer-Admin-Token.

Anfrage

{
  "statusHistory": {
    "comment":              "Customer phoned to confirm delivery slot",
    "is_customer_notified": false,
    "is_visible_on_front":  false
  }
}

statusHistory.status ist optional — fehlt es, bleibt der bestehende Bestellstatus erhalten.

Antwort (200)true

Fehler

  • 400statusHistory.comment fehlt
  • 404 — unbekannte Bestell-ID

POST /rest/V1/order/{id}/refund

Hinweis — Magento verwendet die Singularform /order/, NICHT /orders/. Der Adapter bildet das exakt nach.

Erstellt eine Rückerstattung. STOAR delegiert an das bestehende Order::processRefund(), das Stripe über StripeService::processRefund() aufruft. Die Bestellung wird auf refunded gesetzt (Vollerstattung) oder bleibt im aktuellen bezahlten Status, wobei refunded_amount aufsummiert wird (Teilerstattung).

Authorization: Bearer-Admin-Token.

Anfrage — Vollerstattung (Body oder arguments weglassen):

{}

Anfrage — expliziter Betrag:

{ "arguments": { "amount": 50.00 } }

Anfrage — positionsweise (Magento-Stil):

{
  "items": [
    { "order_item_id": 456, "qty": 1 },
    { "order_item_id": 457, "qty": 2 }
  ]
}

Wird items[] übergeben, berechnet sich der Erstattungsbetrag aus dem gespeicherten price * qty jeder Position. Ein angegebenes arguments.amount überschreibt diese Berechnung.

Antwort (200) — Credit-Memo-ID (Integer). STOAR kennt keine eigene Credit-Memo-Entität, daher wird ersatzweise die Bestell-ID zurückgegeben.

Fehler

  • 404 — unbekannte Bestell-ID
  • 422 — Bestellung ist nicht erstattungsfähig (kein Stripe Payment Intent, Status nicht paid/processing/shipped/delivered)

Syntax der Search-Criteria-Abfragen #

Der Endpunkt GET /rest/V1/orders akzeptiert die vollständige Magento-Search-Criteria-Grammatik.

Aufbau

searchCriteria[filter_groups][N][filters][M][field|value|condition_type]
searchCriteria[sortOrders][N][field|direction]
searchCriteria[pageSize]
searchCriteria[currentPage]

Filterlogik

  • Filter innerhalb derselben filter_groups[N] werden mit OR verknüpft
  • Verschiedene filter_groups[N] werden mit AND verknüpft

Beispiel — Bestellungen mit status paid ODER shipped UND einer customer_email, die @example.com enthält:

GET /rest/V1/orders
  ?searchCriteria[filter_groups][0][filters][0][field]=status
  &searchCriteria[filter_groups][0][filters][0][value]=paid
  &searchCriteria[filter_groups][0][filters][0][condition_type]=eq
  &searchCriteria[filter_groups][0][filters][1][field]=status
  &searchCriteria[filter_groups][0][filters][1][value]=shipped
  &searchCriteria[filter_groups][0][filters][1][condition_type]=eq
  &searchCriteria[filter_groups][1][filters][0][field]=customer_email
  &searchCriteria[filter_groups][1][filters][0][value]=%[email protected]
  &searchCriteria[filter_groups][1][filters][0][condition_type]=like

Unterstützte Operatoren

condition_type Bedeutung Beispiel
eq gleich value=paid&condition_type=eq
neq ungleich value=cancelled&condition_type=neq
gt größer als value=100&condition_type=gt
gteq value=2026-01-01&condition_type=gteq
lt kleiner als
lteq
from Bereichsanfang (Alias für gteq)
to Bereichsende (Alias für lteq)
like SQL LIKE; die %-Platzhalter lieferst du selbst value=%25%40example.com&condition_type=like
in kommagetrennte Liste value=paid,shipped,delivered&condition_type=in
nin NOT IN
null IS NULL (kein value nötig)
notnull IS NOT NULL
finset Teilstring-Abgleich nach bestem Bemühen

Nicht unterstützte Operatoren oder unbekannte Felder → 400 mit erläuternder message.

Sortierung

searchCriteria[sortOrders][0][field]=created_at
searchCriteria[sortOrders][0][direction]=DESC
searchCriteria[sortOrders][1][field]=grand_total
searchCriteria[sortOrders][1][direction]=ASC

direction akzeptiert ASC oder DESC (Standard ASC). Mehrere Sortierungen wirken von links nach rechts.

Pagination

searchCriteria[pageSize]=25       # max 500
searchCriteria[currentPage]=2     # 1-indexed

Die Antwort spiegelt die tatsächlich angewendeten Werte zurück:

"search_criteria": { "page_size": 25, "current_page": 2 }

Feld-Mapping (Magento ↔ STOAR) #

Der Adapter stellt ausschließlich Magento-Feldnamen bereit. Intern verweist jeder Name auf eine STOAR-Spalte oder einen berechneten Wert. Felder, die nicht in dieser Liste stehen, lassen sich weder in filter_groups noch in sortOrders verwenden — der Versuch führt zu 400.

Filter- und sortierbar

Magento-Feld STOAR-Quelle Hinweise
entity_id id
increment_id id beim Filtern numerisch behandelt (das Präfix ORD- dient nur der Darstellung)
status status
state status STOAR führt Magentos state in status zusammen
customer_id customer_id
customer_email customer_email
customer_firstname customer_info->first_name über MariaDB JSON_EXTRACT aufgelöst
customer_lastname customer_info->last_name ebenso
grand_total total_amount
subtotal subtotal
tax_amount tax_amount
shipping_amount shipping_amount
discount_amount discount_amount
coupon_code coupon_code
currency_code currency
order_currency_code currency
created_at created_at
updated_at updated_at

Nur in der Antwort (Lesefelder)

Diese Felder erscheinen in der JSON-Antwort, taugen aber nicht als Filter- oder Sortierfelder:

  • total_paid, total_refunded — abgeleitet aus OrderPayment-Zeilen + refunded_amount
  • customer_is_guestcustomer_id === null
  • items[], billing_address, shipping_address, payment, status_histories[]
  • Alle base_*-Summen — STOAR ist einwährungsfähig, daher gilt base_grand_total === grand_total

Ableitung des state

STOAR status Magento state
pending new
paid, processing, shipped, delivered processing
cancelled canceled
refunded closed

Antwortstruktur #

Eine vollständige Bestellantwort (der Kürze halber gekürzt):

{
  "entity_id":             123,
  "increment_id":          "ORD-000123",
  "state":                 "processing",
  "status":                "paid",

  "customer_id":           45,
  "customer_email":        "[email protected]",
  "customer_firstname":    "Jane",
  "customer_lastname":     "Doe",
  "customer_group_id":     0,
  "customer_is_guest":     false,

  "base_currency_code":    "EUR",
  "currency_code":         "EUR",
  "order_currency_code":   "EUR",

  "grand_total":           115.0,
  "base_grand_total":      115.0,
  "subtotal":              100.0,
  "base_subtotal":         100.0,
  "tax_amount":            10.0,
  "base_tax_amount":       10.0,
  "shipping_amount":       5.0,
  "base_shipping_amount":  5.0,
  "discount_amount":       0.0,
  "base_discount_amount":  0.0,

  "total_paid":            115.0,
  "total_refunded":        0.0,
  "base_total_paid":       115.0,
  "base_total_refunded":   0.0,

  "shipping_description":  "Standard",
  "shipping_incl_tax":     5.0,
  "base_shipping_incl_tax":5.0,

  "created_at":            "2026-04-10T09:00:00+00:00",
  "updated_at":            "2026-04-10T09:30:00+00:00",

  "is_virtual":            false,
  "weight":                0,
  "store_id":              1,
  "coupon_code":           null,

  "items": [
    {
      "item_id":           456,
      "order_id":          123,
      "product_id":        789,
      "product_type":      "simple",
      "sku":               "WID-1-A",
      "name":              "Widget",
      "qty_ordered":       2.0,
      "qty_invoiced":      0.0,
      "qty_shipped":       0.0,
      "qty_refunded":      0.0,
      "qty_canceled":      0.0,
      "price":             50.0,
      "base_price":        50.0,
      "price_incl_tax":    55.0,
      "row_total":         100.0,
      "row_total_incl_tax":110.0,
      "tax_amount":        10.0,
      "tax_percent":       10.0,
      "discount_amount":   0,
      "extension_attributes": { "variant_id": 12 }
    }
  ],

  "billing_address": {
    "entity_id":     null,
    "parent_id":     123,
    "address_type":  "billing",
    "email":         "[email protected]",
    "firstname":     "Jane",
    "lastname":      "Doe",
    "street":        "1 Test St",
    "city":          "Berlin",
    "country_id":    "DE",
    "postcode":      "10115",
    "region":        null,
    "telephone":     "+49…"
  },

  "shipping_address": { /* same shape, address_type="shipping" */ },

  "payment": {
    "entity_id":              null,
    "parent_id":              123,
    "method":                 "stripe",
    "base_amount_paid":       115.0,
    "base_amount_refunded":   0.0,
    "cc_trans_id":            "pi_test_…",
    "extension_attributes": {
      "payments": [
        { "id": 1, "gateway": "stripe", "amount": 115.0, "currency": "eur",
          "status": "succeeded", "reference": "pi_test_…", "archived_at": null,
          "created_at": "2026-04-10T09:05:00+00:00" }
      ]
    }
  },

  "status_histories": [
    {
      "entity_id":             1,
      "parent_id":             123,
      "comment":               null,
      "status":                "pending",
      "created_at":            "2026-04-10T09:00:00+00:00",
      "extension_attributes":  { "old_status": null, "changed_by": "System" }
    },
    {
      "entity_id":             2,
      "parent_id":             123,
      "comment":               "Payment confirmed via webhook",
      "status":                "paid",
      "created_at":            "2026-04-10T09:05:00+00:00",
      "extension_attributes":  { "old_status": "pending", "changed_by": "System" }
    }
  ],

  "extension_attributes": {
    "lookup_token":     "abc…",
    "tracking_number":  null,
    "tracking_url":     null,
    "tracking_carrier": null,
    "shipment_status":  null,
    "admin_notes":      null,
    "customer_notes":   null
  }
}

Praxisbeispiel #

Nachfolgend eine echte Antwort aus der Produktion für GET /rest/V1/orders/10126 — eine bezahlte Bestellung über USD $936.98 mit zwei einfachen Produktpositionen. Personenbezogene Daten (E-Mail, Telefon, Lookup-Token, exakte Straßenadresse) wurden anonymisiert; alles andere ist wortgetreu.

Anfrage

GET /rest/V1/orders/10126
Authorization: Bearer 1|vYuVLH4wvkSFfhwAVHGhzVMkOVbKkw8S5gKjVU5o9212c81b

Antwort (200)

{
  "entity_id":             10126,
  "increment_id":          "ORD-010126",
  "state":                 "processing",
  "status":                "paid",
  "customer_id":           5794,
  "customer_email":        "[email protected]",
  "customer_firstname":    "Jane",
  "customer_lastname":     "Doe",
  "customer_group_id":     0,
  "customer_is_guest":     false,
  "base_currency_code":    "USD",
  "currency_code":         "USD",
  "order_currency_code":   "USD",
  "grand_total":           936.98,
  "base_grand_total":      936.98,
  "subtotal":              936.98,
  "base_subtotal":         936.98,
  "tax_amount":            0,
  "base_tax_amount":       0,
  "shipping_amount":       0,
  "base_shipping_amount":  0,
  "discount_amount":       0,
  "base_discount_amount":  0,
  "total_paid":            0,
  "total_refunded":        0,
  "base_total_paid":       0,
  "base_total_refunded":   0,
  "shipping_description":  "Free Shipping",
  "shipping_incl_tax":     0,
  "base_shipping_incl_tax":0,
  "created_at":            "2025-06-03T04:56:43+00:00",
  "updated_at":            "2025-06-03T04:56:43+00:00",
  "is_virtual":            false,
  "weight":                0,
  "store_id":              1,
  "coupon_code":           null,
  "items": [
    {
      "item_id":               30219,
      "order_id":              10126,
      "product_id":            112238,
      "product_type":          "simple",
      "sku":                   "RELOOP_TERMINALMIX8_025-DEF",
      "name":                  "Reloop Terminal Mix 8",
      "qty_ordered":           3,
      "qty_invoiced":          0,
      "qty_shipped":           0,
      "qty_refunded":          0,
      "qty_canceled":          0,
      "price":                 299,
      "base_price":            299,
      "price_incl_tax":        299,
      "base_price_incl_tax":   299,
      "original_price":        299,
      "base_original_price":   299,
      "row_total":             897,
      "base_row_total":        897,
      "row_total_incl_tax":    897,
      "base_row_total_incl_tax":897,
      "discount_amount":       0,
      "base_discount_amount":  0,
      "discount_percent":      0,
      "tax_amount":            0,
      "base_tax_amount":       0,
      "tax_percent":           0,
      "amount_refunded":       0,
      "base_amount_refunded":  0,
      "row_weight":            0,
      "created_at":            "2025-06-03T04:56:43+00:00",
      "updated_at":            "2025-06-03T04:56:43+00:00",
      "is_qty_decimal":        false,
      "no_discount":           false,
      "parent_item_id":        null,
      "extension_attributes":  { "variant_id": 95589 }
    },
    {
      "item_id":               30220,
      "order_id":              10126,
      "product_id":            51706,
      "product_type":          "simple",
      "sku":                   "SK8-SOCK-027-DEF",
      "name":                  "Premium Skateboard Socks",
      "qty_ordered":           2,
      "qty_invoiced":          0,
      "qty_shipped":           0,
      "qty_refunded":          0,
      "qty_canceled":          0,
      "price":                 19.99,
      "base_price":            19.99,
      "price_incl_tax":        19.99,
      "base_price_incl_tax":   19.99,
      "original_price":        19.99,
      "base_original_price":   19.99,
      "row_total":             39.98,
      "base_row_total":        39.98,
      "row_total_incl_tax":    39.98,
      "base_row_total_incl_tax":39.98,
      "discount_amount":       0,
      "base_discount_amount":  0,
      "discount_percent":      0,
      "tax_amount":            0,
      "base_tax_amount":       0,
      "tax_percent":           0,
      "amount_refunded":       0,
      "base_amount_refunded":  0,
      "row_weight":            0,
      "created_at":            "2025-06-03T04:56:43+00:00",
      "updated_at":            "2025-06-03T04:56:43+00:00",
      "is_qty_decimal":        false,
      "no_discount":           false,
      "parent_item_id":        null,
      "extension_attributes":  { "variant_id": 33857 }
    }
  ],
  "billing_address": {
    "entity_id":           null,
    "parent_id":           10126,
    "address_type":        "billing",
    "email":               null,
    "firstname":           "Jane",
    "lastname":            "Doe",
    "middlename":          null,
    "prefix":              null,
    "suffix":              null,
    "street":              "1 Example Street",
    "city":                "Phoenix",
    "country_id":          "US",
    "postcode":            "85001",
    "region":              "AZ",
    "region_code":         "AZ",
    "region_id":           null,
    "telephone":           "+1-555-0100",
    "fax":                 null,
    "company":             null,
    "customer_address_id": null
  },
  "shipping_address": {
    "entity_id":           null,
    "parent_id":           10126,
    "address_type":        "shipping",
    "email":               null,
    "firstname":           "Jane",
    "lastname":            "Doe",
    "middlename":          null,
    "prefix":              null,
    "suffix":              null,
    "street":              "1 Example Street",
    "city":                "Phoenix",
    "country_id":          "US",
    "postcode":            "85001",
    "region":              "AZ",
    "region_code":         "AZ",
    "region_id":           null,
    "telephone":           "+1-555-0100",
    "fax":                 null,
    "company":             null,
    "customer_address_id": null
  },
  "payment": {
    "entity_id":              null,
    "parent_id":              10126,
    "base_amount_authorized": 936.98,
    "base_amount_paid":       0,
    "base_amount_refunded":   0,
    "base_shipping_amount":   0,
    "base_shipping_captured": 0,
    "base_shipping_refunded": 0,
    "billing_address_id":     null,
    "cc_avs_status":          null,
    "cc_cid_status":          null,
    "cc_exp_month":           null,
    "cc_exp_year":            null,
    "cc_last4":               null,
    "cc_number_enc":          null,
    "cc_owner":               null,
    "cc_status":              null,
    "cc_status_description":  null,
    "cc_trans_id":            null,
    "created_at":             null,
    "updated_at":             null,
    "method":                 "payid",
    "po_number":              null,
    "protection_eligibility": null,
    "quote_payment_id":       null,
    "extension_attributes":   { "payments": [] }
  },
  "status_histories": [],
  "extension_attributes": {
    "lookup_token":      "REDACTED-FOR-DOCS",
    "tracking_number":   null,
    "tracking_url":      null,
    "tracking_carrier":  null,
    "shipment_status":   null,
    "admin_notes":       null,
    "customer_notes":    null
  }
}

Was dieses Beispiel über den Kontrakt aussagt

Einige Punkte dieser echten Antwort verdienen Beachtung, weil sie Integratoren überraschen können:

Feld Beobachtet Warum es „falsch“ wirken kann
total_paid, payment.base_amount_paid 0 Der status der Bestellung lautet paid, ihr OrderPayment-Audit-Log ist jedoch leer. Der Adapter berechnet total_paid als Summe der nicht archivierten, erfolgreichen OrderPayment-Zeilen — er leitet den Zahlbetrag nicht allein aus dem Bestellstatus ab. Bestellungen aus der Zeit vor dem Zahlungs-Audit liefern hier 0, obwohl sie bezahlt sind.
payment.method "payid" Das ist der STOAR-Gateway-Key, kein Magento-kanonischer Methodenname. Mögliche Werte sind unter anderem stripe, bank_transfer, cash_on_delivery, payid, invoice sowie jedes über GatewayRegistry registrierte eigene Gateway.
status_histories [] Statuslogs kamen erst nach der Anlage einiger Altbestellungen hinzu, ältere Bestellungen liefern daher ein leeres Array. Neu angelegte Bestellungen haben immer mindestens einen Eintrag (den initialen Status pending).
qty_invoiced, qty_shipped, qty_refunded, qty_canceled 0 für alle Positionen STOAR kennt keine eigenen Invoice-/Shipment-Entitäten, daher werden positionsbezogene Fulfilment-Zähler stets als 0 gemeldet. Verwende stattdessen die Felder total_refunded und status auf Bestellebene.
coupon_code null Nur gefüllt, wenn die Bestellung mit einem Rabattcode aufgegeben wurde. Ohne Bezug zu Rabatten aus Warenkorbregeln.
customer_id + customer_is_guest: false beide gefüllt Wenn die Bestellung von einem angemeldeten Kunden aufgegeben wurde. Gastbestellungen liefern customer_id: null und customer_is_guest: true.
weight 0 STOAR erfasst kein Gewicht je Bestellung; das Feld existiert nur zur Kompatibilität mit Magento-Clients.
store_id 1 STOAR ist Single-Store; dieses Feld ist immer 1.
extension_attributes.lookup_token geschwärzt Das ist STOARs „Magic-Link“-Token je Bestellung für die Bestellstatus-Seiten von Gästen. Gib es niemals in Client-Code oder öffentlichen Logs preis — der Besitz des Tokens genügt, um die Bestellung ohne Authentifizierung einzusehen.

Fehlerstruktur #

Jeder /rest/V1/*-Fehler folgt dem Magento-Envelope:

{
  "message":    "Human message with %fieldName placeholders",
  "parameters": ["fieldName", "fieldValue"],
  "trace":      "…stack trace…"
}

parameters korrespondiert mit den Platzhaltern %1, %2 oder %fieldName in message, sodass lokalisierte Clients Werte einsetzen können. trace ist nur enthalten, wenn APP_DEBUG=true gesetzt ist.

HTTP Auslöser Beispiel
400 fehlerhafte Eingabe — unbekanntes Filterfeld, nicht unterstützter condition_type, Validierungsfehler { "message": "Unsupported condition_type: zorp" }
401 fehlendes oder ungültiges Token { "message": "Consumer is not authorized to access %resources", "parameters": ["Magento_Sales::sales"] }
403 Token mit falscher Ability (z. B. Kunden-Token an einem Admin-Endpunkt) { "message": "The consumer does not have access to the requested resource." }
404 unbekannte Bestell-ID { "message": "No such entity with %fieldName = %fieldValue", "parameters": ["entity_id", "99999"] }
422 Vorbedingung verletzt (nicht stornierbare Stornierung, nicht erstattungsfähige Erstattung) { "message": "Order 5 cannot be cancelled in status 'delivered'." }
500 unerwarteter Serverfehler { "message": "Internal server error." } (im Debug-Modus erscheint die echte Meldung)

Siehe auch #