Signals
20 Credits pro erfolgreichem Aufruf · Katalog kostenlos • 60/min
Ein Signal ist eine normalisierte Änderung aus dem Handelsregister. Du kannst Signals unternehmensübergreifend durchsuchen, nach Themen filtern oder ein einzelnes Signal per ID abrufen.
Endpunkte
| Method | Path | 説明 |
|---|---|---|
| GET | /v1/signals | Signals auflisten und filtern. Bis zu 20 pro Seite, Blättern per Cursor. |
| GET | /v1/signals/catalog | Alle öffentlichen Themen-Codes mit Bezeichnungen, Beschreibungen und Stufen. Kostenlos. |
| GET | /v1/signals/{signal_id} | Ein einzelnes Signal per ID abrufen. |
Eine Signal-ID ist 1 bis 255 Zeichen lang, besteht aus A-Z, a-z, 0-9, Punkt, Unterstrich, Tilde und Bindestrich und beginnt mit einem Buchstaben oder einer Ziffer. Alles andere liefert ein schlichtes JSON-404 ohne Credit- und Request-ID-Header. Andere Methoden als GET und HEAD liefern 405.
Themen
Du filterst Signals über Themen. Es gibt sieben Codes, und sie sind case-sensitiv: NEW_REGISTRATIONS funktioniert, new_registrations nicht.
| Code | 名前 | 説明 |
|---|---|---|
| NEW_REGISTRATIONS | Neueintragungen | Neu ins Handelsregister eingetragene Unternehmen. |
| MASTER_DATA_CHANGES | Stammdatenänderungen | Änderungen von Firmenname, Sitz, Geschäftsanschrift oder Registerzuständigkeit. |
| CLOSURES | Löschungen & Auflösungen | Auflösung, Liquidation, Löschung oder Erlöschen von Unternehmen. |
| ROLE_HOLDER_CHANGES | Führungswechsel | Eintritte, Austritte und Wechsel von Geschäftsführung, Vorstand und Prokura. |
| CAPITAL_CHANGES | Kapitaländerungen | Änderungen am Stamm-, Grund-, Haft- oder genehmigten Kapital. |
| INSOLVENCIES | Insolvenzen Pro | Eröffnungen, Sicherungsmaßnahmen und Beendigungen von Insolvenzverfahren. |
| TRANSFORMATIONS | Umwandlungen & M&A Max | Verschmelzungen, Spaltungen, Formwechsel, Vermögensübertragungen, Unternehmensverträge und Squeeze-outs. |
Themen und Dein Tarif
Fünf Themen stehen jedem Account offen, auch ohne Abo und mit Plus. INSOLVENCIES braucht Pro oder Max, TRANSFORMATIONS braucht Max. Fragst Du ein Thema oberhalb Deines Tarifs an, bekommst Du 403 PLAN_REQUIRED bei 0 Credits — im Listen- wie im Detailendpunkt.
Ohne topics bekommst Du nur die Themen aus Deinem Tarif: fünf ohne Plan und mit Plus, sechs mit Pro, sieben mit Max. Die Antwort sagt davon nichts: filters.topics kommt so oder so als leere Liste zurück. Schick topics also mit, sobald der genaue Umfang zählt.
Das Thema OTHER
event.topic ist einer der sieben Codes oben oder OTHER. OTHER steht für jedes Registerereignis außerhalb der sieben, etwa Zweckänderungen, Zweigniederlassungen und Berichtigungen. Der Detailendpunkt liefert es regelmäßig, im Listenendpunkt ist es selten. OTHER ist nicht tarifgebunden, jeder Account kann es lesen. Filtern kannst Du damit nicht: topics=OTHER liefert 422.
Authentifizierung
Alle drei Endpunkte brauchen einen authentifizierten Account. Anonymen Zugriff gibt es nicht, eine bestimmte Token-Ability ist nicht nötig.
| Zugang | Hinweise |
|---|---|
| x-api-key: YOUR_API_KEY | Ein aktiver API-Key aus Deinem Dashboard. Nimm diesen Weg — so landet das Geheimnis nicht in URLs und Logs. |
| ?api_key=YOUR_API_KEY | Bei Signals erlaubt. Der Wert wird aus Query-String und Logs entfernt. Schickst Du beides, gewinnt der Header. |
| Authorization: Bearer YOUR_TOKEN | Jedes gültige, nicht abgelaufene Personal Access Token. |
Fehlt der Zugang oder ist er ungültig, bekommst Du 401 UNAUTHORIZED. Eine nicht bestätigte E-Mail-Adresse und ein gesperrter Account liefern beide 403 UNAUTHORIZED mit demselben detail: „Signals access is not available for this account.“ Die beiden Fälle sind bewusst nicht unterscheidbar.
Parameter
Listenparameter
| 名前 | タイプ | 説明 |
|---|---|---|
| cursor | string | Der next_cursor aus Deiner vorherigen Antwort. Schick ihn unverändert zurück und zerlege ihn nicht. Höchstens 8192 Zeichen. |
| topics | string list | Ein oder mehrere Codes aus der Tabelle oben. topics=A&topics=B, topics[]=A&topics[]=B und topics=A,B bedeuten dasselbe. Werte werden dedupliziert und sortiert. Die Codes sind case-sensitiv. |
| organization_ids | string list | Entity-IDs der Unternehmen, auf die sich die Signals beziehen, in denselben drei Listenformen. Höchstens 5 pro Anfrage, jede 1 bis 128 Zeichen aus A-Z, a-z, 0-9, Punkt, Unterstrich, Tilde und Bindestrich. |
| from / to | date | Anfang und Ende des Zeitraums. Nutze YYYY-MM-DD oder ein zeitzonenloses YYYY-MM-DDTHH:MM:SS mit optional 1 bis 6 Nachkommastellen. Ein angehängtes Z oder ein Offset wie +02:00 liefert 422. to muss gleich from oder später sein; ein einzelner Tag ist gültig. |
Unbekannte Parameter werden abgewiesen
Der Listenendpunkt akzeptiert cursor, topics, organization_ids, from und to. Jeder andere Query-Parameter liefert 422 mit der Meldung „Unknown Signals parameter.“ Gemeldet wird nur der erste unbekannte Parameter, korrigiere sie also einzeln. Seitengröße, Sortierung und Feldauswahl kannst Du nicht ändern.
GET /api/v1/signals?topics=NEW_REGISTRATIONS&limit=5
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
X-Credits-Charged: 0
X-Request-Id: req_01k1c2...
{
"type": "https://handelsregister.ai/problems/invalid-request",
"title": "Invalid request",
"status": 422,
"code": "INVALID_REQUEST",
"detail": "One or more Signals parameters are invalid.",
"invalid_params": {
"limit": ["Unknown Signals parameter."]
},
"meta": {
"request_id": "req_01k1c2...",
"request_credit_cost": 0,
"credits_remaining": 95
}
}
Der Detailendpunkt nimmt keine Query-Parameter. Die ID im Pfad genügt, alles Zusätzliche liefert 422.
Der Katalog liefert dieselben sieben Themen maschinenlesbar: code, deutsche und englische Bezeichnung und Beschreibung, die nötige Stufe (ALL, PRO oder MAX) und ein observed-Flag für Themen, die schon Daten führen. Alle sieben erscheinen unabhängig von Deinem Tarif. Er ist kostenlos und nimmt keine Query-Parameter — jeder Parameter liefert 422.
Validierungsmeldungen
Ein Validierungsfehler liefert 422 mit einem invalid_params-Objekt, dessen Schlüssel die Parameternamen sind. Diese Meldungen kannst Du bekommen:
| Meldung | Wann |
|---|---|
| Unknown Signals parameter. | Ein Query-Parameter außerhalb der erlaubten Menge. Gemeldet wird nur der erste. |
| Unknown topics value. | Ein Themen-Code, der keiner der sieben öffentlichen Codes ist. Kleinschreibung gilt als unbekannt. |
| organization_ids accepts at most 50 values. | Mehr als 5 organization_ids in einer Anfrage. |
| organization_ids contains an invalid identifier. | Eine ID mit einem nicht unterstützten Zeichen oder mit mehr als 128 Zeichen. |
| from must use YYYY-MM-DD or a timezone-naive ISO datetime with seconds. | from oder to ist weder YYYY-MM-DD noch ein zeitzonenloser Zeitstempel mit Sekunden. Ein angehängtes Z oder ein Offset landet ebenfalls hier. |
| to must be the same as or later than from. | to liegt vor from. |
| cursor is invalid. | cursor ist leer, länger als 8192 Zeichen oder enthält Steuerzeichen. |
| cursor does not match these filters. | Der Cursor wurde nicht für diese Filter ausgegeben. Starte ohne Cursor neu. |
| signal_id is invalid. | Die Signal-ID im Pfad ist leer oder länger als 255 Zeichen. |
Beispiel
Beispiel für eine Listenanfrage
NEW_REGISTRATIONS und CAPITAL_CHANGES funktionieren in jedem Tarif. Tauschst Du sie gegen INSOLVENCIES (Pro oder Max) oder TRANSFORMATIONS (Max), liefern niedrigere Tarife 403 PLAN_REQUIRED.
# NEW_REGISTRATIONS and CAPITAL_CHANGES are open to every plan.
# INSOLVENCIES needs Pro or Max, TRANSFORMATIONS needs Max.
curl --get 'https://handelsregister.ai/api/v1/signals' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Accept: application/json' \
--data-urlencode 'topics=NEW_REGISTRATIONS,CAPITAL_CHANGES' \
--data-urlencode 'from=2026-07-01'
Beispielantwort
{
"signals": [
{
"event": {
"id": "0123456789abcdef0123456789abcdef",
"topic": "CAPITAL_CHANGES",
"topic_name": {
"de": "Kapitaländerungen",
"en": "Capital changes"
},
"occurred_on": "2026-07-25",
"announced_on": "2026-07-25",
"date_basis": "REGISTER_ENTRY"
},
"organization": {
"type": "ORGANIZATION",
"entity_id": "0123456789abcdef0123456789abcdef",
"current_profile": {
"name": "Beispiel Handel GmbH",
"status": {
"code": "ACTIVE"
}
}
},
"register_entry": {
"entry_number": "7",
"entry_date": "2026-07-25",
"phase": "INCREASED",
"description_text": "Das Stammkapital wurde erhöht.",
"context": "PRIMARY",
"flags": []
},
"source": {
"kind": "COMMERCIAL_REGISTER"
},
"details": {
"schema": "CAPITAL_CHANGE",
"capital_kind": "SHARE_CAPITAL",
"resulting_amount": {
"amount": "50000.00",
"currency": "EUR",
"source_text": "50.000,00 EUR"
}
}
}
],
"pagination": {
"mode": "CURSOR",
"limit": 20,
"returned": 1,
"has_more": true,
"next_cursor": "sgc1.eyJiIjoiYTNmMmVkZWJlNWU5Iiw..."
},
"filters": {
"topics": ["CAPITAL_CHANGES", "NEW_REGISTRATIONS"],
"organization_ids": [],
"from": "2026-07-01"
},
"warnings": [],
"meta": {
"schema_version": "1.0",
"request_id": "req_01k1c2...",
"request_credit_cost": 20,
"credits_remaining": 95
}
}
In filters steht normalisiert, was Du gesendet hast: topics kommt dedupliziert und sortiert zurück, und from erscheint nur, weil es mitgeschickt wurde.
Aufbau der Antwort
Eine Listenantwort hat immer diese fünf Member. Enum-Werte kommen in GROSSBUCHSTABEN. Felder ohne Wert fehlen, statt als null zu erscheinen, und ein Objekt, das dadurch alle Member verliert, fehlt ebenfalls. Leere Listen bleiben, eine leere signals-Liste ist also ein echter Wert.
| Feld | Inhalt |
|---|---|
| signals | Bis zu 20 Einträge, neuestes Veröffentlichungsdatum zuerst. Eine leere Liste ist eine gültige Seite. |
| pagination | mode ist immer CURSOR. limit ist immer 20, und 20 ist das Maximum, keine Zusage. returned zählt diese Seite, has_more sagt Dir, ob Du weiterblättern musst, und next_cursor fehlt auf der letzten Seite. |
| filters | Deine Filter, normalisiert. topics und organization_ids sind immer da, ohne Angabe als leere Listen; from, to und cursor erscheinen nur, wenn Du sie gesendet hast. |
| warnings | Leer, oder ein Eintrag mit dem Code SOURCE_CATALOG_WARNING, wenn ein Filter im aktuellen Quellkatalog fehlt. |
| meta | schema_version (1.0), request_id (nenne sie in Support-Anfragen), request_credit_cost, credits_remaining nach der Buchung sowie generated_at und profiles_resolved_at, sofern verfügbar. |
Im Inneren eines Signals
Jeder Eintrag hat event, organization und source. parties, register_entry und details erscheinen nur, wenn die Quelle etwas dazu hergibt.
| Feld | Inhalt |
|---|---|
| event.id | Reich sie an den Detailendpunkt weiter und überspringe damit Duplikate. |
| event.occurred_on, event.announced_on | Reine YYYY-MM-DD-Daten. Beide können fehlen, verlass Dich also nie darauf, dass sie da sind. |
| event.date_basis | Welche Art Datum die Quelle verwendet hat: REGISTER_ENTRY, SOURCE_EVENT, ROLE_HOLDER_EVENT, COURT_PUBLICATION, PUBLICATION oder OTHER. |
| organization, parties | Beide tragen ein current_profile mit name, registration, legal_form, seat und status. |
| details | Zusatzfelder, die vom Ereignistyp abhängen, gekennzeichnet über details.schema. Geldbeträge nutzen amount, currency und source_text. |
Der Detailendpunkt liefert denselben Aufbau unter dem Schlüssel signal. Er kann auch ein Ereignis ausliefern, das im Listenendpunkt nicht aufgetaucht wäre.
Ereignistypen: event.type
Manche Ereignisse tragen in event.type einen feineren Typ, mit deutscher und englischer Bezeichnung in event.type_name. Heute haben nur Funktionsträger-Ereignisse einen, den meisten Signals fehlen also beide Felder. Wo kein Typ freigegeben ist, fehlen beide Felder ganz — null kommt nie. Prüfe deshalb, ob event.type da ist, bevor Du es ausliest.
"event": {
"id": "0123456789abcdef0123456789abcdef",
"topic": "ROLE_HOLDER_CHANGES",
"topic_name": {
"de": "Führungswechsel",
"en": "Management changes"
},
"type": "ROLE_HOLDER_ENTRY",
"type_name": {
"de": "Funktionsträger eingetreten",
"en": "Role holder joined"
},
"occurred_on": "2026-07-25",
"announced_on": "2026-07-25",
"date_basis": "ROLE_HOLDER_EVENT"
}
Diese Werte werden heute ausgeliefert. Alle gehören zu ROLE_HOLDER_CHANGES, das jeder Account lesen kann:
| event.type | Bedeutung |
|---|---|
| ROLE_HOLDER_ENTRY | Ein Funktionsträger ist hinzugekommen: neue Bestellung, zusätzliche Position oder Rückkehr. type_name: „Funktionsträger eingetreten“. |
| ROLE_HOLDER_EXIT | Ein Funktionsträger hat eine Position verlassen, auch ohne genannten Grund. type_name: „Funktionsträger ausgeschieden“. |
| ROLE_HOLDER_TRANSITION | Ein Funktionsträger hat einen anderen im selben Registereintrag abgelöst. type_name: „Funktionsträgerwechsel“. |
| ROLE_HOLDER_CHANGE | Die Angaben zu einem bestehenden Funktionsträger haben sich geändert, ohne Eintritt oder Austritt. type_name: „Funktionsträger geändert“. |
- event.type_name erscheint nur zusammen mit event.type. Es ist ein Bezeichnungsobjekt mit einem de- und einem en-Member — zeig es Menschen, verzweige aber über event.type.
- event.type ist kein Filter. Einen Parameter type gibt es nicht, und schickst Du einen mit, kommt 422. Filtere über topics und grenze in Deinem eigenen Code weiter ein.
- Ein Signal ohne event.type kann später eines bekommen, ohne dass sich id, topic oder sonst etwas ändert.
Was nie zurückkommt
- null-Werte und jedes Objekt, das dadurch leer bleibt. Leere Listen bleiben erhalten.
- Quellbelege: evidence_excerpt, evidence_text, evidence_redactions und evidence_text_status werden immer entfernt.
- Interne Details: der feingliedrige Quellcode hinter einem Thema, first_seen_at, detail_completeness und observed_identity.
- details-Felder außerhalb der für ihr schema definierten Menge sowie Signals zu gesperrten Unternehmen. Das passiert nach dem Blättern, eine Seite kann deshalb kurz sein, während has_more true bleibt.
Paginierung
Geblättert wird nur per Cursor, neuestes Veröffentlichungsdatum zuerst. Zum Weiterblättern schickst Du pagination.next_cursor unverändert und mit exakt denselben Filtern zurück.
- 20 ist die maximale Seitengröße, keine Garantie. Kurze und sogar leere Seiten sind normal — nicht aufgelöste Profile und gesperrte Entitäten fallen aus einer Seite heraus.
- Blättere weiter, solange pagination.has_more true ist, auch direkt nach einer leeren Seite. Hör auf, sobald es false ist; next_cursor fehlt dann, statt null zu sein.
- Die Zustellung ist at-least-once. Dasselbe Signal kann also später erneut auftauchen — überspringe Duplikate über event.id.
- Jede Seite ist ein eigener erfolgreicher Aufruf zu 20 Credits, leere eingeschlossen. Eine Gesamtzahl gibt es nicht und keinen Sprung zu Seite N.
Cursor gehören zu ihrer Abfrage
Behandle einen Cursor als undurchsichtig: nicht selbst bauen, nicht zerlegen, unter 8192 Zeichen halten. Einen Filter mitten im Blättern zu ändern, wird nicht unterstützt. Meist bekommst Du 422 INVALID_CURSOR bei 0 Credits, manche Wechsel werden aber angenommen und liefern dann eine falsch versetzte Seite, die trotzdem 20 Credits kostet. Willst Du die Filter ändern, starte eine neue Abfrage ohne Cursor.
Sicher blättern
import requests
URL = "https://handelsregister.ai/api/v1/signals"
HEADERS = {"x-api-key": "YOUR_API_KEY", "Accept": "application/json"}
FILTERS = {"topics": "NEW_REGISTRATIONS,CAPITAL_CHANGES"}
seen = set()
cursor = None
while True:
params = dict(FILTERS) # identical filters on every page
if cursor:
params["cursor"] = cursor
response = requests.get(URL, headers=HEADERS, params=params)
response.raise_for_status() # 20 credits per successful page
page = response.json()
for signal in page["signals"]: # 0 to 20 items, short pages are normal
event_id = signal["event"]["id"]
if event_id in seen:
continue # at-least-once: repeats are expected
seen.add(event_id)
handle(signal)
if not page["pagination"]["has_more"]:
break # last page: next_cursor is absent
cursor = page["pagination"]["next_cursor"]
Credits
- Eine Listenseite kostet 20 Credits, ein Detailaufruf ebenfalls. Der Katalog ist kostenlos und prüft nicht einmal Dein Guthaben.
- Abgebucht wird kurz, bevor die Antwort rausgeht. meta.credits_remaining und X-Credits-Charged beschreiben deshalb, was tatsächlich passiert ist.
- Unter 20 Credits bekommst Du 402 INSUFFICIENT_CREDITS, bevor überhaupt etwas passiert. Scheitert die Abbuchung, bekommst Du 402 BILLING_FAILED, es wird nichts berechnet und die Daten werden verworfen — wiederhole den Aufruf.
- Fehlgeschlagene Anfragen werden nie berechnet: 401, 402, 403, 404, 422, 429 und 503 kosten alle 0 Credits.
- Im Ledger stehen topics, organization_ids, from, to und ob ein Cursor verwendet wurde. Detailaufrufe protokollieren nichts davon.
Fehler
Signals-Fehler kommen als JSON mit einem maschinenlesbaren code, auf den Du verzweigen kannst. Dazu gibt es type, title, status, detail und meta. invalid_params gibt es nur bei Validierungsfehlern. Die einzige Ausnahme ist der 429, siehe unten.
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
X-Credits-Charged: 0
X-Request-Id: req_01k1c2...
{
"type": "https://handelsregister.ai/problems/plan-required",
"title": "Plan upgrade required",
"status": 403,
"code": "PLAN_REQUIRED",
"detail": "Your current plan does not include the requested topic(s): INSOLVENCIES requires the Pro plan.",
"meta": {
"request_id": "req_01k1c2...",
"request_credit_cost": 0,
"credits_remaining": 95
}
}
| Status | code | Wann |
|---|---|---|
| 401 | UNAUTHORIZED | Kein Zugang oder ein ungültiger. credits_remaining ist null; ein X-Request-Id-Header fehlt. |
| 402 | INSUFFICIENT_CREDITS | Dein Guthaben liegt unter 20 Credits. Es wurde nichts abgerufen. Der Katalog liefert das nie. |
| 402 | BILLING_FAILED | Die Daten wurden geholt, die Abbuchung ist gescheitert. Es wurde nichts berechnet und es kommen keine Daten zurück — wiederhole den Aufruf. |
| 403 | UNAUTHORIZED | Nicht bestätigte E-Mail-Adresse oder gesperrter Account, von außen nicht unterscheidbar. credits_remaining ist null; ein X-Request-Id-Header fehlt. |
| 403 | PLAN_REQUIRED | Du hast ein Thema angefragt, das Dein Tarif nicht enthält; detail nennt jedes gesperrte Thema und den nötigen Tarif. Im Detailendpunkt gilt dasselbe für das Thema des abgerufenen Signals. |
| 403 | EVIDENCE_NOT_AVAILABLE | Für Anfragen nach Quellbelegen reserviert. Über öffentliche Parameter nicht auslösbar. |
| 404 | NOT_FOUND | Signals ist für diesen Account gar nicht verfügbar: Alle drei Endpunkte antworten wie eine unbekannte Route. |
| 404 | SIGNAL_NOT_FOUND | Nur im Detailendpunkt: kein Signal mit dieser ID, oder sein Subjekt wird nicht ausgeliefert. |
| 422 | INVALID_REQUEST | Die Validierung ist fehlgeschlagen und invalid_params nennt den Parameter, der Katalog wurde mit einem Query-Parameter aufgerufen, oder die Quelle hat die Filterkombination abgelehnt. |
| 422 | INVALID_CURSOR | Der Cursor ist für diese Anfrage nicht verwendbar. Starte ohne Cursor neu. |
| 429 | — | Du hast das gemeinsame Limit von 60 Anfragen pro Minute erreicht. Das ist die einzige Signals-Antwort mit einem anderen Aufbau — siehe Rate-Limits unten. |
| 503 | SIGNALS_UNAVAILABLE | Die Signals-Quelle ist vorübergehend nicht verfügbar, oder die Cursor-Paginierung ist es. Ein erneuter Versuch ist unbedenklich; Retry-After kann dabei sein. |
Response-Header
- X-Credits-Charged: 5 oder 0 — die verbindliche Auskunft darüber, was der Aufruf gekostet hat.
- X-Request-Id: req_… passt zu meta.request_id. Nenne sie in Support-Anfragen. Bei den oben genannten 401 und 403 fehlt der Header, beim 429 ebenfalls.
- Retry-After: nur bei 503, nur wenn die Quelle einen Wert geliefert hat, und auf höchstens 5 Sekunden begrenzt.
- Cache-Control: private, no-store, max-age=0, dazu Pragma: no-cache und Vary: x-api-key. Jede Signals-Antwort ist privat — leg sie nie in einen gemeinsamen Cache. Die Ausnahme ist der 429, er kommt mit no-cache, private.
Rate-Limits
Authentifizierte Anfragen teilen sich ein Kontingent von 60 pro Minute mit /v1/get-organization, /v1/search-organizations und /v1/fetch-document. Schöpfst Du es auf einem davon aus, sind die anderen ebenfalls ausgebremst, auch der kostenlose Katalog.
Das Rate-Limit greift, bevor Deine Anfrage bei Signals ankommt. Ein 429 sieht deshalb anders aus als jeder andere Fehler: kein code, kein detail, kein meta, und der Body hängt vom gesendeten Accept-Header ab.
So sieht eine ausgebremste Anfrage aus
GET /api/v1/signals?topics=NEW_REGISTRATIONS
Accept: application/json
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Cache-Control: no-cache, private
{
"message": "Too Many Attempts."
}
- Mit Accept: application/json bekommst Du JSON mit einer kurzen message. Verzweige über den Statuscode 429 und parse den Body nicht.
- Ohne diesen Header bekommst Du stattdessen eine HTML-Fehlerseite. Sende deshalb bei jeder Signals-Anfrage Accept: application/json, damit auch eine ausgebremste maschinenlesbar bleibt.
- Verlass Dich nicht darauf, dass Retry-After oder die X-RateLimit-*-Header ankommen. Warte nach Deinem eigenen Zeitplan; ein sofortiger neuer Versuch verbrennt nur das nächste Zeitfenster.
- Weder X-Credits-Charged noch X-Request-Id ist vorhanden. Ein 429 kostet trotzdem 0 Credits, aber nichts in der Antwort sagt das.