Schnellstart in fünf Minuten
Erst ausprobieren, ohne Echtdaten? Die Sandbox bietet erfundene Musterdaten und eigene Test-Tokens (m2h_test_…) — nutzbar, solange der API-Zugang aktiv ist (auch in der kostenlosen Testzeit), samt Webhooks und Ereignis-Simulation per Beispielaufruf.
Voraussetzungen
- Die API ist für Ihre Organisation freigeschaltet (Testzeit oder Buchung). Unter Administration → API-Zugänge sehen Sie den Stand; ohne Freischaltung lässt sich kein Token anlegen.
- Sie haben in der Verwaltung das Recht API-Zugang mit Vollzugriff (nur damit lassen sich Tokens anlegen) und selbst alle Rechte, die das Token bekommen soll.
- Ein Rechner oder Server mit Internetzugang, der https-Anfragen senden kann (curl genügt). Die API ist für Server-zu-Server-Aufrufe gedacht, nicht für Browser.
1. Token anlegen
In der Verwaltung: Administration → API-Zugänge → Neues Token. Name vergeben (z. B. „Schnellstart“), als Berechtigung genau einen Scope wählen — für diesen Schnellstart locations:read („Garagenparks lesen“; der Ersteller braucht dafür das Recht Standorte mit Lesezugriff) — und eine Laufzeit wählen. Weitere Scopes: Berechtigungen.
2. Token bereitstellen
Legen Sie das Token als Umgebungsvariable M2H_API_TOKEN ab — nie direkt im Quelltext.
$env:M2H_API_TOKEN = "m2h_live_…"export M2H_API_TOKEN="m2h_live_…"3. Erster Aufruf: Ihre Garagenparks
Die curl-Beispiele sind in Bash-Schreibweise ($VARIABLE, \ am Zeilenende, $(uuidgen)): Sie laufen unter Linux, macOS und Git Bash. Unter Windows nehmen Sie das PowerShell-Beispiel direkt darunter.
curl -s "https://api.manage2hero.com/v1/locations" \
-H "Authorization: Bearer $M2H_API_TOKEN"$kopf = @{ Authorization = "Bearer $env:M2H_API_TOKEN" }
Invoke-RestMethod -Uri "https://api.manage2hero.com/v1/locations" -Headers $kopfconst res = await fetch('https://api.manage2hero.com/v1/locations', {
headers: { Authorization: `Bearer ${process.env.M2H_API_TOKEN}` },
});
const body = await res.json();
if (!body.success) throw new Error(`${body.error.code}: ${body.error.message}`);
const daten = body.data; // hier weiterverarbeitenimport os, requests
res = requests.get(
"https://api.manage2hero.com/v1/locations",
headers={"Authorization": f"Bearer {os.environ['M2H_API_TOKEN']}"},
timeout=30,
)
body = res.json()
if not body["success"]:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"])Antwort (200, vollständig)
{
"success": true,
"data": {
"items": [
{
"id": "6a1f0c2e-4d7b-4b8e-9f10-2c3d4e5f6a7b",
"code": "HH01",
"name": "Garagenpark Hamburg Nord",
"street": "Beispielweg",
"house_number": "12",
"postal_code": "22297",
"city": "Hamburg",
"country_code": "DE",
"active": true
}
],
"next_cursor": null
},
"request_id": "req_4a2c9e1b7e84d2f9c0a6b3d5e7f1a2c9"
}items enthält je Garagenpark ein Objekt; ohne Garagenpark ist die Liste leer ([]). next_cursor ist null, wenn es keine weitere Seite gibt. Mit der id eines Garagenparks rufen Sie anschließend z. B. die Vermietungsquote ab: GET /v1/locations/{id}/occupancy.
Typische Fehler beim ersten Aufruf
| HTTP | error.code | Ursache | Abhilfe |
|---|---|---|---|
| 401 | missing_token | Der Kopf Authorization fehlt oder ist leer (häufig: die Umgebungsvariable ist nicht gesetzt). | Kopf Authorization: Bearer <token> senden; Variable prüfen. |
| 401 | invalid_token | Token falsch kopiert (Leerzeichen, Anführungszeichen), widerrufen oder der Ersteller wurde deaktiviert. | Token neu kopieren; sonst in der Verwaltung ein neues anlegen. |
| 401 | token_expired | Die Laufzeit des Tokens ist vorbei. | Neues Token anlegen und austauschen. |
| 401 | wrong_environment | Ein Token der Umgebung stg oder dev wurde gegen Produktion verwendet (oder umgekehrt). | Token der passenden Umgebung (live, stg, dev) verwenden. |
| 403 | insufficient_scope | Dem Token fehlt der Scope des Endpunkts; error.required_scope nennt ihn. | Neues Token mit diesem Scope anlegen — ein bestehendes lässt sich nicht erweitern. |
| 403 | insufficient_permissions | Der Ersteller des Tokens hat das nötige Recht in der Verwaltung nicht (mehr). | Recht ergänzen; das Token funktioniert danach ohne Änderung wieder. |
| 429 | rate_limited | Zu viele Aufrufe in kurzer Zeit. | Retry-After abwarten, dann wiederholen (siehe Grenzen). |
{
"success": false,
"error": {
"code": "insufficient_scope",
"message": "Das API-Token hat nicht die nötige Berechtigung (Scope).",
"required_scope": "locations:read"
},
"request_id": "req_8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f"
}Alle Fehlercodes mit Handlungsanweisung: Fehlercodes; Mengengrenzen: Grenzen.
4. Optional: Ereignisse per Webhook empfangen
Statt regelmäßig abzufragen, meldet Manage²Hero Ereignisse (Zahlungseingang, Mahnung, Vertrag, Rechnung, Dokument, E-Mail, Schaden) per signiertem POST an Ihr System. Der kürzeste Weg:
- Webhook anlegen: neues Token mit
webhooks:manage(Ersteller: API-Zugang mit Vollzugriff) und den Lese-Scopes der Ereignisse, die Sie abonnieren. Ihre Adresse muss eine öffentlich erreichbare https-Adresse auf Port 443 sein.
curl -s -X POST "https://api.manage2hero.com/v1/webhooks" \
-H "Authorization: Bearer $M2H_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
--data '{"url":"https://erp.example.com/hooks/manage2hero","events":["payment.received","invoice.created"],"description":"ERP Buchhaltung"}'$kopf = @{
Authorization = "Bearer $env:M2H_API_TOKEN"
"Idempotency-Key" = [guid]::NewGuid().ToString()
}
$body = '{"url":"https://erp.example.com/hooks/manage2hero","events":["payment.received","invoice.created"],"description":"ERP Buchhaltung"}'
Invoke-RestMethod -Method Post -Uri "https://api.manage2hero.com/v1/webhooks" -Headers $kopf -ContentType "application/json; charset=utf-8" -Body $bodyimport { createHash, randomUUID } from 'node:crypto';
import { linkSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
// Schlüssel EINMAL erzeugen und VOR dem Senden dauerhaft speichern (hier: Datei, eine je Vorgang). Nach einem
// Neustart wird derselbe Schlüssel gelesen. Für einen neuen, anderen Vorgang einen neuen Dateinamen wählen. Datei erst nach der endgültigen Antwort löschen.
const VORGANG = 'auftrag-2026/1001'; // EIGENE Kennung je Vorgang setzen (z. B. Auftrags-Id); nie für zwei Vorgänge wiederverwenden
const VORGANG_ID = createHash('sha256').update(VORGANG).digest('hex').slice(0, 16); // als Dateiname gehasht: beliebige Zeichen (/, \ …) in der Kennung sind unkritisch
const KEY_FILE = `idempotency-key-post-v1-webhooks-${VORGANG_ID}.txt`;
const neu = randomUUID();
const tmp = `${KEY_FILE}.${neu}`; // eindeutiger Name je Versuch, nie eine vorhandene Datei überschreiben
writeFileSync(tmp, neu, { flag: 'wx' }); // erst vollständig in eine temporäre Datei schreiben
try {
linkSync(tmp, KEY_FILE); // veröffentlicht sie atomar, ohne eine vorhandene zu überschreiben
} catch (e) {
if (e.code !== 'EEXIST') throw e; // vorhandener Schlüssel bleibt unverändert
} finally {
unlinkSync(tmp);
}
const idempotencyKey = readFileSync(KEY_FILE, 'utf8').trim();
const res = await fetch('https://api.manage2hero.com/v1/webhooks', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.M2H_API_TOKEN}`,
'Content-Type': 'application/json',
// Bei jeder Wiederholung (z. B. nach einem Timeout) diesen gespeicherten Schlüssel erneut senden.
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify({
"url": "https://erp.example.com/hooks/manage2hero",
"events": [
"payment.received",
"invoice.created"
],
"description": "ERP Buchhaltung"
}),
});
const body = await res.json();
if (!body.success) throw new Error(`${body.error.code}: ${body.error.message}`);
const daten = body.data; // hier weiterverarbeitenimport hashlib, os, uuid, requests
from pathlib import Path
# Schlüssel EINMAL erzeugen und VOR dem Senden dauerhaft speichern (hier: Datei, eine je Vorgang). Nach einem
# Neustart wird derselbe Schlüssel gelesen. Für einen neuen, anderen Vorgang einen neuen Dateinamen wählen. Datei erst nach der endgültigen Antwort löschen.
VORGANG = "auftrag-2026/1001" # EIGENE Kennung je Vorgang setzen (z. B. Auftrags-Id); nie für zwei Vorgänge wiederverwenden
VORGANG_ID = hashlib.sha256(VORGANG.encode()).hexdigest()[:16] # als Dateiname gehasht: beliebige Zeichen (/, \ …) in der Kennung sind unkritisch
KEY_FILE = Path(f"idempotency-key-post-v1-webhooks-{VORGANG_ID}.txt")
neu = str(uuid.uuid4())
tmp = Path(f"{KEY_FILE}.{neu}") # eindeutiger Name je Versuch, nie eine vorhandene Datei überschreiben
with tmp.open("x") as f:
f.write(neu) # erst vollständig in eine temporäre Datei schreiben
try:
os.link(tmp, KEY_FILE) # veröffentlicht sie atomar, ohne eine vorhandene zu überschreiben
except FileExistsError:
pass # vorhandener Schlüssel bleibt unverändert
finally:
tmp.unlink()
idempotency_key = KEY_FILE.read_text().strip()
res = requests.post(
"https://api.manage2hero.com/v1/webhooks",
headers={
"Authorization": f"Bearer {os.environ['M2H_API_TOKEN']}",
"Idempotency-Key": idempotency_key,
},
json={"url":"https://erp.example.com/hooks/manage2hero","events":["payment.received","invoice.created"],"description":"ERP Buchhaltung"},
timeout=30,
)
body = res.json()
if not body["success"]:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"])- Geheimnis speichern: Die Antwort (201) enthält einmalig das
secret(whsec_…). Legen Sie es sofort im Secret-Speicher Ihres Empfängers ab. Verloren? MitPOST /v1/webhooks/{id}/rotate-secreterzeugen Sie ein neues. - Testen:
POST /v1/webhooks/{id}/test(mitIdempotency-Key) stellt ein Testereigniswebhook.testein; der Server sendet es innerhalb von etwa einer Minute.
curl -s -X POST "https://api.manage2hero.com/v1/webhooks/3f6c1b52-8a47-4d09-9e1c-5b2a7d4e6f80/test" \
-H "Authorization: Bearer $M2H_API_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"- Zustellstatus prüfen:
GET /v1/webhooks/{id}/deliverieszeigt je Zustellungstatus(pending,succeeded,failed,abandoned,paused),response_status(Antwortcode Ihres Empfängers) und einen festenerror-Code.succeededmitresponse_status: 200heißt: Ihr Empfänger funktioniert. Eine Nachricht wird bis zu 6 Mal versucht; scheitert der letzte Versuch, wird der Webhook abgeschaltet (active: false). Der Zustellverlauf wird 30 Tage aufbewahrt.
pending). Signatur prüfen, Wiederholungen, Abschaltung und Betrieb: das Webhooks-Handbuch. Ein lauffähiges Empfänger-Projekt (Signaturprüfung, Eingangstabelle, Abgleich) gibt es als ZIP zum Herunterladen (ohne Anmeldung, Beispielcode unter MIT-Lizenz). Die Nachrichten sind in der openapi.json im Abschnitt webhooks beschrieben (nicht unter paths; wichtig für Codegeneratoren). Die wichtigsten Regeln für den Betrieb fasst die Integrations-Checkliste zusammen. Alle Aufrufe zum Ausprobieren gibt es als Postman-Sammlung.