Erstellen Sie Partner API Webhooks für AI API Wiederverkäufer: Signierte Ereignisse, dauerhafte Zustellung und sichere Wiedergabe
Eine praktische Architektur für zuverlässige Partner API-Webhooks, die die Generierung fester Ereignisse, mandantensicheres Fanout, Signaturen, Wiederholungsversuche, Wiedergabe, SSRF-Schutz, Schemaentwicklung und Abgleich abdeckt.
Polling a Partner API for every balance, customer, key, budget, and usage change creates an awkward control loop: important actions arrive late, unchanged resources are fetched repeatedly, and concurrent updates can be observed in the wrong order. Outbound webhooks reduce that delay, but only if they are built as a durable notification system rather than an HTTP callback added to request handlers.
The essential rule is simple: a webhook reports a state transition that has already committed. It does not create the transition, replace the ledger, or become the authoritative record. This distinction matters when an event can freeze customer access, trigger a credit action, or affect an invoice.
Define the delivery contract first
Established fact: common webhook specifications and large webhook publishers assume at-least-once delivery. Retries can produce duplicates, and independent deliveries can arrive out of order.
Recommendation: publish the following contract before exposing an endpoint-management API:
- Every business event has a stable, immutable event ID.
- The same event ID is retained across automatic retries and manual replays.
- Delivery is at least once; exactly-once delivery is not promised.
- Ordering is not guaranteed across endpoints or event types.
- A successful response means the receiver durably accepted the event, not necessarily that all downstream work finished.
- Webhooks are notifications; Partner API reads and ledger exports remain authoritative.
This contract fits an AI API reseller platform because access-control and financial events need both prompt notification and a reliable recovery path.
Start with a narrow event catalog
Do not turn every database update into a public event. Publish transitions that a partner can act on and define precisely.
| Event | When to emit it | Typical partner action |
|---|---|---|
customer.created | Customer creation commits | Provision the customer in a reseller portal |
customer.frozen | Effective access state changes to frozen | Disable local sign-in or notify support |
api_key.created | Key metadata commits | Refresh the customer's key inventory |
api_key.revoked | Revocation becomes effective | Stop assigning work to the key |
balance.low | Available balance crosses a configured threshold downward | Request a top-up or warn the customer |
budget.threshold_crossed | Finalized spend crosses a policy threshold | Apply a local workflow or approval rule |
usage.finalized | Usage moves from provisional to finalized | Update reporting or downstream billing |
credit.adjustment_posted | A ledger adjustment commits | Refresh the displayed balance |
Threshold events need an explicit crossing rule. Emit when the prior value was below 80 percent and the new value is at or above 80 percent, for example, rather than emitting on every subsequent usage record. Define whether reversals can re-arm the threshold and whether adjustments can generate a new crossing.
Recommendation: avoid putting full API keys, provider credentials, raw prompts, or detailed abuse evidence in payloads. Prefer resource identifiers and minimal state snapshots. A receiver can use the Partner API to fetch sensitive or rapidly changing details.
Create events from committed state
Publishing directly from a request handler creates two failure windows. The callback may escape before the database transaction commits, or the transaction may commit while the process fails before sending the callback. A transactional outbox closes both windows.
Transactional outbox sequence
- Begin the control-plane or ledger transaction.
- Apply the authoritative state change.
- Insert an immutable event into an outbox table in the same transaction.
- Commit once.
- Let a publisher worker claim committed outbox rows.
- Resolve eligible endpoints using the event's partner scope and subscription filters.
- Create one delivery record for each event-endpoint pair.
A unique constraint on (event_id, endpoint_id) prevents duplicate fanout when workers retry. Outbox publication status should be updated with compare-and-set semantics or row locking so multiple workers can cooperate safely.
outbox_event(
event_id, partner_id, type, subject_id,
occurred_at, schema_version, payload, correlation_id,
published_at
)
delivery(
delivery_id, event_id, endpoint_id, state,
attempt_count, next_attempt_at, last_status,
last_latency_ms, last_error_category
)
The outbox adds database writes, cleanup work, and backlog monitoring. Those costs are justified when notifications have financial or access-control consequences. A best-effort callback may still be acceptable for disposable product telemetry, but it should not share the reliability claims of the Partner API webhook system.
Use a stable event envelope
Keep business-event identity separate from delivery-attempt identity. The event remains the same when it is retried; the attempt timestamp and delivery record change.
{
"event_id": "evt_01J...",
"type": "usage.finalized",
"occurred_at": "2026-10-15T14:22:31Z",
"partner_id": "partner_42",
"subject": {
"type": "usage_record",
"id": "usage_9182"
},
"schema_version": "1",
"correlation_id": "op_7fd...",
"data": {
"customer_id": "cus_204",
"currency": "USD",
"final_cost": "1.274800"
}
}
Use decimal strings or minor-unit integers for money. Document the currency, precision, and rounding policy. The correlation ID should connect the event to the originating Partner API operation or ledger posting without becoming the event's identity.
Enforce tenant-safe fanout
Resolve subscriptions within the event's partner scope before constructing endpoint-specific payloads. An endpoint ID supplied by a job or queue message must not be enough to authorize delivery. The worker should load the endpoint with a predicate equivalent to endpoint.partner_id = event.partner_id and verify that it is active and subscribed to the event type.
This is the outbound counterpart to tenant authorization in Partner API automation: object ownership must be re-established at each asynchronous boundary.
Sign the exact bytes you send
Established fact: the Standard Webhooks specification defines webhook-id, webhook-timestamp, and webhook-signature headers and signs the event ID, attempt timestamp, and raw request body together.
Assign a distinct signing secret to every endpoint. Compute the signature after final JSON serialization, and send those exact bytes. Re-serializing an object after signing can change whitespace, escaping, or property order and invalidate verification.
Receivers should reject timestamps outside a documented tolerance, calculate the expected HMAC over the raw body, and compare signatures in constant time. They should then persist the event ID under a unique constraint before acknowledging it.
For rotation, allow two active secrets temporarily and include signatures from both. End rotation only after the partner confirms the new secret or after a documented overlap period. Never expose an existing secret again after initial creation.
Make every delivery observable and replayable
Persist each attempt with its start time, status code, latency, error category, next retry time, and a size-limited response excerpt. Redact headers and response bodies before display. Operators need to distinguish DNS failure, connection refusal, TLS failure, timeout, HTTP rejection, and internal worker failure.
A practical response policy is:
200-299: mark delivered.410: stop delivery and disable the endpoint.408,425,429, and500-599: retry, respecting a validRetry-Aftervalue within configured limits.- Other
400-499: classify as a persistent receiver error and retry only according to the published policy. - Network and timeout failures: retry with exponential backoff and jitter.
Cap concurrency per endpoint so one failing receiver cannot consume the worker pool. Spread retries over multiple days, warn endpoint owners through a separate channel, and disable an endpoint after a documented failure window.
Manual replay should create a new attempt for the original event-endpoint pair. It must not create a new business event, change event_id, or imply that the underlying action happened again.
Treat callback URLs as an SSRF boundary
A partner-controlled callback URL instructs your infrastructure where to make a network request. That makes the webhook publisher an SSRF target.
Recommendation: require HTTPS, restrict ports, reject embedded credentials, and block loopback, private, link-local, multicast, reserved, and cloud metadata destinations. Resolve the hostname during validation and again when connecting. Verify every resolved address, not just the first one.
Do not follow redirects automatically. If redirects are supported, validate every destination hop and apply a small hop limit. Protect against DNS rebinding by connecting only to the validated public address while preserving the expected hostname for TLS verification.
Run delivery workers in an isolated network segment without access to control-plane databases, internal admin services, orchestration APIs, or instance metadata. Apply request-body limits, response-size limits, connection timeouts, and total request deadlines.
Design consumers for duplicates and stale events
The receiver should authenticate the signature, validate the timestamp and schema, insert the event ID into a durable inbox, enqueue processing, and return quickly. A unique event-ID constraint turns concurrent duplicates into a normal database outcome.
Business effects need their own idempotency controls. If credit.adjustment_posted triggers an accounting import, key that import to the source adjustment ID rather than assuming webhook deduplication alone protects the ledger. A timeout can occur after the receiver commits its effect but before the publisher sees the response.
For mutable state such as key status, compare resource versions or fetch current state before applying an older event. This is especially important for AI API budget controls, where a delayed threshold notification must not overwrite a newer limit or enforcement decision.
Version schemas and provide reconciliation
Version webhook schemas independently from normal Partner API responses. Keep additive fields backward compatible, publish JSON Schemas and examples, and reserve a new event type or schema URI for incompatible semantics. Pin each endpoint to an explicit event-schema behavior instead of silently changing payloads whenever the API evolves.
Webhooks also need pull-based recovery:
- List events after a cursor, scoped to the authenticated partner.
- Retrieve current customer, key, balance, and budget state.
- Export finalized usage and ledger adjustments for a time range.
- Expose delivery retention and replay-window limits.
Prediction: partners will eventually miss notifications because of expired retention, disabled endpoints, deployment mistakes, or prolonged outages. A cursor-based event feed and authoritative state APIs turn that incident into reconciliation work instead of manual data repair.
Implementation checklist
- Document event semantics, crossing rules, and data sensitivity.
- Write events and authoritative changes in one transaction.
- Enforce partner ownership during fanout and delivery.
- Sign stable event IDs, attempt timestamps, and raw payload bytes.
- Store per-attempt evidence and expose searchable delivery history.
- Support overlapping secrets, test events, disabling, and replay.
- Validate destinations at registration and connection time.
- Test duplicates, out-of-order delivery, timeout after durable receipt, rotation overlap, DNS rebinding, private-IP redirects, rate limiting, and prolonged downtime.
- Monitor outbox age, queue depth, success rate, endpoint disablement, and retry saturation.
- Keep reconciliation APIs available after delivery records expire.
Build notifications around authoritative records
The dependable design is not a more aggressive retry loop. It is a chain of durable boundaries: committed state, transactional event creation, tenant-scoped fanout, signed delivery, idempotent receipt, and pull-based reconciliation. Implement those boundaries before expanding the event catalog. Partners can then automate provisioning, access controls, balances, budgets, and usage without treating an unreliable HTTP exchange as the system of record.