Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Bulk, Batch and Asynchronous APIs: Bulk Operations, Partial Success, Webhooks or Polling, and the Rate Limit Contract
The contract of a bulk API spells out the size limit, which errors reject the whole request and which reject a single line, how partial success is reported, how the outcome is delivered, and the quota. At Bookstore we design the schools' bulk order as a 201 with a line-by-line report, a 422 with allOrNothing and a long-running operation with Prefer: respond-async, add the webhook to the contract, and see the RateLimit header draft and 429 with real responses.
The Payments Service: A Fake Payment Provider, Idempotent Charges and Webhook Callbacks
Payments sends charges to the payment provider with an Idempotency-Key derived from the order, does not repeat POSTs in the HTTP layer and treats a timeout as an unknown result, not a failure; a signed, replay-protected webhook or a reconciliation job settles the outcome. The provider's model stays in an anti-corruption layer, and a late payment for a cancelled order turns into a refund end to end.
Receiving Webhooks: Signature Verification, Replay Protection, Fast 2xx and Idempotent Processing
Verify an incoming webhook's signature over the raw body before model binding with a constant-time comparison, block replays with a timestamp tolerance and webhook-id, store the event in an inbox and return 200 right away, and process it idempotently in the background. In Bookstore, payment.succeeded closes unknown payment outcomes.
Sending Webhooks: Standard Webhooks, Signing, Outbox-Based Delivery and Retry Schedules
Send webhooks from an outbox in the background, not inside the request; sign every request with the Standard Webhooks headers (webhook-id, webhook-timestamp, webhook-signature) and HMAC-SHA256, follow a retry schedule spanning days, and disable endpoints that keep failing. This is how Bookstore delivers order.shipped to its institutional customers.