BigCommerce-REST-API-Adapter
Kompatibel zu v2/v3
Zuletzt aktualisiert: 5. September 2026
Eine unmittelbar einsetzbare, kompatible REST-API für STOAR, die BigCommerce v2 (/api/v2/orders) und v3 (/api/v3/catalog/products) nachbildet — dieselben URL-Pfade, dieselben RFC-2822-Datumsangaben, dasselbe numerische status_id-Vokabular, dieselbe { data, meta.pagination }-Hülle in v3, dieselben X-Pagination-*-Header in v2, derselbe X-Auth-Token-Header. Bestehende BigCommerce-Client-Bibliotheken (bigcommerce/api Node SDK, bigcommerce-api-php, BigCommerce Python) sprechen ohne Änderung mit STOAR.
Dies ist die vierte Implementierung von STOARs erweiterbarem API-Adapter-Framework (nach Magento, WooCommerce und Shopify). Sie zeigt, dass die Architektur zwei Versionsvarianten unter einem Adapter (v2 + v3) trägt, ohne Geschäftslogik zu duplizieren.
Inhaltsverzeichnis #
- Schnellstart
- Authentifizierung
- Endpunkte
- Query-Parameter
- Feld-Mapping (BigCommerce ↔ STOAR)
- Statusübersetzung
- Antwortstruktur
- Praxisbeispiel
- Fehlerstruktur
- Rate-Limiting
Schnellstart #
TOKEN="5|abcdef…" # Sanctum personal-access token with bigcommerce:admin ability
# v2 — orders
curl -H "X-Auth-Token: $TOKEN" \
"https://app.stoar.ai/api/v2/orders?limit=5" | jq '.[] | {id, status_id, status, total_inc_tax}'
# v2 — line items for a specific order (separate sub-endpoint)
curl -H "X-Auth-Token: $TOKEN" \
"https://app.stoar.ai/api/v2/orders/10126/products" | jq '.[].name'
# v3 — catalog products with pagination meta envelope
curl -H "X-Auth-Token: $TOKEN" \
"https://app.stoar.ai/api/v3/catalog/products?limit=2&page=1" | jq '.meta.pagination'
# v3 — single product
curl -H "X-Auth-Token: $TOKEN" \
"https://app.stoar.ai/api/v3/catalog/products/789"
Bearer-Auth (-H "Authorization: Bearer $TOKEN") wird ebenfalls als Fallback akzeptiert.
Authentifizierung #
Der kanonische Auth-Header von BigCommerce lautet X-Auth-Token: <token>. STOARs Adapter akzeptiert ihn sowie einen Bearer-Fallback:
| Methode | Format | Anwendungsfall |
|---|---|---|
| X-Auth-Token | X-Auth-Token: <sanctum-token> |
Standard für alle BigCommerce-Client-Bibliotheken |
| Bearer (STOAR-Erweiterung) | Authorization: Bearer <sanctum-token> |
Natives Sanctum — austauschbar mit den anderen Adaptern |
Tokens werden auf STOARs Seite /manager/api-tokens ausgestellt oder programmatisch über AdminUser::createToken('label', ['bigcommerce:admin']). Ein einzelnes Token kann die Ability jedes Adapters gleichzeitig tragen (bigcommerce:admin + magento:admin + shopify:admin + woocommerce:admin).
Die AuthTokenMiddleware läuft vor auth:sanctum und überführt X-Auth-Token in einen Authorization: Bearer …-Header. Aus Sicht von STOAR ist jede BC-Anfrage eine normale, per Sanctum authentifizierte Anfrage.
Der OAuth-Client-Credential-Flow (echte BC-Apps gehen über /auth/load und /oauth2/token) wird nicht unterstützt.
Endpunkte #
Alle Pfade sind relativ zu /api. v2-Endpunkte liegen unter /api/v2, v3-Endpunkte unter /api/v3.
GET /api/v2/orders
Bestellungen auflisten — flaches Array im Body plus Pagination-Header.
Autorisierung: bigcommerce:admin.
Query: siehe Query-Parameter.
Antwort:
HTTP/1.1 200 OK
X-Pagination-Total-Count: 150
X-Pagination-Page-Total: 3
Content-Type: application/json
[
{ /* order object — see Response shape */ }
]
Warum Header statt Hülle? Genau das ist die tatsächliche Konvention von BC v2. v3-Endpunkte nutzen die
{ data, meta }-Hülle (siehe Katalogprodukte weiter unten). Echte BC-Client-Bibliotheken beherrschen beides.
GET /api/v2/orders/{id}
Einzelne Bestellung — reines Objekt (in v2 KEINE Hülle).
Fehler:
{ "status": 404, "title": "The order requested could not be found.", "type": "..." }
GET /api/v2/orders/{id}/products
Hinweis — Positionen liegen an einem SEPARATEN Endpunkt und sind nicht in die Bestellressource eingebettet. Das ist einer der größeren Unterschiede von BC gegenüber Magento, WooCommerce und Shopify (die Positionen jeweils inline führen).
Antwort: flaches Array von BC-v2-Positionsobjekten.
[
{
"id": 30219,
"order_id": 10126,
"product_id": 112238,
"variant_id": 95589,
"name": "Widget",
"sku": "WID-1-A",
"type": "physical",
"base_price": 299,
"price_ex_tax": 299,
"price_inc_tax": 299,
"base_total": 897,
"total_ex_tax": 897,
"total_inc_tax": 897,
"quantity": 3,
"is_refunded": false,
"product_options": [],
"..."
}
]
GET /api/v3/catalog/products
Katalogprodukte auflisten — v3-Hülle mit data + meta.pagination.
Query: siehe Query-Parameter.
Antwort (200):
{
"data": [
{ /* product — see Response shape */ }
],
"meta": {
"pagination": {
"total": 150,
"count": 50,
"per_page": 50,
"current_page": 1,
"total_pages": 3,
"links": {
"current": "https://.../api/v3/catalog/products?page=1&limit=50",
"next": "https://.../api/v3/catalog/products?page=2&limit=50"
},
"too_many": false
}
}
}
links.previous ist ab Seite 2 enthalten, links.next auf allen Seiten außer der letzten.
GET /api/v3/catalog/products/{id}
Einzelnes Produkt — v3-Hülle mit data (einzelnes Objekt) und leerem meta.
Antwort:
{
"data": { /* product — see Response shape */ },
"meta": {}
}
Query-Parameter #
Gemeinsam (Bestellungen + Produkte)
| Parameter | Standard | Zweck |
|---|---|---|
limit |
50 |
Einträge pro Seite (max. 250) |
page |
1 |
Seitenzahl, 1-basiert |
Nur v2-Bestellungen
| Parameter | Beispiel | Wirkung |
|---|---|---|
status_id |
11 |
Numerischer BC-Statuscode → in Stoar-Status übersetzt |
customer_id |
42 |
Nach Kunde filtern |
min_id / max_id |
100 |
id-Bereich |
min_date_created / max_date_created |
2025-01-01T00:00:00 |
created_at-Bereich |
sort |
id:desc |
<field>:<asc\|desc>. Felder: id, date_created, date_modified, total_inc_tax |
Nur v3-Katalogprodukte
V3 unterstützt die reichhaltigere Operator-Suffix-Syntax von BC: id:in, price:min usw.
| Parameter | Beispiel | Wirkung |
|---|---|---|
id |
42 |
exakte id |
id:in |
1,2,3 |
id IN Liste |
id:not_in |
4,5 |
id NOT IN Liste |
sku |
WID-1 |
exakte sku |
name |
Widget |
exakter Name |
keyword |
widget |
LIKE-Teilstring auf dem Namen |
is_visible |
true / false |
wird zu active / inactive übersetzt |
is_featured |
true / false |
Filter auf is_featured |
categories |
5 |
exakte Kategorie-id |
price:min |
10 |
price >= |
price:max |
100 |
price <= |
sort |
name, -price, -date_created, id |
führendes - kehrt die Richtung um |
Unbekannte Operatoren oder Felder werden stillschweigend ignoriert — genau wie bei BC.
Feld-Mapping (BigCommerce ↔ STOAR) #
Bestellung (v2)
| BC-v2-Feld | STOAR-Quelle | Hinweise |
|---|---|---|
id |
id |
numerisch |
status_id |
status (übersetzt) |
numerischer BC-Code (1, 11, 7, 3, 10, 5, 4) — siehe Statusübersetzung |
status |
status (übersetzt) |
String-Label („Pending“, „Awaiting Fulfillment“, „Shipped“, …) |
customer_id |
customer_id ?? 0 |
Gastbestellungen erhalten 0 |
date_created, date_modified |
created_at, updated_at |
RFC-2822-Format (NICHT ISO 8601) |
date_shipped |
updated_at, wenn status='shipped'/'delivered' |
sonst leerer String |
currency_code, default_currency_code |
currency (in Großbuchstaben) |
z. B. EUR |
currency_exchange_rate |
immer '1.0000000000' |
Stoar ist einwährungsfähig |
total_inc_tax |
total_amount |
NUMERISCHER Float (KEIN String — das ist V3-/WC-Verhalten) |
total_ex_tax |
total_amount - tax_amount |
|
total_tax |
tax_amount |
|
subtotal_ex_tax |
subtotal |
|
subtotal_inc_tax |
subtotal + tax_amount |
|
subtotal_tax |
tax_amount |
|
shipping_cost_ex_tax, shipping_cost_inc_tax, base_shipping_cost |
shipping_amount |
|
discount_amount, coupon_discount |
discount_amount |
|
payment_method |
erstes nicht archiviertes OrderPayment.gateway |
|
payment_status |
'captured', wenn payment_status='succeeded' |
sonst leer |
refunded_amount |
refunded_amount ?? 0 |
|
staff_notes |
admin_notes |
|
customer_message |
customer_notes |
|
billing_address |
billing_info-JSON |
verschachteltes Objekt — flache Struktur mit den Schlüsseln street_1/street_2 |
products |
Unterressource | {url, resource}-Zeiger auf /orders/{id}/products |
shipping_addresses |
Unterressource | {url, resource}-Zeiger (nicht implementiert) |
coupons |
Unterressource | {url, resource}-Zeiger (nicht implementiert) |
items_total |
sum(items.quantity) |
|
items_shipped |
sum(items.quantity), wenn status='shipped'/'delivered', sonst 0 |
|
customer_locale |
immer 'en' |
nicht gespeichert |
channel_id |
immer 1 |
nicht modelliert |
Bestellposition line_item (v2 /products)
| BC-v2-Feld | Stoar-Quelle |
|---|---|
id |
OrderItem.id |
order_id |
OrderItem.order_id |
product_id |
OrderItem.product_id |
variant_id |
OrderItem.variant_id |
name, name_customer, name_merchant |
OrderItem.name |
sku |
zuerst die Varianten-SKU, ersatzweise die des Produkts |
type |
immer 'physical' |
base_price, price_ex_tax |
OrderItem.price |
price_inc_tax |
price + (tax_amount / quantity) |
base_total, total_ex_tax |
price * quantity |
total_inc_tax |
(price * quantity) + tax_amount |
total_tax |
OrderItem.tax_amount |
quantity |
OrderItem.quantity |
product_options[] |
ein Element mit dem Variantennamen (sofern nicht Default) |
weight, width, height, depth |
immer 0 |
is_refunded, quantity_refunded, refund_amount |
immer false/0 (Stoar verfolgt Erstattungen nur auf Bestellebene) |
Katalogprodukt (v3)
| BC-v3-Feld | STOAR-Quelle | Hinweise |
|---|---|---|
id |
id |
|
name, description, sku |
direkt übernommen | |
type |
immer 'physical' |
BC kennt zusätzlich 'digital'; Stoar führt nur physische Ware |
is_visible |
status === 'active' |
bool |
availability |
'available', wenn aktiv, sonst 'disabled' |
enum |
is_featured |
is_featured |
bool |
inventory_tracking |
'product' für einfache, 'variant' für konfigurierbare Produkte |
|
inventory_level |
stock (bei konfigurierbaren Produkten Summe der Varianten) |
|
inventory_warning_level |
low_stock_threshold ?? 0 |
|
price |
price (roh) |
NUMERISCHER Float |
sale_price |
special_price ?? 0 |
Float |
calculated_price |
min(price, special_price) | Float |
weight |
weight ?? 0 |
Float |
tax_class_id |
tax_class_id ?? 0 |
|
categories |
[category_id] |
Array mit einem einzelnen Int (KEINE verschachtelten Objekte) |
base_variant_id |
id der ersten Variante | |
images[] |
image_path + gallery_paths |
Inline-Array |
variants[] |
inline | vollständige Variantenobjekte |
custom_url |
{url: "/{slug}", is_customized: false, create_redirect: false} |
|
page_title, meta_description, meta_keywords |
meta_title, meta_description, [] |
|
date_created, date_modified |
created_at, updated_at |
ISO 8601 (v3 nutzt ISO, v2 RFC 2822) |
condition |
immer 'New' |
nicht modelliert |
total_sold, view_count, reviews_rating_sum, reviews_count |
immer 0 |
nicht aggregiert |
related_products |
immer [-1] |
BC-Konvention für „automatisch verwandt“ |
brand_id |
immer null |
Stoar hat kein Markenmodell |
Katalogprodukt-Variante (v3)
| BC-v3-Feld | Stoar-Quelle |
|---|---|
id |
Variant.id |
product_id |
Variant.product_id |
sku |
Variant.sku |
price, calculated_price |
Variant.price |
inventory_level |
Variant.stock |
weight, calculated_weight |
Variant.weight |
purchasing_disabled |
!Variant.is_active |
image_url |
Variant.image_path ?? "" |
option_values[] |
immer [] (Stoar-Variantenattribute nutzen ein anderes Modell) |
Statusübersetzung #
BigCommerce verwendet NUMERISCHE status_id-Codes plus ein paralleles String-Feld status. Der Übersetzer zerlegt Stoars Enum in beides.
Stoar → BigCommerce (Ausgabe)
Stoar status |
status_id |
status (String) |
|---|---|---|
pending |
1 | Pending |
paid |
11 | Awaiting Fulfillment |
processing |
7 | Awaiting Pickup |
shipped |
3 | Shipped |
delivered |
10 | Completed |
cancelled |
5 | Cancelled |
refunded |
4 | Refunded |
BigCommerce-Filter → Stoar (Parsing)
?status_id=N wird über dieselbe Nachschlagetabelle übersetzt. Codes ohne Eintrag in der Tabelle (z. B. BC-Status 2 = „Manually Verified“ oder 6 = „Declined“) fallen stillschweigend durch — passend zu BCs Verhalten bei fehlender exakter Entsprechung. Die vollständige Codetabelle des echten BC hat rund 14 Einträge; STOAR stellt die sieben bereit, die sich sauber abbilden lassen.
Produktstatus
BigCommerce hat kein String-Feld status — es nutzt is_visible (bool) plus das availability-Enum. Filtere mit ?is_visible=true nach aktiven und mit ?is_visible=false nach inaktiven Produkten.
Antwortstruktur #
v2-Bestellung — kommentiert
{
"id": 456,
"customer_id": 45,
"date_created": "Tue, 03 Jun 2025 04:56:43 +0000",
"date_modified": "Tue, 03 Jun 2025 04:56:43 +0000",
"date_shipped": "",
"status_id": 11,
"status": "Awaiting Fulfillment",
"subtotal_ex_tax": 100,
"subtotal_inc_tax": 110,
"subtotal_tax": 10,
"total_ex_tax": 105,
"total_inc_tax": 115,
"total_tax": 10,
"items_total": 2,
"items_shipped": 0,
"payment_method": "stripe",
"payment_status": "captured",
"refunded_amount": 0,
"currency_code": "EUR",
"currency_exchange_rate": "1.0000000000",
"default_currency_code": "EUR",
"billing_address": {
"first_name": "Jane",
"last_name": "Doe",
"company": "",
"street_1": "1 Test St",
"street_2": "",
"city": "Berlin",
"state": "",
"zip": "10115",
"country": "Germany",
"country_iso2": "DE",
"phone": "+49…",
"email": "[email protected]",
"form_fields": []
},
"products": {
"url": "https://.../api/v2/orders/456/products",
"resource": "/orders/456/products"
},
"shipping_addresses": {
"url": "https://.../api/v2/orders/456/shippingaddresses",
"resource": "/orders/456/shippingaddresses"
},
"coupons": {
"url": "https://.../api/v2/orders/456/coupons",
"resource": "/orders/456/coupons"
},
"store_default_currency_code": "EUR",
"channel_id": 1,
"..."
}
v3-Katalogprodukt — gekürzt
{
"data": {
"id": 789,
"name": "Widget",
"type": "physical",
"sku": "WID-1",
"description": "<p>A great widget</p>",
"weight": 0.5,
"price": 99.99,
"sale_price": 0,
"retail_price": 0,
"calculated_price": 99.99,
"categories": [5],
"is_visible": true,
"is_featured": true,
"availability": "available",
"inventory_tracking": "product",
"inventory_level": 42,
"page_title": "Widget – buy now",
"custom_url": {
"url": "/widget",
"is_customized": false,
"create_redirect": false
},
"images": [
{ "id": 0, "image_file": "products/widget.webp", "is_thumbnail": true, "sort_order": 0, "url_thumbnail": "products/widget.webp", "url_zoom": "products/widget.webp", "..." }
],
"variants": [
{ "id": 12, "product_id": 789, "sku": "WID-RED", "price": 99.99, "inventory_level": 22, "purchasing_disabled": false, "..." }
]
},
"meta": {}
}
Praxisbeispiel #
GET /api/v2/orders/10126 gegen die Produktion. Dieselbe Stoar-Bestellung wie in Magento, WooCommerce und Shopify — hier in BC-v2-Struktur gerendert. Personenbezogene Daten anonymisiert.
{
"id": 10126,
"customer_id": 5794,
"date_created": "Tue, 03 Jun 2025 04:56:43 +0000",
"date_modified": "Tue, 03 Jun 2025 04:56:43 +0000",
"date_shipped": "",
"status_id": 11,
"status": "Awaiting Fulfillment",
"subtotal_ex_tax": 936.98,
"subtotal_inc_tax": 936.98,
"subtotal_tax": 0,
"shipping_cost_ex_tax": 0,
"shipping_cost_inc_tax": 0,
"shipping_cost_tax": 0,
"total_ex_tax": 936.98,
"total_inc_tax": 936.98,
"total_tax": 0,
"items_total": 5,
"items_shipped": 0,
"payment_method": "payid",
"payment_provider_id":null,
"payment_status": "captured",
"refunded_amount": 0,
"order_is_digital": false,
"currency_id": 1,
"currency_code": "USD",
"currency_exchange_rate": "1.0000000000",
"default_currency_id": 1,
"default_currency_code": "USD",
"staff_notes": "",
"customer_message": "",
"discount_amount": 0,
"coupon_discount": 0,
"shipping_address_count": 1,
"is_deleted": false,
"ebay_order_id": "0",
"cart_id": null,
"billing_address": {
"first_name": "Jane",
"last_name": "Doe",
"company": "",
"street_1": "1 Example Street",
"street_2": "",
"city": "Phoenix",
"state": "AZ",
"zip": "85001",
"country": "United States",
"country_iso2": "US",
"phone": "+1-555-0100",
"email": "",
"form_fields": []
},
"products": {
"url": "https://app.stoar.ai/api/v2/orders/10126/products",
"resource": "/orders/10126/products"
},
"shipping_addresses": {
"url": "https://app.stoar.ai/api/v2/orders/10126/shippingaddresses",
"resource": "/orders/10126/shippingaddresses"
},
"coupons": {
"url": "https://app.stoar.ai/api/v2/orders/10126/coupons",
"resource": "/orders/10126/coupons"
},
"store_default_currency_code": "USD",
"store_default_to_transactional_exchange_rate": "1.0000000000",
"custom_status": "Awaiting Fulfillment",
"channel_id": 1,
"ip_address": "",
"ip_address_v6": "",
"geoip_country": "",
"geoip_country_iso2": "",
"is_email_opt_in": false,
"credit_card_type": null,
"order_source": "www",
"external_source": null,
"external_id": null,
"external_merchant_id":null,
"tax_provider_id": "",
"customer_locale": "en",
"external_order_id": ""
}
Fallstricke, die Integratoren kennen sollten
| Feld | Beobachtet | Grund |
|---|---|---|
date_created, date_modified |
RFC-2822-String | v2 nutzt gezielt RFC 2822 (Tue, 03 Jun 2025 04:56:43 +0000). v3-Endpunkte nutzen ISO 8601 — die Inkonsistenz stammt von BC, wir bilden sie nach. |
payment_method |
"payid" |
Stoars Gateway-Key — kein BC-kanonischer Methodenname. |
payment_status |
"captured" bei bezahlten Bestellungen |
BC hat ein eigenes Statusvokabular; wir bilden succeeded auf captured ab. |
total_inc_tax, total_ex_tax usw. |
Floats (z. B. 936.98) |
BC v2 gibt Beträge als Floats aus — anders als WooCommerce/Shopify, die Strings mit zwei Nachkommastellen verwenden. |
country |
"United States" |
Langform, aus ISO-2 über eine kleine Nachschlagetabelle abgeleitet (DE/US/GB/AU/AT/CH). Andere Länder liefern "". |
products, shipping_addresses, coupons |
{url, resource}-Zeiger auf Unterressourcen |
BC-Konvention für „folge dieser URL, um verwandte Daten zu laden“. /orders/{id}/products ist implementiert, die übrigen sind noch nicht verfügbar. |
customer_locale |
immer "en" |
nicht am Stoar-Customer gespeichert. |
channel_id |
immer 1 |
Stoar ist Single-Store; BC unterstützt mehrere Kanäle. |
currency_exchange_rate |
immer "1.0000000000" |
Stoar ist einwährungsfähig. |
staff_notes, customer_message |
admin_notes, customer_notes |
BC-Terminologie. |
external_*, ebay_order_id, cart_id |
leer / null / „0“ | Stoar hat keine Marktplatzanbindung. |
Fehlerstruktur #
BigCommerce verwendet eine Hülle im Stil von RFC 7807:
{
"status": 404,
"title": "The order requested could not be found.",
"type": "https://developer.bigcommerce.com/api-docs/getting-started/api-status-codes",
"errors": { "<field>": "..." }
}
type verweist immer auf BCs Dokumentationsseite zu den Statuscodes. errors erscheint nur bei Validierungsfehlern (400).
| HTTP | Auslöser | title |
|---|---|---|
| 400 | fehlerhafte Query / Validierung | Invalid query parameters. (mit errors-Map) |
| 401 | fehlendes oder ungültiges Token | Not authenticated. |
| 403 | Token mit falscher Ability | Insufficient OAuth scope. |
| 404 | unbekannte Ressource | The {resource} requested could not be found. |
| 422 | Vorbedingung nicht erfüllt | dynamische Meldung |
| 429 | Rate-Limit überschritten | Too many requests. (mit den Headern X-Rate-Limit-Time-Reset-Ms und X-Rate-Limit-Requests-Left) |
| 500 | unerwarteter Serverfehler | Internal Server Error |
Rate-Limiting #
Dieselbe per Sanctum-Token gekennzeichnete api-rest-Drosselung, die alle anderen Adapter schützt, schützt auch die BC-Routen. Schwellwert und Hauptschalter konfigurierst du unter /manager/api-settings. Beim Auslösen nutzt die Antwort BCs RFC-7807-Hülle:
HTTP/1.1 429 Too Many Requests
X-Rate-Limit-Time-Reset-Ms: 60000
X-Rate-Limit-Requests-Left: 0
Content-Type: application/json
{
"status": 429,
"title": "Too many requests.",
"type": "https://developer.bigcommerce.com/api-docs/getting-started/api-status-codes"
}
Die X-Rate-Limit-*-Header entsprechen dem dokumentierten Verhalten von BC. Das echte BC liefert mehr Header und arbeitet mit sekundengenauen Fenstern; STOAR nutzt Laravels Minutenfenster — nah genug für die Kompatibilität mit Client-Bibliotheken.
Ein einzelnes Sanctum-Token, das über alle vier Adapter verwendet wird, teilt sich einen Bucket — die Oberfläche zur Konfiguration ist im Abschnitt Rate-Limiting der Magento-Dokumentation Schritt für Schritt beschrieben.
Siehe auch #
app/Api/Adapters/BigCommerce/Support/StatusTranslator.php— bidirektionales Vokabular-Mapping- BigCommerce-REST-API-Referenz — die Upstream-Spezifikation, die dieser Adapter nachbildet