API-Dokumentation
SoftwareBay REST API v1 — Vollständige Referenz für Entwickler
Übersicht
Die SoftwareBay REST API ermöglicht Geschäftskunden den vollständig programmatischen Zugriff auf Bestelldaten, Lizenzcodes und Download-URLs. Typische Anwendungsfälle sind die ERP-Integration, automatisierte Lizenzverteilung, Buchhaltungsexporte und Revisions-Workflows.
Authentifizierung
Jede API-Anfrage muss den Schlüssel im Authorization-Header als Bearer-Token übergeben:
Authorization: Bearer sb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Fehler-Codes
Alle Fehlerantworten enthalten ein error-Feld mit einer menschenlesbaren Beschreibung.
{
"status": 401,
"error": "Unauthorized – invalid or inactive API key"
}
| HTTP-Code | Bedeutung | Lösung |
|---|---|---|
| 400 | Ungültige Anfrage | Parameter prüfen |
| 401 | Schlüssel ungültig oder gesperrt | Schlüssel im Konto prüfen |
| 403 | Kein Geschäftskonto | Firma/USt-IdNr. im Profil hinterlegen |
| 404 | Bestellung nicht gefunden | Bestellungs-ID prüfen; gehört sie Ihrem Account? |
| 429 | Rate Limit überschritten | Max. 60 Anfragen/Minute warten |
| 500 | Interner Serverfehler | Bitte Support kontaktieren |
Rate Limiting
Das Limit beträgt 60 Anfragen pro Minute pro API-Schlüssel. Bei Überschreitung antworten alle weiteren Anfragen mit 429 Too Many Requests. Das Fenster resetet sich automatisch nach 60 Sekunden.
Endpunkte
Gibt Basisinformationen zum Nutzer des API-Schlüssels zurück. Geeignet zur Verbindungsprüfung und Key-Verifikation.
Antwort-Schema
| Feld | Typ | Beschreibung |
|---|---|---|
| user_id | integer | Interne Nutzer-ID |
| string | E-Mail-Adresse des Accounts | |
| name | string | Vor- und Nachname |
| company | string | Firmenname |
| vat_id | string | USt-Identifikationsnummer |
| api_version | string | Aktuelle API-Version |
Beispiel-Antwort
{
"status": 200,
"data": {
"user_id": 1042,
"email": "firma@beispiel.de",
"name": "Max Mustermann",
"company": "Musterfirma GmbH",
"vat_id": "DE123456789",
"api_version": "1.0"
}
}Gibt eine paginierte Liste aller Bestellungen des Accounts zurück, absteigend nach Bestelldatum sortiert.
Query-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| page | integer | Optional | Seite (Standard: 1) |
| per_page | integer | Optional | Einträge je Seite, 1–50 (Standard: 20) |
| status | string | Optional | Filter nach Status — ausstehend | bezahlt | abgeschlossen | storniert |
Antwort-Schema
| Feld | Typ | Beschreibung |
|---|---|---|
| orders[] | array | Bestellliste (paginiert) |
| orders[].id | integer | Interne Bestell-ID |
| orders[].bestellnummer | string | Lesbare Bestellnummer |
| orders[].status | string | Bestellstatus |
| orders[].zahlungsstatus | string | Zahlungsstatus |
| orders[].gesamtpreis_brutto | decimal | Gesamtbetrag brutto |
| orders[].waehrung | string | ISO 4217 (z.B. EUR) |
| orders[].created_at | datetime | Bestellzeitpunkt (UTC) |
| pagination | object | Paginierungsdaten |
| pagination.page | integer | Aktuelle Seite |
| pagination.per_page | integer | Einträge je Seite |
| pagination.total | integer | Gesamt-Bestellanzahl |
| pagination.pages | integer | Gesamt-Seitenanzahl |
Beispiel-Antwort
{
"status": 200,
"data": {
"orders": [
{
"id": 12345,
"bestellnummer": "S24DXG9F8JK2",
"status": "abgeschlossen",
"zahlungsstatus": "bezahlt",
"gesamtpreis_brutto": "29.99",
"waehrung": "EUR",
"created_at": "2026-04-18 10:23:45",
"lieferstatus": "vollstaendig"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total": 47,
"pages": 3
}
}
}Gibt eine vollständige Bestellung zurück, inklusive aller Positionen, entschlüsselter Lizenzcodes und Download-URLs. Lizenzcodes sind nur für Bestellungen mit Status bezahlt oder abgeschlossen verfügbar.
Pfad-Parameter
| Parameter | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| id | integer | Pflicht | Interne Bestell-ID (aus GET /orders) |
Antwort-Schema (Auszug)
| Feld | Typ | Beschreibung |
|---|---|---|
| items[].license_codes[] | array | Lizenzcodes zur Bestellposition |
| license_codes[].license_key | string | Entschlüsselter Lizenzschlüssel |
| license_codes[].code_typ | string | Code-Typ — retail | volumen | account | abo |
| license_codes[].download_url_64 | string|null | Download-URL (64-bit) |
| license_codes[].download_url_32 | string|null | Download-URL (32-bit) |
| license_codes[].aktivierungen_bestellung | integer | Anzahl erlaubter Aktivierungen |
| billing_address | object | Rechnungsadresse |
Beispiel-Antwort
{
"status": 200,
"data": {
"id": 12345,
"bestellnummer": "S24DXG9F8JK2",
"status": "abgeschlossen",
"gesamtpreis_brutto": "29.99",
"waehrung": "EUR",
"items": [
{
"id": 8821,
"product_name": "Microsoft Office 2021 Professional Plus",
"menge": 1,
"einzelpreis_brutto": "29.99",
"license_codes": [
{
"id": 5501,
"code_typ": "retail",
"license_key": "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
"download_url_64": "https://download.microsoft.com/...",
"download_url_32": null,
"aktivierungen_bestellung": 1
}
]
}
]
}
}Code-Beispiele
Grundlegender API-Aufruf
# Verify account
curl -X GET "https://softwarebay.de/api/v1/me" \
-H "Authorization: Bearer sb_live_YOUR_KEY"
# All orders (first page)
curl -X GET "https://softwarebay.de/api/v1/orders" \
-H "Authorization: Bearer sb_live_YOUR_KEY"
# Order #12345 with license codes
curl -X GET "https://softwarebay.de/api/v1/orders/12345" \
-H "Authorization: Bearer sb_live_YOUR_KEY"define('SB_API_KEY', 'sb_live_YOUR_KEY');
define('SB_API_URL', 'https://softwarebay.de/api/v1');
function sbApi($path) {
$ch = curl_init(SB_API_URL . $path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . SB_API_KEY,
'Accept: application/json',
],
]);
$json = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) throw new RuntimeException("API Error $status");
return json_decode($json, true)['data'];
}
$user = sbApi('/me');
$orders = sbApi('/orders');
$order = sbApi('/orders/12345');import requests
API_KEY = "sb_live_YOUR_KEY"
BASE = "https://softwarebay.de/api/v1"
headers = {"Authorization": f"Bearer {API_KEY}"}
def sb_api(path, params=None):
r = requests.get(BASE + path, headers=headers, params=params)
r.raise_for_status()
return r.json()["data"]
user = sb_api("/me")
orders = sb_api("/orders")
order = sb_api("/orders/12345")const API_KEY = 'sb_live_YOUR_KEY';
const BASE = 'https://softwarebay.de/api/v1';
async function sbApi(path) {
const r = await fetch(BASE + path, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!r.ok) throw new Error(`API ${r.status}`);
return (await r.json()).data;
}
const user = await sbApi('/me');
const orders = await sbApi('/orders');
const order = await sbApi('/orders/12345');using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "sb_live_YOUR_KEY");
async Task<JsonElement> SbApi(string path) {
var json = await client.GetStringAsync($"https://softwarebay.de/api/v1{path}");
return JsonDocument.Parse(json).RootElement.GetProperty("data");
}
var user = await SbApi("/me");
var orders = await SbApi("/orders");
var order = await SbApi("/orders/12345");Alle Bestellungen paginiert abrufen
// Collect all pages
$all = []; $page = 1;
do {
$result = sbApi("/orders?page={$page}&per_page=50");
$all = array_merge($all, $result['orders']);
$pages = $result['pagination']['pages'];
$page++;
usleep(200000); // 200ms delay – respect rate limit
} while ($page <= $pages);
echo count($all) . " orders loaded";import time
def all_orders():
orders, page = [], 1
while True:
data = sb_api("/orders", {"page": page, "per_page": 50})
orders.extend(data["orders"])
if page >= data["pagination"]["pages"]: break
page += 1
time.sleep(0.2) # respect rate limit
return orders
result = all_orders()
print(f"{len(result)} orders loaded")async function allOrders() {
const all = []; let page = 1;
do {
const data = await sbApi(`/orders?page=${page}&per_page=50`);
all.push(...data.orders);
if (page >= data.pagination.pages) break;
page++;
await new Promise(r => setTimeout(r, 200));
} while (true);
return all;
}Nur abgeschlossene Bestellungen abrufen
curl "https://softwarebay.de/api/v1/orders?status=abgeschlossen&per_page=50" \
-H "Authorization: Bearer sb_live_YOUR_KEY"
Robuste Fehlerbehandlung
function sbApiSafe($path, $retry = 3) {
for ($i = 0; $i < $retry; $i++) {
$ch = curl_init(SB_API_URL . $path);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . SB_API_KEY],
CURLOPT_TIMEOUT => 15,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 200) return json_decode($body, true)['data'];
if ($status === 429) { sleep(60); continue; }
$err = json_decode($body, true)['error'] ?? "HTTP $status";
throw new RuntimeException("API Error: $err");
}
throw new RuntimeException("Rate limit not resolved after $retry attempts");
}import time, requests
def sb_api_safe(path, params=None, retries=3):
for attempt in range(retries):
r = requests.get(BASE + path, headers=headers, params=params, timeout=15)
if r.status_code == 200: return r.json()["data"]
if r.status_code == 429:
time.sleep(60)
continue
r.raise_for_status()
raise RuntimeError("Rate limit not resolved")async function sbApiSafe(path, retries = 3) {
for (let i = 0; i < retries; i++) {
const r = await fetch(BASE + path, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (r.ok) return (await r.json()).data;
if (r.status === 429) { await new Promise(res => setTimeout(res, 60000)); continue; }
const err = (await r.json()).error ?? `HTTP ${r.status}`;
throw new Error(err);
}
}Massen-Export: Alle Lizenzcodes als CSV
// Export all completed orders → CSV with license codes
$fp = fopen('licenses.csv', 'w');
fputcsv($fp, ['Order#', 'Product', 'License Key', 'Type', 'Download']);
$page = 1;
do {
$list = sbApi("/orders?status=abgeschlossen&per_page=50&page={$page}");
foreach ($list['orders'] as $o) {
$order = sbApi("/orders/{$o['id']}");
foreach ($order['items'] as $item) {
foreach ($item['license_codes'] as $code) {
fputcsv($fp, [
$order['bestellnummer'],
$item['product_name'],
$code['license_key'],
$code['code_typ'],
$code['download_url_64'] ?? '',
]);
}
}
usleep(100000);
}
$page++;
} while ($page <= $list['pagination']['pages']);
fclose($fp);
echo "Export complete: licenses.csv";import csv, time
with open("licenses.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow(["Order#", "Product", "License Key", "Type", "Download"])
page = 1
while True:
data = sb_api("/orders", {"status": "abgeschlossen", "per_page": 50, "page": page})
for o in data["orders"]:
order = sb_api(f"/orders/{o['id']}")
for item in order["items"]:
for code in item["license_codes"]:
writer.writerow([
order["bestellnummer"], item["product_name"],
code["license_key"], code["code_typ"],
code.get("download_url_64", ""),
])
time.sleep(0.1)
if page >= data["pagination"]["pages"]: break
page += 1
print("Export complete: licenses.csv")Live API-Tester
Testen Sie Ihren API-Schlüssel direkt im Browser. Die Anfrage läuft über Ihre eigene Verbindung — der Schlüssel wird nicht an unsere Server übertragen.
Live API-Tester
API-Schlüssel verwalten
Schlüssel werden im Kundenkonto erstellt (max. 5 pro Account) und können jederzeit widerrufen werden. Ein einmal erstellter Schlüssel kann nicht wiederhergestellt werden.
Zum API-Bereich im Kundenkonto