[{"data":1,"prerenderedAt":5181},["ShallowReactive",2],{"docs-navigation":3,"content-query-S9rMSCZdnK":342},[4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,127,130,133,136,139,142,145,148,151,154,157,160,163,166,169,172,175,178,181,184,187,190,193,196,199,202,205,208,211,214,217,220,223,226,229,232,235,238,241,244,247,250,253,256,259,262,265,268,271,274,277,280,283,285,288,291,294,297,300,303,306,309,312,315,318,321,324,327,330,333,336,339],{"_path":5,"title":6},"/docs/account/account-management","Account management",{"_path":8,"title":9},"/docs/account/mfa","Multi-factor authentication (MFA)",{"_path":11,"title":12},"/docs/account/team","Teams and sub-accounts",{"_path":14,"title":15},"/docs/account/billing-and-subscriptions","Billing & subscriptions",{"_path":17,"title":18},"/docs/account/access-tokens","Webhook Relay access tokens: permissions and subscription scopes",{"_path":20,"title":21},"/docs/clawhub","Webhook Relay on ClawHub",{"_path":23,"title":24},"/docs/email","Receive emails as webhooks",{"_path":26,"title":27},"/docs/email/payload","Email webhook payload",{"_path":29,"title":30},"/docs/email/filtering-and-policy","Sender filtering & policy",{"_path":32,"title":33},"/docs/email/cli","Create & poll email addresses from the CLI",{"_path":35,"title":36},"/docs","Getting Started",{"_path":38,"title":39},"/docs/installation/cli","CLI",{"_path":41,"title":42},"/docs/installation/docker","Docker container",{"_path":44,"title":45},"/docs/installation/docker-compose","Docker Compose",{"_path":47,"title":48},"/docs/installation/kubernetes","Kubernetes",{"_path":50,"title":51},"/docs/installation/autostart-windows","Autostart (Windows)",{"_path":53,"title":54},"/docs/installation/autostart-linux","Autostart (Linux)",{"_path":56,"title":57},"/docs/installation/autostart-macos","Autostart (MacOS)",{"_path":59,"title":60},"/docs/installation/behind-proxy","HTTP proxy configuration",{"_path":62,"title":63},"/docs/mcp","MCP Server",{"_path":65,"title":66},"/docs/outbound","Outbound Gateway: send webhooks to your customers",{"_path":68,"title":69},"/docs/outbound/setup","Set up the Outbound Gateway",{"_path":71,"title":72},"/docs/outbound/receiving","Receive and verify outbound webhooks",{"_path":74,"title":75},"/docs/outbound/operating","Monitor, retry and recover deliveries",{"_path":77,"title":78},"/docs/outbound/migrate","Migrate to the Outbound Gateway",{"_path":80,"title":81},"/docs/outbound/migrate/svix","Migrate from Svix",{"_path":83,"title":84},"/docs/outbound/migrate/hookdeck-outpost","Migrate from Hookdeck Outpost",{"_path":86,"title":87},"/docs/outbound/migrate/convoy","Migrate from Convoy",{"_path":89,"title":90},"/docs/outbound/migrate/hook0","Migrate from Hook0",{"_path":92,"title":93},"/docs/outbound/migrate/diy","Migrate a homegrown webhook sender",{"_path":95,"title":96},"/docs/security","Security & Tech",{"_path":98,"title":99},"/docs/service-connections","Service Connections",{"_path":101,"title":102},"/docs/service-connections/ai-providers","AI provider connections",{"_path":104,"title":105},"/docs/service-connections/aws_s3","AWS S3",{"_path":107,"title":108},"/docs/service-connections/aws_sns","AWS SNS",{"_path":110,"title":111},"/docs/service-connections/aws_sqs","AWS SQS",{"_path":113,"title":114},"/docs/service-connections/azure","Azure",{"_path":116,"title":117},"/docs/service-connections/gcp_gcs","GCP Cloud Storage",{"_path":119,"title":120},"/docs/service-connections/gcp_pubsub","GCP Pub/Sub",{"_path":122,"title":123},"/docs/service-connections/secrets","Secrets",{"_path":125,"title":126},"/docs/skills","Agent Skills",{"_path":128,"title":129},"/docs/skills-cli","skills.sh — the Agent Skills CLI",{"_path":131,"title":132},"/docs/tunnels/demoing-your-website","Demoing your website",{"_path":134,"title":135},"/docs/tunnels/regions","Regions",{"_path":137,"title":138},"/docs/tutorials/cicd/jenkins-bitbucket","Jenkins and Bitbucket",{"_path":140,"title":141},"/docs/tutorials/cicd/jenkins-github","Jenkins and GitHub",{"_path":143,"title":144},"/docs/tutorials/cicd/jenkins-plugin","Jenkins Plugin",{"_path":146,"title":147},"/docs/tutorials/cicd/jenkins-plugin-multibranch","Jenkins Multibranch Pipelines",{"_path":149,"title":150},"/docs/tutorials/cicd/kubernetes-operator","Kubernetes Operator",{"_path":152,"title":153},"/docs/tutorials/cicd/terraform-atlantis","Terraform Atlantis",{"_path":155,"title":156},"/docs/tutorials/cicd/webhook-exec","Execute scripts on webhook",{"_path":158,"title":159},"/docs/tutorials/edge/home-assistant","Home Assistant",{"_path":161,"title":162},"/docs/tutorials/edge/javascript-app","JavaScript app",{"_path":164,"title":165},"/docs/tutorials/edge/node-red","Node-RED",{"_path":167,"title":168},"/docs/tutorials/email/airtable","Email to Airtable",{"_path":170,"title":171},"/docs/tutorials/email/api","Email to API",{"_path":173,"title":174},"/docs/tutorials/email/database","Email to Database",{"_path":176,"title":177},"/docs/tutorials/email/discord","Email to Discord",{"_path":179,"title":180},"/docs/tutorials/email/google-sheets","Email to Google Sheets",{"_path":182,"title":183},"/docs/tutorials/email/microsoft-teams","Email to Microsoft Teams",{"_path":185,"title":186},"/docs/tutorials/email/notion","Email to Notion",{"_path":188,"title":189},"/docs/tutorials/email/slack","Email to Slack",{"_path":191,"title":192},"/docs/tutorials","Tutorials",{"_path":194,"title":195},"/docs/tutorials/n8n/email-trigger","n8n Email Trigger (Inbound Email)",{"_path":197,"title":198},"/docs/tutorials/n8n/webhook-trigger","n8n Webhook Trigger (No Public IP)",{"_path":200,"title":201},"/docs/tutorials/n8n/whatsapp-cloud-api-webhook","n8n WhatsApp Cloud API Webhook Setup",{"_path":203,"title":204},"/docs/tutorials/outbound/send-webhooks-nodejs","Send webhooks to your customers from a Node.js / TypeScript app",{"_path":206,"title":207},"/docs/tutorials/outbound/send-webhooks-go","Send webhooks to your customers from a Go service",{"_path":209,"title":210},"/docs/tutorials/outbound/nextjs-saas-webhooks","Add webhooks to a Next.js SaaS app",{"_path":212,"title":213},"/docs/tutorials/transform/docker-to-slack","DockerHub webhook to Slack notification",{"_path":215,"title":216},"/docs/tutorials/transform/enrich-webhooks","Enrich webhooks from APIs",{"_path":218,"title":219},"/docs/tutorials/transform/stripe-to-plain","Sync Stripe subscriptions to Plain.com tenants",{"_path":221,"title":222},"/docs/tutorials/warehouse/bigquery","GCP BigQuery",{"_path":224,"title":225},"/docs/webhooks/alerts","Alerts",{"_path":227,"title":228},"/docs/webhooks/auth/username-password","Username and password",{"_path":230,"title":231},"/docs/webhooks/auth/hmac","HMAC",{"_path":233,"title":234},"/docs/webhooks/auth/jwt","JWT authentication",{"_path":236,"title":237},"/docs/webhooks/auth/http-method","Auth using request method",{"_path":239,"title":240},"/docs/webhooks/cors","CORS for webhooks",{"_path":242,"title":243},"/docs/webhooks/cron/using-cron-webhooks","Schedule recurring webhooks",{"_path":245,"title":246},"/docs/webhooks/custom-domains","Custom webhook domains",{"_path":248,"title":249},"/docs/webhooks/custom-subdomains","Custom webhook subdomains",{"_path":251,"title":252},"/docs/webhooks/custom-webhook-response","Custom response to webhooks",{"_path":254,"title":255},"/docs/webhooks/durable-webhooks","Durable webhooks: reliable delivery with automatic retries",{"_path":257,"title":258},"/docs/webhooks/functions/manipulating-json","JSON encoding",{"_path":260,"title":261},"/docs/webhooks/functions/make-http-request","Make HTTP request",{"_path":263,"title":264},"/docs/webhooks/functions/modify-request","Modify webhook headers, body, method and path",{"_path":266,"title":267},"/docs/webhooks/functions/multipart-form-data","Multipart form to JSON",{"_path":269,"title":270},"/docs/webhooks/functions/url-encoded-data","URL Encoded Form",{"_path":272,"title":273},"/docs/webhooks/functions/working-with-time","Working with time",{"_path":275,"title":276},"/docs/webhooks/functions/send-emails","Sending emails",{"_path":278,"title":279},"/docs/webhooks/functions/crypto-functions","Base64, encryption",{"_path":281,"title":282},"/docs/webhooks/functions/integrate-into-cicd","Integrating into CI/CD",{"_path":284,"title":222},"/docs/webhooks/functions/big-query",{"_path":286,"title":287},"/docs/webhooks/functions/accessing-metadata","Accessing metadata",{"_path":289,"title":290},"/docs/webhooks/functions/response-functions","Response (post-delivery) functions",{"_path":292,"title":293},"/docs/webhooks/functions/alerting","Alerting from functions",{"_path":295,"title":296},"/docs/webhooks/functions/helper-libraries","Helper libraries",{"_path":298,"title":299},"/docs/webhooks/functions/transform-webhook-payload","Transform a webhook payload",{"_path":301,"title":302},"/docs/webhooks/functions/filter-webhooks","Filter or drop webhooks before forwarding",{"_path":304,"title":305},"/docs/webhooks/functions/provider-helpers","Provider-aware function helpers",{"_path":307,"title":308},"/docs/webhooks/functions","Webhook transformations (functions): modify body, headers, method and path",{"_path":310,"title":311},"/docs/webhooks/internal/localhost","Receive webhooks on localhost with the relay CLI",{"_path":313,"title":314},"/docs/webhooks/large-webhooks","Large Webhooks",{"_path":316,"title":317},"/docs/webhooks/outbound-throttling","Outbound throttling: control webhook delivery speed",{"_path":319,"title":320},"/docs/webhooks/polling-webhooks","Polling webhooks with /v1/events",{"_path":322,"title":323},"/docs/webhooks/public/public-destination","Forward to public URL",{"_path":325,"title":326},"/docs/webhooks/public/multiple-destination-urls","Forward webhooks to multiple destinations",{"_path":328,"title":329},"/docs/webhooks/replay-on-agent-connect","Webhook replay on agent connect: recover missed webhooks",{"_path":331,"title":332},"/docs/webhooks/static-ip-address","Static IP Address",{"_path":334,"title":335},"/docs/webhooks/tls-ssl-errors","Fix TLS/SSL handshake errors: unsupported protocol, wrong version number, handshake failure",{"_path":337,"title":338},"/docs/webhooks/websocket-server","Connecting to websocket server",{"_path":340,"title":341},"/docs/webhooks/zero-retention-buckets","Zero Retention Buckets",{"_path":203,"_dir":343,"_draft":344,"_partial":344,"_locale":345,"title":204,"description":346,"intro":347,"type":348,"layout":349,"tags":350,"faq":356,"body":369,"_type":5174,"_id":5175,"_source":5176,"_file":5177,"_stem":5178,"_extension":5179,"sitemap":5180},"outbound",false,"","Add customer-facing webhooks to a Node.js or TypeScript backend with @webhookrelay/sdk: event types, consumers, endpoints, idempotent publishing, delivery inspection, retries and failing-endpoint reports.","Register each customer and their HTTPS endpoint once, then call one publish method whenever an event happens. Webhook Relay signs, delivers, retries and logs every webhook.","tutorial","doc",[351,352,353,354,355],"Outbound webhooks","Send webhooks","TypeScript","Node.js","Standard Webhooks",[357,360,363,366],{"q":358,"a":359},"Do I need my own queue or retry worker to send webhooks from Node.js?","No. relay.outbound.messages.publish returns a 202 receipt once the message is stored durably, and Webhook Relay delivers it to every subscribed endpoint, retrying failures up to eight times within 48 hours. Your Node.js process can exit or restart right after the call returns.",{"q":361,"a":362},"What happens if my code calls publish twice for the same event?","Pass an idempotencyKey derived from the event, such as invoice-paid:inv_123. A repeat call with the same key and the same message returns the original receipt and nothing is delivered twice. Reusing the key for a different payload is rejected with a 409 error.",{"q":364,"a":365},"Which Webhook Relay plan do I need to send webhooks?","The Outbound Gateway is self-serve on the Basic plan ($9.99 per month) and every plan above it. It is not available on the Free plan. Basic covers 100 customers with up to 10 endpoints each, and there are no per-message fees.",{"q":367,"a":368},"How do my customers verify the webhooks?","Every delivery is signed with the Standard Webhooks scheme using the endpoint's whsec_ secret, in the webhook-id, webhook-timestamp and webhook-signature headers. Customers can use any Standard Webhooks library, including Svix's, or the short verification functions in the Webhook Relay receiving guide.",{"type":370,"children":371,"toc":5160},"root",[372,421,426,467,532,539,654,660,792,821,953,959,980,1265,1278,1284,1311,1674,1687,1693,1706,2429,2434,2467,2473,2484,2992,3053,3059,3072,3743,3749,3762,4159,4165,4184,4223,4229,4234,4966,4990,5045,5051,5084,5090,5154],{"type":373,"tag":374,"props":375,"children":376},"element","p",{},[377,401,403,410,412,419],{"type":373,"tag":378,"props":379,"children":380},"strong",{},[381,384,391,393,399],{"type":382,"value":383},"text","To send webhooks to your customers from a Node.js or TypeScript app, install ",{"type":373,"tag":385,"props":386,"children":388},"code",{"className":387},[],[389],{"type":382,"value":390},"@webhookrelay/sdk",{"type":382,"value":392},", register each customer as a consumer with the HTTPS endpoint they give you, and call ",{"type":373,"tag":385,"props":394,"children":396},{"className":395},[],[397],{"type":382,"value":398},"relay.outbound.messages.publish()",{"type":382,"value":400}," with an idempotency key whenever an event happens.",{"type":382,"value":402}," Webhook Relay's ",{"type":373,"tag":404,"props":405,"children":407},"a",{"href":406},"/outbound-webhooks/",[408],{"type":382,"value":409},"Outbound Gateway",{"type":382,"value":411}," signs each delivery with ",{"type":373,"tag":404,"props":413,"children":417},{"href":414,"rel":415},"https://www.standardwebhooks.com/",[416],"nofollow",[418],{"type":382,"value":355},{"type":382,"value":420}," headers, retries failures up to eight times within 48 hours, paces each endpoint separately and keeps 35 days of per-attempt history. You don't build a queue, a retry worker or signing code.",{"type":373,"tag":374,"props":422,"children":423},{},[424],{"type":382,"value":425},"By the end of this tutorial you will have:",{"type":373,"tag":427,"props":428,"children":429},"ol",{},[430,452,457,462],{"type":373,"tag":431,"props":432,"children":433},"li",{},[434,436,442,444,450],{"type":382,"value":435},"an event catalog (",{"type":373,"tag":385,"props":437,"children":439},{"className":438},[],[440],{"type":382,"value":441},"invoice.paid",{"type":382,"value":443},", ",{"type":373,"tag":385,"props":445,"children":447},{"className":446},[],[448],{"type":382,"value":449},"invoice.refunded",{"type":382,"value":451},"),",{"type":373,"tag":431,"props":453,"children":454},{},[455],{"type":382,"value":456},"a customer with a registered endpoint and its signing secret,",{"type":373,"tag":431,"props":458,"children":459},{},[460],{"type":382,"value":461},"idempotent publishing from your business logic,",{"type":373,"tag":431,"props":463,"children":464},{},[465],{"type":382,"value":466},"code that inspects deliveries, retries one, recovers failures after an outage and reports failing endpoints.",{"type":373,"tag":468,"props":469,"children":472},"pre",{"className":470,"code":471,"language":382,"meta":345,"style":345},"language-text shiki shiki-themes github-dark","your Node.js app ──publish once──▶ Webhook Relay Outbound Gateway\n                                     │  sign (whsec_ per endpoint)\n                                     │  retry 5s → 10h, up to 8 attempts / 48h\n                                     │  per-endpoint rate limit, 35-day log\n                                     ├──▶ https://acme.example/webhooks\n                                     └──▶ https://hooks.globex.example/wr\n",[473],{"type":373,"tag":385,"props":474,"children":475},{"__ignoreMap":345},[476,487,496,505,514,523],{"type":373,"tag":477,"props":478,"children":481},"span",{"class":479,"line":480},"line",1,[482],{"type":373,"tag":477,"props":483,"children":484},{},[485],{"type":382,"value":486},"your Node.js app ──publish once──▶ Webhook Relay Outbound Gateway\n",{"type":373,"tag":477,"props":488,"children":490},{"class":479,"line":489},2,[491],{"type":373,"tag":477,"props":492,"children":493},{},[494],{"type":382,"value":495},"                                     │  sign (whsec_ per endpoint)\n",{"type":373,"tag":477,"props":497,"children":499},{"class":479,"line":498},3,[500],{"type":373,"tag":477,"props":501,"children":502},{},[503],{"type":382,"value":504},"                                     │  retry 5s → 10h, up to 8 attempts / 48h\n",{"type":373,"tag":477,"props":506,"children":508},{"class":479,"line":507},4,[509],{"type":373,"tag":477,"props":510,"children":511},{},[512],{"type":382,"value":513},"                                     │  per-endpoint rate limit, 35-day log\n",{"type":373,"tag":477,"props":515,"children":517},{"class":479,"line":516},5,[518],{"type":373,"tag":477,"props":519,"children":520},{},[521],{"type":382,"value":522},"                                     ├──▶ https://acme.example/webhooks\n",{"type":373,"tag":477,"props":524,"children":526},{"class":479,"line":525},6,[527],{"type":373,"tag":477,"props":528,"children":529},{},[530],{"type":382,"value":531},"                                     └──▶ https://hooks.globex.example/wr\n",{"type":373,"tag":533,"props":534,"children":536},"h2",{"id":535},"prerequisites",[537],{"type":382,"value":538},"Prerequisites",{"type":373,"tag":540,"props":541,"children":542},"ul",{},[543,562,618,636],{"type":373,"tag":431,"props":544,"children":545},{},[546,551,553,560],{"type":373,"tag":378,"props":547,"children":548},{},[549],{"type":382,"value":550},"A Webhook Relay account on the Basic plan or above.",{"type":382,"value":552}," The Outbound Gateway is self-serve on Basic ($9.99/month), Business and Pro. It is not on the Free plan. Open ",{"type":373,"tag":404,"props":554,"children":557},{"href":555,"rel":556},"https://my.webhookrelay.com/outbound",[416],[558],{"type":382,"value":559},"my.webhookrelay.com/outbound",{"type":382,"value":561}," to confirm it is on.",{"type":373,"tag":431,"props":563,"children":564},{},[565,570,572,579,581,586,588,593,595,600,602,608,610,616],{"type":373,"tag":378,"props":566,"children":567},{},[568],{"type":382,"value":569},"An outbound-restricted access token.",{"type":382,"value":571}," On the ",{"type":373,"tag":404,"props":573,"children":576},{"href":574,"rel":575},"https://my.webhookrelay.com/tokens",[416],[577],{"type":382,"value":578},"Access Tokens",{"type":382,"value":580}," page create a standalone token and choose an ",{"type":373,"tag":378,"props":582,"children":583},{},[584],{"type":382,"value":585},"Outbound",{"type":382,"value":587}," restriction. Use ",{"type":373,"tag":378,"props":589,"children":590},{},[591],{"type":382,"value":592},"Outbound: manage",{"type":382,"value":594}," for onboarding code that creates consumers and endpoints, and ",{"type":373,"tag":378,"props":596,"children":597},{},[598],{"type":382,"value":599},"Outbound: publish only",{"type":382,"value":601}," (",{"type":373,"tag":385,"props":603,"children":605},{"className":604},[],[606],{"type":382,"value":607},"\"permissions\": { \"outbound\": \"publish\" }",{"type":382,"value":609},") for the service that emits events. A restricted token can only reach ",{"type":373,"tag":385,"props":611,"children":613},{"className":612},[],[614],{"type":382,"value":615},"/v1/outbound/*",{"type":382,"value":617},", so a leaked publish token cannot touch your buckets, tunnels or account.",{"type":373,"tag":431,"props":619,"children":620},{},[621,626,628,634],{"type":373,"tag":378,"props":622,"children":623},{},[624],{"type":382,"value":625},"Node.js 18 or newer",{"type":382,"value":627}," (the SDK uses the built-in ",{"type":373,"tag":385,"props":629,"children":631},{"className":630},[],[632],{"type":382,"value":633},"fetch",{"type":382,"value":635},").",{"type":373,"tag":431,"props":637,"children":638},{},[639,644,646,652],{"type":373,"tag":378,"props":640,"children":641},{},[642],{"type":382,"value":643},"A test endpoint.",{"type":382,"value":645}," Any public HTTPS URL works. A free ",{"type":373,"tag":404,"props":647,"children":649},{"href":648},"/webhook-bin/",[650],{"type":382,"value":651},"Webhook Bin",{"type":382,"value":653}," is the quickest way to watch deliveries arrive.",{"type":373,"tag":533,"props":655,"children":657},{"id":656},"_1-install-the-sdk-and-set-credentials",[658],{"type":382,"value":659},"1. Install the SDK and set credentials",{"type":373,"tag":468,"props":661,"children":665},{"className":662,"code":663,"language":664,"meta":345,"style":345},"language-bash shiki shiki-themes github-dark","npm install @webhookrelay/sdk\nnpm install --save-dev tsx typescript\n\nexport RELAY_KEY=YOUR_TOKEN_KEY\nexport RELAY_SECRET=YOUR_TOKEN_SECRET\nexport CUSTOMER_WEBHOOK_URL=https://bin.webhookrelay.com/v1/webhooks/YOUR_BIN_ID\n","bash",[666],{"type":373,"tag":385,"props":667,"children":668},{"__ignoreMap":345},[669,689,716,725,750,771],{"type":373,"tag":477,"props":670,"children":671},{"class":479,"line":480},[672,678,684],{"type":373,"tag":477,"props":673,"children":675},{"style":674},"--shiki-default:#B392F0",[676],{"type":382,"value":677},"npm",{"type":373,"tag":477,"props":679,"children":681},{"style":680},"--shiki-default:#9ECBFF",[682],{"type":382,"value":683}," install",{"type":373,"tag":477,"props":685,"children":686},{"style":680},[687],{"type":382,"value":688}," @webhookrelay/sdk\n",{"type":373,"tag":477,"props":690,"children":691},{"class":479,"line":489},[692,696,700,706,711],{"type":373,"tag":477,"props":693,"children":694},{"style":674},[695],{"type":382,"value":677},{"type":373,"tag":477,"props":697,"children":698},{"style":680},[699],{"type":382,"value":683},{"type":373,"tag":477,"props":701,"children":703},{"style":702},"--shiki-default:#79B8FF",[704],{"type":382,"value":705}," --save-dev",{"type":373,"tag":477,"props":707,"children":708},{"style":680},[709],{"type":382,"value":710}," tsx",{"type":373,"tag":477,"props":712,"children":713},{"style":680},[714],{"type":382,"value":715}," typescript\n",{"type":373,"tag":477,"props":717,"children":718},{"class":479,"line":498},[719],{"type":373,"tag":477,"props":720,"children":722},{"emptyLinePlaceholder":721},true,[723],{"type":382,"value":724},"\n",{"type":373,"tag":477,"props":726,"children":727},{"class":479,"line":507},[728,734,740,745],{"type":373,"tag":477,"props":729,"children":731},{"style":730},"--shiki-default:#F97583",[732],{"type":382,"value":733},"export",{"type":373,"tag":477,"props":735,"children":737},{"style":736},"--shiki-default:#E1E4E8",[738],{"type":382,"value":739}," RELAY_KEY",{"type":373,"tag":477,"props":741,"children":742},{"style":730},[743],{"type":382,"value":744},"=",{"type":373,"tag":477,"props":746,"children":747},{"style":736},[748],{"type":382,"value":749},"YOUR_TOKEN_KEY\n",{"type":373,"tag":477,"props":751,"children":752},{"class":479,"line":516},[753,757,762,766],{"type":373,"tag":477,"props":754,"children":755},{"style":730},[756],{"type":382,"value":733},{"type":373,"tag":477,"props":758,"children":759},{"style":736},[760],{"type":382,"value":761}," RELAY_SECRET",{"type":373,"tag":477,"props":763,"children":764},{"style":730},[765],{"type":382,"value":744},{"type":373,"tag":477,"props":767,"children":768},{"style":736},[769],{"type":382,"value":770},"YOUR_TOKEN_SECRET\n",{"type":373,"tag":477,"props":772,"children":773},{"class":479,"line":525},[774,778,783,787],{"type":373,"tag":477,"props":775,"children":776},{"style":730},[777],{"type":382,"value":733},{"type":373,"tag":477,"props":779,"children":780},{"style":736},[781],{"type":382,"value":782}," CUSTOMER_WEBHOOK_URL",{"type":373,"tag":477,"props":784,"children":785},{"style":730},[786],{"type":382,"value":744},{"type":373,"tag":477,"props":788,"children":789},{"style":736},[790],{"type":382,"value":791},"https://bin.webhookrelay.com/v1/webhooks/YOUR_BIN_ID\n",{"type":373,"tag":374,"props":793,"children":794},{},[795,797,803,805,811,813,819],{"type":382,"value":796},"Create one client module and import it everywhere. With no arguments the client reads ",{"type":373,"tag":385,"props":798,"children":800},{"className":799},[],[801],{"type":382,"value":802},"RELAY_KEY",{"type":382,"value":804}," and ",{"type":373,"tag":385,"props":806,"children":808},{"className":807},[],[809],{"type":382,"value":810},"RELAY_SECRET",{"type":382,"value":812}," (or a ",{"type":373,"tag":385,"props":814,"children":816},{"className":815},[],[817],{"type":382,"value":818},"RELAY_API_KEY",{"type":382,"value":820}," account key) from the environment. Keep it server-side: never publish from a browser or mobile app.",{"type":373,"tag":468,"props":822,"children":826},{"className":823,"code":824,"language":825,"meta":345,"style":345},"language-ts shiki shiki-themes github-dark","// relay.ts\nimport { WebhookRelay } from \"@webhookrelay/sdk\";\n\nexport const relay = new WebhookRelay({\n  key: process.env.RELAY_KEY,\n  secret: process.env.RELAY_SECRET,\n});\n","ts",[827],{"type":373,"tag":385,"props":828,"children":829},{"__ignoreMap":345},[830,839,867,874,911,928,944],{"type":373,"tag":477,"props":831,"children":832},{"class":479,"line":480},[833],{"type":373,"tag":477,"props":834,"children":836},{"style":835},"--shiki-default:#6A737D",[837],{"type":382,"value":838},"// relay.ts\n",{"type":373,"tag":477,"props":840,"children":841},{"class":479,"line":489},[842,847,852,857,862],{"type":373,"tag":477,"props":843,"children":844},{"style":730},[845],{"type":382,"value":846},"import",{"type":373,"tag":477,"props":848,"children":849},{"style":736},[850],{"type":382,"value":851}," { WebhookRelay } ",{"type":373,"tag":477,"props":853,"children":854},{"style":730},[855],{"type":382,"value":856},"from",{"type":373,"tag":477,"props":858,"children":859},{"style":680},[860],{"type":382,"value":861}," \"@webhookrelay/sdk\"",{"type":373,"tag":477,"props":863,"children":864},{"style":736},[865],{"type":382,"value":866},";\n",{"type":373,"tag":477,"props":868,"children":869},{"class":479,"line":498},[870],{"type":373,"tag":477,"props":871,"children":872},{"emptyLinePlaceholder":721},[873],{"type":382,"value":724},{"type":373,"tag":477,"props":875,"children":876},{"class":479,"line":507},[877,881,886,891,896,901,906],{"type":373,"tag":477,"props":878,"children":879},{"style":730},[880],{"type":382,"value":733},{"type":373,"tag":477,"props":882,"children":883},{"style":730},[884],{"type":382,"value":885}," const",{"type":373,"tag":477,"props":887,"children":888},{"style":702},[889],{"type":382,"value":890}," relay",{"type":373,"tag":477,"props":892,"children":893},{"style":730},[894],{"type":382,"value":895}," =",{"type":373,"tag":477,"props":897,"children":898},{"style":730},[899],{"type":382,"value":900}," new",{"type":373,"tag":477,"props":902,"children":903},{"style":674},[904],{"type":382,"value":905}," WebhookRelay",{"type":373,"tag":477,"props":907,"children":908},{"style":736},[909],{"type":382,"value":910},"({\n",{"type":373,"tag":477,"props":912,"children":913},{"class":479,"line":516},[914,919,923],{"type":373,"tag":477,"props":915,"children":916},{"style":736},[917],{"type":382,"value":918},"  key: process.env.",{"type":373,"tag":477,"props":920,"children":921},{"style":702},[922],{"type":382,"value":802},{"type":373,"tag":477,"props":924,"children":925},{"style":736},[926],{"type":382,"value":927},",\n",{"type":373,"tag":477,"props":929,"children":930},{"class":479,"line":525},[931,936,940],{"type":373,"tag":477,"props":932,"children":933},{"style":736},[934],{"type":382,"value":935},"  secret: process.env.",{"type":373,"tag":477,"props":937,"children":938},{"style":702},[939],{"type":382,"value":810},{"type":373,"tag":477,"props":941,"children":942},{"style":736},[943],{"type":382,"value":927},{"type":373,"tag":477,"props":945,"children":947},{"class":479,"line":946},7,[948],{"type":373,"tag":477,"props":949,"children":950},{"style":736},[951],{"type":382,"value":952},"});\n",{"type":373,"tag":533,"props":954,"children":956},{"id":955},"_2-define-your-event-catalog",[957],{"type":382,"value":958},"2. Define your event catalog",{"type":373,"tag":374,"props":960,"children":961},{},[962,964,970,972,978],{"type":382,"value":963},"Event types are the webhooks your customers can subscribe to. ",{"type":373,"tag":385,"props":965,"children":967},{"className":966},[],[968],{"type":382,"value":969},"upsert",{"type":382,"value":971}," creates or updates them, so you can run this on every deploy. The ",{"type":373,"tag":385,"props":973,"children":975},{"className":974},[],[976],{"type":382,"value":977},"example",{"type":382,"value":979}," payload documents the event for your customers (up to 64 KiB).",{"type":373,"tag":468,"props":981,"children":983},{"className":823,"code":982,"language":825,"meta":345,"style":345},"// catalog.ts\nimport { relay } from \"./relay.js\";\n\nexport async function syncEventCatalog() {\n  await relay.outbound.eventTypes.upsert(\"invoice.paid\", {\n    description: \"An invoice was paid in full\",\n    example: { invoice_id: \"inv_123\", customer_id: \"customer_42\", amount: 4900, currency: \"usd\" },\n  });\n  await relay.outbound.eventTypes.upsert(\"invoice.refunded\", {\n    description: \"An invoice was refunded, fully or partially\",\n    example: { invoice_id: \"inv_123\", refund_id: \"re_9\", amount: 4900, currency: \"usd\" },\n  });\n}\n",[984],{"type":373,"tag":385,"props":985,"children":986},{"__ignoreMap":345},[987,995,1020,1027,1054,1086,1103,1151,1160,1189,1206,1248,1256],{"type":373,"tag":477,"props":988,"children":989},{"class":479,"line":480},[990],{"type":373,"tag":477,"props":991,"children":992},{"style":835},[993],{"type":382,"value":994},"// catalog.ts\n",{"type":373,"tag":477,"props":996,"children":997},{"class":479,"line":489},[998,1002,1007,1011,1016],{"type":373,"tag":477,"props":999,"children":1000},{"style":730},[1001],{"type":382,"value":846},{"type":373,"tag":477,"props":1003,"children":1004},{"style":736},[1005],{"type":382,"value":1006}," { relay } ",{"type":373,"tag":477,"props":1008,"children":1009},{"style":730},[1010],{"type":382,"value":856},{"type":373,"tag":477,"props":1012,"children":1013},{"style":680},[1014],{"type":382,"value":1015}," \"./relay.js\"",{"type":373,"tag":477,"props":1017,"children":1018},{"style":736},[1019],{"type":382,"value":866},{"type":373,"tag":477,"props":1021,"children":1022},{"class":479,"line":498},[1023],{"type":373,"tag":477,"props":1024,"children":1025},{"emptyLinePlaceholder":721},[1026],{"type":382,"value":724},{"type":373,"tag":477,"props":1028,"children":1029},{"class":479,"line":507},[1030,1034,1039,1044,1049],{"type":373,"tag":477,"props":1031,"children":1032},{"style":730},[1033],{"type":382,"value":733},{"type":373,"tag":477,"props":1035,"children":1036},{"style":730},[1037],{"type":382,"value":1038}," async",{"type":373,"tag":477,"props":1040,"children":1041},{"style":730},[1042],{"type":382,"value":1043}," function",{"type":373,"tag":477,"props":1045,"children":1046},{"style":674},[1047],{"type":382,"value":1048}," syncEventCatalog",{"type":373,"tag":477,"props":1050,"children":1051},{"style":736},[1052],{"type":382,"value":1053},"() {\n",{"type":373,"tag":477,"props":1055,"children":1056},{"class":479,"line":516},[1057,1062,1067,1071,1076,1081],{"type":373,"tag":477,"props":1058,"children":1059},{"style":730},[1060],{"type":382,"value":1061},"  await",{"type":373,"tag":477,"props":1063,"children":1064},{"style":736},[1065],{"type":382,"value":1066}," relay.outbound.eventTypes.",{"type":373,"tag":477,"props":1068,"children":1069},{"style":674},[1070],{"type":382,"value":969},{"type":373,"tag":477,"props":1072,"children":1073},{"style":736},[1074],{"type":382,"value":1075},"(",{"type":373,"tag":477,"props":1077,"children":1078},{"style":680},[1079],{"type":382,"value":1080},"\"invoice.paid\"",{"type":373,"tag":477,"props":1082,"children":1083},{"style":736},[1084],{"type":382,"value":1085},", {\n",{"type":373,"tag":477,"props":1087,"children":1088},{"class":479,"line":525},[1089,1094,1099],{"type":373,"tag":477,"props":1090,"children":1091},{"style":736},[1092],{"type":382,"value":1093},"    description: ",{"type":373,"tag":477,"props":1095,"children":1096},{"style":680},[1097],{"type":382,"value":1098},"\"An invoice was paid in full\"",{"type":373,"tag":477,"props":1100,"children":1101},{"style":736},[1102],{"type":382,"value":927},{"type":373,"tag":477,"props":1104,"children":1105},{"class":479,"line":946},[1106,1111,1116,1121,1126,1131,1136,1141,1146],{"type":373,"tag":477,"props":1107,"children":1108},{"style":736},[1109],{"type":382,"value":1110},"    example: { invoice_id: ",{"type":373,"tag":477,"props":1112,"children":1113},{"style":680},[1114],{"type":382,"value":1115},"\"inv_123\"",{"type":373,"tag":477,"props":1117,"children":1118},{"style":736},[1119],{"type":382,"value":1120},", customer_id: ",{"type":373,"tag":477,"props":1122,"children":1123},{"style":680},[1124],{"type":382,"value":1125},"\"customer_42\"",{"type":373,"tag":477,"props":1127,"children":1128},{"style":736},[1129],{"type":382,"value":1130},", amount: ",{"type":373,"tag":477,"props":1132,"children":1133},{"style":702},[1134],{"type":382,"value":1135},"4900",{"type":373,"tag":477,"props":1137,"children":1138},{"style":736},[1139],{"type":382,"value":1140},", currency: ",{"type":373,"tag":477,"props":1142,"children":1143},{"style":680},[1144],{"type":382,"value":1145},"\"usd\"",{"type":373,"tag":477,"props":1147,"children":1148},{"style":736},[1149],{"type":382,"value":1150}," },\n",{"type":373,"tag":477,"props":1152,"children":1154},{"class":479,"line":1153},8,[1155],{"type":373,"tag":477,"props":1156,"children":1157},{"style":736},[1158],{"type":382,"value":1159},"  });\n",{"type":373,"tag":477,"props":1161,"children":1163},{"class":479,"line":1162},9,[1164,1168,1172,1176,1180,1185],{"type":373,"tag":477,"props":1165,"children":1166},{"style":730},[1167],{"type":382,"value":1061},{"type":373,"tag":477,"props":1169,"children":1170},{"style":736},[1171],{"type":382,"value":1066},{"type":373,"tag":477,"props":1173,"children":1174},{"style":674},[1175],{"type":382,"value":969},{"type":373,"tag":477,"props":1177,"children":1178},{"style":736},[1179],{"type":382,"value":1075},{"type":373,"tag":477,"props":1181,"children":1182},{"style":680},[1183],{"type":382,"value":1184},"\"invoice.refunded\"",{"type":373,"tag":477,"props":1186,"children":1187},{"style":736},[1188],{"type":382,"value":1085},{"type":373,"tag":477,"props":1190,"children":1192},{"class":479,"line":1191},10,[1193,1197,1202],{"type":373,"tag":477,"props":1194,"children":1195},{"style":736},[1196],{"type":382,"value":1093},{"type":373,"tag":477,"props":1198,"children":1199},{"style":680},[1200],{"type":382,"value":1201},"\"An invoice was refunded, fully or partially\"",{"type":373,"tag":477,"props":1203,"children":1204},{"style":736},[1205],{"type":382,"value":927},{"type":373,"tag":477,"props":1207,"children":1209},{"class":479,"line":1208},11,[1210,1214,1218,1223,1228,1232,1236,1240,1244],{"type":373,"tag":477,"props":1211,"children":1212},{"style":736},[1213],{"type":382,"value":1110},{"type":373,"tag":477,"props":1215,"children":1216},{"style":680},[1217],{"type":382,"value":1115},{"type":373,"tag":477,"props":1219,"children":1220},{"style":736},[1221],{"type":382,"value":1222},", refund_id: ",{"type":373,"tag":477,"props":1224,"children":1225},{"style":680},[1226],{"type":382,"value":1227},"\"re_9\"",{"type":373,"tag":477,"props":1229,"children":1230},{"style":736},[1231],{"type":382,"value":1130},{"type":373,"tag":477,"props":1233,"children":1234},{"style":702},[1235],{"type":382,"value":1135},{"type":373,"tag":477,"props":1237,"children":1238},{"style":736},[1239],{"type":382,"value":1140},{"type":373,"tag":477,"props":1241,"children":1242},{"style":680},[1243],{"type":382,"value":1145},{"type":373,"tag":477,"props":1245,"children":1246},{"style":736},[1247],{"type":382,"value":1150},{"type":373,"tag":477,"props":1249,"children":1251},{"class":479,"line":1250},12,[1252],{"type":373,"tag":477,"props":1253,"children":1254},{"style":736},[1255],{"type":382,"value":1159},{"type":373,"tag":477,"props":1257,"children":1259},{"class":479,"line":1258},13,[1260],{"type":373,"tag":477,"props":1261,"children":1262},{"style":736},[1263],{"type":382,"value":1264},"}\n",{"type":373,"tag":374,"props":1266,"children":1267},{},[1268,1270,1276],{"type":382,"value":1269},"To retire an event later, upsert it with ",{"type":373,"tag":385,"props":1271,"children":1273},{"className":1272},[],[1274],{"type":382,"value":1275},"deprecated: true",{"type":382,"value":1277},". Deprecated event types can't be published.",{"type":373,"tag":533,"props":1279,"children":1281},{"id":1280},"_3-onboard-a-customer-and-register-their-endpoint",[1282],{"type":382,"value":1283},"3. Onboard a customer and register their endpoint",{"type":373,"tag":374,"props":1285,"children":1286},{},[1287,1289,1294,1296,1301,1303,1309],{"type":382,"value":1288},"A ",{"type":373,"tag":378,"props":1290,"children":1291},{},[1292],{"type":382,"value":1293},"consumer",{"type":382,"value":1295}," is one of your customers. Use your own customer or organization ID so you never need a mapping table. An ",{"type":373,"tag":378,"props":1297,"children":1298},{},[1299],{"type":382,"value":1300},"endpoint",{"type":382,"value":1302}," is an HTTPS URL the customer gives you, subscribed to some event types (or ",{"type":373,"tag":385,"props":1304,"children":1306},{"className":1305},[],[1307],{"type":382,"value":1308},"[\"*\"]",{"type":382,"value":1310}," for all).",{"type":373,"tag":468,"props":1312,"children":1314},{"className":823,"code":1313,"language":825,"meta":345,"style":345},"// onboarding.ts\nimport { relay } from \"./relay.js\";\n\nexport async function addCustomerEndpoint(customer: { id: string; name: string }, url: string) {\n  // Creates the consumer, or updates its name if it already exists.\n  await relay.outbound.consumers.upsert(customer.id, { name: customer.name });\n\n  const endpoint = await relay.outbound.endpoints.create(customer.id, {\n    url,\n    eventTypes: [\"invoice.paid\", \"invoice.refunded\"],\n    description: \"Production webhook receiver\",\n    autoDisable: true, // disable after 100 failures in a row spanning 12+ hours\n    timeout: 15,       // seconds per attempt, up to 60\n  });\n\n  // Store endpoint.id next to the customer. Show endpoint.secret to the customer\n  // once: it is the whsec_ key they verify signatures with.\n  return { endpointId: endpoint.id, signingSecret: endpoint.secret };\n}\n",[1315],{"type":373,"tag":385,"props":1316,"children":1317},{"__ignoreMap":345},[1318,1326,1349,1356,1451,1459,1480,1487,1524,1532,1557,1573,1595,1618,1626,1634,1643,1652,1666],{"type":373,"tag":477,"props":1319,"children":1320},{"class":479,"line":480},[1321],{"type":373,"tag":477,"props":1322,"children":1323},{"style":835},[1324],{"type":382,"value":1325},"// onboarding.ts\n",{"type":373,"tag":477,"props":1327,"children":1328},{"class":479,"line":489},[1329,1333,1337,1341,1345],{"type":373,"tag":477,"props":1330,"children":1331},{"style":730},[1332],{"type":382,"value":846},{"type":373,"tag":477,"props":1334,"children":1335},{"style":736},[1336],{"type":382,"value":1006},{"type":373,"tag":477,"props":1338,"children":1339},{"style":730},[1340],{"type":382,"value":856},{"type":373,"tag":477,"props":1342,"children":1343},{"style":680},[1344],{"type":382,"value":1015},{"type":373,"tag":477,"props":1346,"children":1347},{"style":736},[1348],{"type":382,"value":866},{"type":373,"tag":477,"props":1350,"children":1351},{"class":479,"line":498},[1352],{"type":373,"tag":477,"props":1353,"children":1354},{"emptyLinePlaceholder":721},[1355],{"type":382,"value":724},{"type":373,"tag":477,"props":1357,"children":1358},{"class":479,"line":507},[1359,1363,1367,1371,1376,1380,1386,1391,1396,1401,1405,1410,1415,1420,1424,1428,1433,1438,1442,1446],{"type":373,"tag":477,"props":1360,"children":1361},{"style":730},[1362],{"type":382,"value":733},{"type":373,"tag":477,"props":1364,"children":1365},{"style":730},[1366],{"type":382,"value":1038},{"type":373,"tag":477,"props":1368,"children":1369},{"style":730},[1370],{"type":382,"value":1043},{"type":373,"tag":477,"props":1372,"children":1373},{"style":674},[1374],{"type":382,"value":1375}," addCustomerEndpoint",{"type":373,"tag":477,"props":1377,"children":1378},{"style":736},[1379],{"type":382,"value":1075},{"type":373,"tag":477,"props":1381,"children":1383},{"style":1382},"--shiki-default:#FFAB70",[1384],{"type":382,"value":1385},"customer",{"type":373,"tag":477,"props":1387,"children":1388},{"style":730},[1389],{"type":382,"value":1390},":",{"type":373,"tag":477,"props":1392,"children":1393},{"style":736},[1394],{"type":382,"value":1395}," { ",{"type":373,"tag":477,"props":1397,"children":1398},{"style":1382},[1399],{"type":382,"value":1400},"id",{"type":373,"tag":477,"props":1402,"children":1403},{"style":730},[1404],{"type":382,"value":1390},{"type":373,"tag":477,"props":1406,"children":1407},{"style":702},[1408],{"type":382,"value":1409}," string",{"type":373,"tag":477,"props":1411,"children":1412},{"style":736},[1413],{"type":382,"value":1414},"; ",{"type":373,"tag":477,"props":1416,"children":1417},{"style":1382},[1418],{"type":382,"value":1419},"name",{"type":373,"tag":477,"props":1421,"children":1422},{"style":730},[1423],{"type":382,"value":1390},{"type":373,"tag":477,"props":1425,"children":1426},{"style":702},[1427],{"type":382,"value":1409},{"type":373,"tag":477,"props":1429,"children":1430},{"style":736},[1431],{"type":382,"value":1432}," }, ",{"type":373,"tag":477,"props":1434,"children":1435},{"style":1382},[1436],{"type":382,"value":1437},"url",{"type":373,"tag":477,"props":1439,"children":1440},{"style":730},[1441],{"type":382,"value":1390},{"type":373,"tag":477,"props":1443,"children":1444},{"style":702},[1445],{"type":382,"value":1409},{"type":373,"tag":477,"props":1447,"children":1448},{"style":736},[1449],{"type":382,"value":1450},") {\n",{"type":373,"tag":477,"props":1452,"children":1453},{"class":479,"line":516},[1454],{"type":373,"tag":477,"props":1455,"children":1456},{"style":835},[1457],{"type":382,"value":1458},"  // Creates the consumer, or updates its name if it already exists.\n",{"type":373,"tag":477,"props":1460,"children":1461},{"class":479,"line":525},[1462,1466,1471,1475],{"type":373,"tag":477,"props":1463,"children":1464},{"style":730},[1465],{"type":382,"value":1061},{"type":373,"tag":477,"props":1467,"children":1468},{"style":736},[1469],{"type":382,"value":1470}," relay.outbound.consumers.",{"type":373,"tag":477,"props":1472,"children":1473},{"style":674},[1474],{"type":382,"value":969},{"type":373,"tag":477,"props":1476,"children":1477},{"style":736},[1478],{"type":382,"value":1479},"(customer.id, { name: customer.name });\n",{"type":373,"tag":477,"props":1481,"children":1482},{"class":479,"line":946},[1483],{"type":373,"tag":477,"props":1484,"children":1485},{"emptyLinePlaceholder":721},[1486],{"type":382,"value":724},{"type":373,"tag":477,"props":1488,"children":1489},{"class":479,"line":1153},[1490,1495,1500,1504,1509,1514,1519],{"type":373,"tag":477,"props":1491,"children":1492},{"style":730},[1493],{"type":382,"value":1494},"  const",{"type":373,"tag":477,"props":1496,"children":1497},{"style":702},[1498],{"type":382,"value":1499}," endpoint",{"type":373,"tag":477,"props":1501,"children":1502},{"style":730},[1503],{"type":382,"value":895},{"type":373,"tag":477,"props":1505,"children":1506},{"style":730},[1507],{"type":382,"value":1508}," await",{"type":373,"tag":477,"props":1510,"children":1511},{"style":736},[1512],{"type":382,"value":1513}," relay.outbound.endpoints.",{"type":373,"tag":477,"props":1515,"children":1516},{"style":674},[1517],{"type":382,"value":1518},"create",{"type":373,"tag":477,"props":1520,"children":1521},{"style":736},[1522],{"type":382,"value":1523},"(customer.id, {\n",{"type":373,"tag":477,"props":1525,"children":1526},{"class":479,"line":1162},[1527],{"type":373,"tag":477,"props":1528,"children":1529},{"style":736},[1530],{"type":382,"value":1531},"    url,\n",{"type":373,"tag":477,"props":1533,"children":1534},{"class":479,"line":1191},[1535,1540,1544,1548,1552],{"type":373,"tag":477,"props":1536,"children":1537},{"style":736},[1538],{"type":382,"value":1539},"    eventTypes: [",{"type":373,"tag":477,"props":1541,"children":1542},{"style":680},[1543],{"type":382,"value":1080},{"type":373,"tag":477,"props":1545,"children":1546},{"style":736},[1547],{"type":382,"value":443},{"type":373,"tag":477,"props":1549,"children":1550},{"style":680},[1551],{"type":382,"value":1184},{"type":373,"tag":477,"props":1553,"children":1554},{"style":736},[1555],{"type":382,"value":1556},"],\n",{"type":373,"tag":477,"props":1558,"children":1559},{"class":479,"line":1208},[1560,1564,1569],{"type":373,"tag":477,"props":1561,"children":1562},{"style":736},[1563],{"type":382,"value":1093},{"type":373,"tag":477,"props":1565,"children":1566},{"style":680},[1567],{"type":382,"value":1568},"\"Production webhook receiver\"",{"type":373,"tag":477,"props":1570,"children":1571},{"style":736},[1572],{"type":382,"value":927},{"type":373,"tag":477,"props":1574,"children":1575},{"class":479,"line":1250},[1576,1581,1586,1590],{"type":373,"tag":477,"props":1577,"children":1578},{"style":736},[1579],{"type":382,"value":1580},"    autoDisable: ",{"type":373,"tag":477,"props":1582,"children":1583},{"style":702},[1584],{"type":382,"value":1585},"true",{"type":373,"tag":477,"props":1587,"children":1588},{"style":736},[1589],{"type":382,"value":443},{"type":373,"tag":477,"props":1591,"children":1592},{"style":835},[1593],{"type":382,"value":1594},"// disable after 100 failures in a row spanning 12+ hours\n",{"type":373,"tag":477,"props":1596,"children":1597},{"class":479,"line":1258},[1598,1603,1608,1613],{"type":373,"tag":477,"props":1599,"children":1600},{"style":736},[1601],{"type":382,"value":1602},"    timeout: ",{"type":373,"tag":477,"props":1604,"children":1605},{"style":702},[1606],{"type":382,"value":1607},"15",{"type":373,"tag":477,"props":1609,"children":1610},{"style":736},[1611],{"type":382,"value":1612},",       ",{"type":373,"tag":477,"props":1614,"children":1615},{"style":835},[1616],{"type":382,"value":1617},"// seconds per attempt, up to 60\n",{"type":373,"tag":477,"props":1619,"children":1621},{"class":479,"line":1620},14,[1622],{"type":373,"tag":477,"props":1623,"children":1624},{"style":736},[1625],{"type":382,"value":1159},{"type":373,"tag":477,"props":1627,"children":1629},{"class":479,"line":1628},15,[1630],{"type":373,"tag":477,"props":1631,"children":1632},{"emptyLinePlaceholder":721},[1633],{"type":382,"value":724},{"type":373,"tag":477,"props":1635,"children":1637},{"class":479,"line":1636},16,[1638],{"type":373,"tag":477,"props":1639,"children":1640},{"style":835},[1641],{"type":382,"value":1642},"  // Store endpoint.id next to the customer. Show endpoint.secret to the customer\n",{"type":373,"tag":477,"props":1644,"children":1646},{"class":479,"line":1645},17,[1647],{"type":373,"tag":477,"props":1648,"children":1649},{"style":835},[1650],{"type":382,"value":1651},"  // once: it is the whsec_ key they verify signatures with.\n",{"type":373,"tag":477,"props":1653,"children":1655},{"class":479,"line":1654},18,[1656,1661],{"type":373,"tag":477,"props":1657,"children":1658},{"style":730},[1659],{"type":382,"value":1660},"  return",{"type":373,"tag":477,"props":1662,"children":1663},{"style":736},[1664],{"type":382,"value":1665}," { endpointId: endpoint.id, signingSecret: endpoint.secret };\n",{"type":373,"tag":477,"props":1667,"children":1669},{"class":479,"line":1668},19,[1670],{"type":373,"tag":477,"props":1671,"children":1672},{"style":736},[1673],{"type":382,"value":1264},{"type":373,"tag":374,"props":1675,"children":1676},{},[1677,1679,1685],{"type":382,"value":1678},"The URL must be public HTTPS. Hosts that resolve to private or loopback addresses are rejected, and each URL can be registered once per consumer. If the customer loses the secret, ",{"type":373,"tag":385,"props":1680,"children":1682},{"className":1681},[],[1683],{"type":382,"value":1684},"relay.outbound.endpoints.revealSecret(endpointId)",{"type":382,"value":1686}," returns it again.",{"type":373,"tag":533,"props":1688,"children":1690},{"id":1689},"_4-publish-when-the-event-happens",[1691],{"type":382,"value":1692},"4. Publish when the event happens",{"type":373,"tag":374,"props":1694,"children":1695},{},[1696,1698,1704],{"type":382,"value":1697},"Call ",{"type":373,"tag":385,"props":1699,"children":1701},{"className":1700},[],[1702],{"type":382,"value":1703},"publish",{"type":382,"value":1705}," from the code path where the event actually occurs, after your database transaction commits. Derive the idempotency key from the event itself, so a retry after a timeout, a crash or a duplicate job can never deliver twice.",{"type":373,"tag":468,"props":1707,"children":1709},{"className":823,"code":1708,"language":825,"meta":345,"style":345},"// billing.ts\nimport { WebhookRelayAPIError } from \"@webhookrelay/sdk\";\nimport { relay } from \"./relay.js\";\n\ntype Invoice = { id: string; customerId: string; amount: number; currency: string };\n\nexport async function onInvoicePaid(invoice: Invoice) {\n  try {\n    const receipt = await relay.outbound.messages.publish(\n      {\n        consumer: invoice.customerId,\n        eventType: \"invoice.paid\",\n        eventId: `evt_${invoice.id}`, // your own reference, stored on the receipt\n        payload: {\n          invoice_id: invoice.id,\n          customer_id: invoice.customerId,\n          amount: invoice.amount,\n          currency: invoice.currency,\n        },\n      },\n      { idempotencyKey: `invoice-paid:${invoice.id}` },\n    );\n    // 202 Accepted: stored durably, delivery is asynchronous.\n    // receipt.id is sent to every endpoint as the webhook-id header.\n    return receipt;\n  } catch (err) {\n    if (err instanceof WebhookRelayAPIError) {\n      if (err.status === 404) return null;   // customer has no consumer yet: nothing to send\n      if (err.status === 409) throw new Error(`idempotency key reused for a different payload: ${invoice.id}`);\n      if (err.status === 413) throw new Error(\"payload is over 256 KiB, send a reference and let the customer fetch it\");\n      // 429 means 10,000 messages are already waiting to be prepared. Retry later with the same key.\n    }\n    throw err;\n  }\n}\n",[1710],{"type":373,"tag":385,"props":1711,"children":1712},{"__ignoreMap":345},[1713,1721,1745,1768,1775,1865,1872,1913,1926,1961,1969,1977,1993,2033,2041,2049,2057,2065,2073,2081,2090,2124,2133,2142,2151,2165,2184,2212,2261,2330,2380,2389,2398,2412,2421],{"type":373,"tag":477,"props":1714,"children":1715},{"class":479,"line":480},[1716],{"type":373,"tag":477,"props":1717,"children":1718},{"style":835},[1719],{"type":382,"value":1720},"// billing.ts\n",{"type":373,"tag":477,"props":1722,"children":1723},{"class":479,"line":489},[1724,1728,1733,1737,1741],{"type":373,"tag":477,"props":1725,"children":1726},{"style":730},[1727],{"type":382,"value":846},{"type":373,"tag":477,"props":1729,"children":1730},{"style":736},[1731],{"type":382,"value":1732}," { WebhookRelayAPIError } ",{"type":373,"tag":477,"props":1734,"children":1735},{"style":730},[1736],{"type":382,"value":856},{"type":373,"tag":477,"props":1738,"children":1739},{"style":680},[1740],{"type":382,"value":861},{"type":373,"tag":477,"props":1742,"children":1743},{"style":736},[1744],{"type":382,"value":866},{"type":373,"tag":477,"props":1746,"children":1747},{"class":479,"line":498},[1748,1752,1756,1760,1764],{"type":373,"tag":477,"props":1749,"children":1750},{"style":730},[1751],{"type":382,"value":846},{"type":373,"tag":477,"props":1753,"children":1754},{"style":736},[1755],{"type":382,"value":1006},{"type":373,"tag":477,"props":1757,"children":1758},{"style":730},[1759],{"type":382,"value":856},{"type":373,"tag":477,"props":1761,"children":1762},{"style":680},[1763],{"type":382,"value":1015},{"type":373,"tag":477,"props":1765,"children":1766},{"style":736},[1767],{"type":382,"value":866},{"type":373,"tag":477,"props":1769,"children":1770},{"class":479,"line":507},[1771],{"type":373,"tag":477,"props":1772,"children":1773},{"emptyLinePlaceholder":721},[1774],{"type":382,"value":724},{"type":373,"tag":477,"props":1776,"children":1777},{"class":479,"line":516},[1778,1783,1788,1792,1796,1800,1804,1808,1812,1817,1821,1825,1829,1834,1838,1843,1847,1852,1856,1860],{"type":373,"tag":477,"props":1779,"children":1780},{"style":730},[1781],{"type":382,"value":1782},"type",{"type":373,"tag":477,"props":1784,"children":1785},{"style":674},[1786],{"type":382,"value":1787}," Invoice",{"type":373,"tag":477,"props":1789,"children":1790},{"style":730},[1791],{"type":382,"value":895},{"type":373,"tag":477,"props":1793,"children":1794},{"style":736},[1795],{"type":382,"value":1395},{"type":373,"tag":477,"props":1797,"children":1798},{"style":1382},[1799],{"type":382,"value":1400},{"type":373,"tag":477,"props":1801,"children":1802},{"style":730},[1803],{"type":382,"value":1390},{"type":373,"tag":477,"props":1805,"children":1806},{"style":702},[1807],{"type":382,"value":1409},{"type":373,"tag":477,"props":1809,"children":1810},{"style":736},[1811],{"type":382,"value":1414},{"type":373,"tag":477,"props":1813,"children":1814},{"style":1382},[1815],{"type":382,"value":1816},"customerId",{"type":373,"tag":477,"props":1818,"children":1819},{"style":730},[1820],{"type":382,"value":1390},{"type":373,"tag":477,"props":1822,"children":1823},{"style":702},[1824],{"type":382,"value":1409},{"type":373,"tag":477,"props":1826,"children":1827},{"style":736},[1828],{"type":382,"value":1414},{"type":373,"tag":477,"props":1830,"children":1831},{"style":1382},[1832],{"type":382,"value":1833},"amount",{"type":373,"tag":477,"props":1835,"children":1836},{"style":730},[1837],{"type":382,"value":1390},{"type":373,"tag":477,"props":1839,"children":1840},{"style":702},[1841],{"type":382,"value":1842}," number",{"type":373,"tag":477,"props":1844,"children":1845},{"style":736},[1846],{"type":382,"value":1414},{"type":373,"tag":477,"props":1848,"children":1849},{"style":1382},[1850],{"type":382,"value":1851},"currency",{"type":373,"tag":477,"props":1853,"children":1854},{"style":730},[1855],{"type":382,"value":1390},{"type":373,"tag":477,"props":1857,"children":1858},{"style":702},[1859],{"type":382,"value":1409},{"type":373,"tag":477,"props":1861,"children":1862},{"style":736},[1863],{"type":382,"value":1864}," };\n",{"type":373,"tag":477,"props":1866,"children":1867},{"class":479,"line":525},[1868],{"type":373,"tag":477,"props":1869,"children":1870},{"emptyLinePlaceholder":721},[1871],{"type":382,"value":724},{"type":373,"tag":477,"props":1873,"children":1874},{"class":479,"line":946},[1875,1879,1883,1887,1892,1896,1901,1905,1909],{"type":373,"tag":477,"props":1876,"children":1877},{"style":730},[1878],{"type":382,"value":733},{"type":373,"tag":477,"props":1880,"children":1881},{"style":730},[1882],{"type":382,"value":1038},{"type":373,"tag":477,"props":1884,"children":1885},{"style":730},[1886],{"type":382,"value":1043},{"type":373,"tag":477,"props":1888,"children":1889},{"style":674},[1890],{"type":382,"value":1891}," onInvoicePaid",{"type":373,"tag":477,"props":1893,"children":1894},{"style":736},[1895],{"type":382,"value":1075},{"type":373,"tag":477,"props":1897,"children":1898},{"style":1382},[1899],{"type":382,"value":1900},"invoice",{"type":373,"tag":477,"props":1902,"children":1903},{"style":730},[1904],{"type":382,"value":1390},{"type":373,"tag":477,"props":1906,"children":1907},{"style":674},[1908],{"type":382,"value":1787},{"type":373,"tag":477,"props":1910,"children":1911},{"style":736},[1912],{"type":382,"value":1450},{"type":373,"tag":477,"props":1914,"children":1915},{"class":479,"line":1153},[1916,1921],{"type":373,"tag":477,"props":1917,"children":1918},{"style":730},[1919],{"type":382,"value":1920},"  try",{"type":373,"tag":477,"props":1922,"children":1923},{"style":736},[1924],{"type":382,"value":1925}," {\n",{"type":373,"tag":477,"props":1927,"children":1928},{"class":479,"line":1162},[1929,1934,1939,1943,1947,1952,1956],{"type":373,"tag":477,"props":1930,"children":1931},{"style":730},[1932],{"type":382,"value":1933},"    const",{"type":373,"tag":477,"props":1935,"children":1936},{"style":702},[1937],{"type":382,"value":1938}," receipt",{"type":373,"tag":477,"props":1940,"children":1941},{"style":730},[1942],{"type":382,"value":895},{"type":373,"tag":477,"props":1944,"children":1945},{"style":730},[1946],{"type":382,"value":1508},{"type":373,"tag":477,"props":1948,"children":1949},{"style":736},[1950],{"type":382,"value":1951}," relay.outbound.messages.",{"type":373,"tag":477,"props":1953,"children":1954},{"style":674},[1955],{"type":382,"value":1703},{"type":373,"tag":477,"props":1957,"children":1958},{"style":736},[1959],{"type":382,"value":1960},"(\n",{"type":373,"tag":477,"props":1962,"children":1963},{"class":479,"line":1191},[1964],{"type":373,"tag":477,"props":1965,"children":1966},{"style":736},[1967],{"type":382,"value":1968},"      {\n",{"type":373,"tag":477,"props":1970,"children":1971},{"class":479,"line":1208},[1972],{"type":373,"tag":477,"props":1973,"children":1974},{"style":736},[1975],{"type":382,"value":1976},"        consumer: invoice.customerId,\n",{"type":373,"tag":477,"props":1978,"children":1979},{"class":479,"line":1250},[1980,1985,1989],{"type":373,"tag":477,"props":1981,"children":1982},{"style":736},[1983],{"type":382,"value":1984},"        eventType: ",{"type":373,"tag":477,"props":1986,"children":1987},{"style":680},[1988],{"type":382,"value":1080},{"type":373,"tag":477,"props":1990,"children":1991},{"style":736},[1992],{"type":382,"value":927},{"type":373,"tag":477,"props":1994,"children":1995},{"class":479,"line":1258},[1996,2001,2006,2010,2015,2019,2024,2028],{"type":373,"tag":477,"props":1997,"children":1998},{"style":736},[1999],{"type":382,"value":2000},"        eventId: ",{"type":373,"tag":477,"props":2002,"children":2003},{"style":680},[2004],{"type":382,"value":2005},"`evt_${",{"type":373,"tag":477,"props":2007,"children":2008},{"style":736},[2009],{"type":382,"value":1900},{"type":373,"tag":477,"props":2011,"children":2012},{"style":680},[2013],{"type":382,"value":2014},".",{"type":373,"tag":477,"props":2016,"children":2017},{"style":736},[2018],{"type":382,"value":1400},{"type":373,"tag":477,"props":2020,"children":2021},{"style":680},[2022],{"type":382,"value":2023},"}`",{"type":373,"tag":477,"props":2025,"children":2026},{"style":736},[2027],{"type":382,"value":443},{"type":373,"tag":477,"props":2029,"children":2030},{"style":835},[2031],{"type":382,"value":2032},"// your own reference, stored on the receipt\n",{"type":373,"tag":477,"props":2034,"children":2035},{"class":479,"line":1620},[2036],{"type":373,"tag":477,"props":2037,"children":2038},{"style":736},[2039],{"type":382,"value":2040},"        payload: {\n",{"type":373,"tag":477,"props":2042,"children":2043},{"class":479,"line":1628},[2044],{"type":373,"tag":477,"props":2045,"children":2046},{"style":736},[2047],{"type":382,"value":2048},"          invoice_id: invoice.id,\n",{"type":373,"tag":477,"props":2050,"children":2051},{"class":479,"line":1636},[2052],{"type":373,"tag":477,"props":2053,"children":2054},{"style":736},[2055],{"type":382,"value":2056},"          customer_id: invoice.customerId,\n",{"type":373,"tag":477,"props":2058,"children":2059},{"class":479,"line":1645},[2060],{"type":373,"tag":477,"props":2061,"children":2062},{"style":736},[2063],{"type":382,"value":2064},"          amount: invoice.amount,\n",{"type":373,"tag":477,"props":2066,"children":2067},{"class":479,"line":1654},[2068],{"type":373,"tag":477,"props":2069,"children":2070},{"style":736},[2071],{"type":382,"value":2072},"          currency: invoice.currency,\n",{"type":373,"tag":477,"props":2074,"children":2075},{"class":479,"line":1668},[2076],{"type":373,"tag":477,"props":2077,"children":2078},{"style":736},[2079],{"type":382,"value":2080},"        },\n",{"type":373,"tag":477,"props":2082,"children":2084},{"class":479,"line":2083},20,[2085],{"type":373,"tag":477,"props":2086,"children":2087},{"style":736},[2088],{"type":382,"value":2089},"      },\n",{"type":373,"tag":477,"props":2091,"children":2093},{"class":479,"line":2092},21,[2094,2099,2104,2108,2112,2116,2120],{"type":373,"tag":477,"props":2095,"children":2096},{"style":736},[2097],{"type":382,"value":2098},"      { idempotencyKey: ",{"type":373,"tag":477,"props":2100,"children":2101},{"style":680},[2102],{"type":382,"value":2103},"`invoice-paid:${",{"type":373,"tag":477,"props":2105,"children":2106},{"style":736},[2107],{"type":382,"value":1900},{"type":373,"tag":477,"props":2109,"children":2110},{"style":680},[2111],{"type":382,"value":2014},{"type":373,"tag":477,"props":2113,"children":2114},{"style":736},[2115],{"type":382,"value":1400},{"type":373,"tag":477,"props":2117,"children":2118},{"style":680},[2119],{"type":382,"value":2023},{"type":373,"tag":477,"props":2121,"children":2122},{"style":736},[2123],{"type":382,"value":1150},{"type":373,"tag":477,"props":2125,"children":2127},{"class":479,"line":2126},22,[2128],{"type":373,"tag":477,"props":2129,"children":2130},{"style":736},[2131],{"type":382,"value":2132},"    );\n",{"type":373,"tag":477,"props":2134,"children":2136},{"class":479,"line":2135},23,[2137],{"type":373,"tag":477,"props":2138,"children":2139},{"style":835},[2140],{"type":382,"value":2141},"    // 202 Accepted: stored durably, delivery is asynchronous.\n",{"type":373,"tag":477,"props":2143,"children":2145},{"class":479,"line":2144},24,[2146],{"type":373,"tag":477,"props":2147,"children":2148},{"style":835},[2149],{"type":382,"value":2150},"    // receipt.id is sent to every endpoint as the webhook-id header.\n",{"type":373,"tag":477,"props":2152,"children":2154},{"class":479,"line":2153},25,[2155,2160],{"type":373,"tag":477,"props":2156,"children":2157},{"style":730},[2158],{"type":382,"value":2159},"    return",{"type":373,"tag":477,"props":2161,"children":2162},{"style":736},[2163],{"type":382,"value":2164}," receipt;\n",{"type":373,"tag":477,"props":2166,"children":2168},{"class":479,"line":2167},26,[2169,2174,2179],{"type":373,"tag":477,"props":2170,"children":2171},{"style":736},[2172],{"type":382,"value":2173},"  } ",{"type":373,"tag":477,"props":2175,"children":2176},{"style":730},[2177],{"type":382,"value":2178},"catch",{"type":373,"tag":477,"props":2180,"children":2181},{"style":736},[2182],{"type":382,"value":2183}," (err) {\n",{"type":373,"tag":477,"props":2185,"children":2187},{"class":479,"line":2186},27,[2188,2193,2198,2203,2208],{"type":373,"tag":477,"props":2189,"children":2190},{"style":730},[2191],{"type":382,"value":2192},"    if",{"type":373,"tag":477,"props":2194,"children":2195},{"style":736},[2196],{"type":382,"value":2197}," (err ",{"type":373,"tag":477,"props":2199,"children":2200},{"style":730},[2201],{"type":382,"value":2202},"instanceof",{"type":373,"tag":477,"props":2204,"children":2205},{"style":674},[2206],{"type":382,"value":2207}," WebhookRelayAPIError",{"type":373,"tag":477,"props":2209,"children":2210},{"style":736},[2211],{"type":382,"value":1450},{"type":373,"tag":477,"props":2213,"children":2215},{"class":479,"line":2214},28,[2216,2221,2226,2231,2236,2241,2246,2251,2256],{"type":373,"tag":477,"props":2217,"children":2218},{"style":730},[2219],{"type":382,"value":2220},"      if",{"type":373,"tag":477,"props":2222,"children":2223},{"style":736},[2224],{"type":382,"value":2225}," (err.status ",{"type":373,"tag":477,"props":2227,"children":2228},{"style":730},[2229],{"type":382,"value":2230},"===",{"type":373,"tag":477,"props":2232,"children":2233},{"style":702},[2234],{"type":382,"value":2235}," 404",{"type":373,"tag":477,"props":2237,"children":2238},{"style":736},[2239],{"type":382,"value":2240},") ",{"type":373,"tag":477,"props":2242,"children":2243},{"style":730},[2244],{"type":382,"value":2245},"return",{"type":373,"tag":477,"props":2247,"children":2248},{"style":702},[2249],{"type":382,"value":2250}," null",{"type":373,"tag":477,"props":2252,"children":2253},{"style":736},[2254],{"type":382,"value":2255},";   ",{"type":373,"tag":477,"props":2257,"children":2258},{"style":835},[2259],{"type":382,"value":2260},"// customer has no consumer yet: nothing to send\n",{"type":373,"tag":477,"props":2262,"children":2264},{"class":479,"line":2263},29,[2265,2269,2273,2277,2282,2286,2291,2295,2300,2304,2309,2313,2317,2321,2325],{"type":373,"tag":477,"props":2266,"children":2267},{"style":730},[2268],{"type":382,"value":2220},{"type":373,"tag":477,"props":2270,"children":2271},{"style":736},[2272],{"type":382,"value":2225},{"type":373,"tag":477,"props":2274,"children":2275},{"style":730},[2276],{"type":382,"value":2230},{"type":373,"tag":477,"props":2278,"children":2279},{"style":702},[2280],{"type":382,"value":2281}," 409",{"type":373,"tag":477,"props":2283,"children":2284},{"style":736},[2285],{"type":382,"value":2240},{"type":373,"tag":477,"props":2287,"children":2288},{"style":730},[2289],{"type":382,"value":2290},"throw",{"type":373,"tag":477,"props":2292,"children":2293},{"style":730},[2294],{"type":382,"value":900},{"type":373,"tag":477,"props":2296,"children":2297},{"style":674},[2298],{"type":382,"value":2299}," Error",{"type":373,"tag":477,"props":2301,"children":2302},{"style":736},[2303],{"type":382,"value":1075},{"type":373,"tag":477,"props":2305,"children":2306},{"style":680},[2307],{"type":382,"value":2308},"`idempotency key reused for a different payload: ${",{"type":373,"tag":477,"props":2310,"children":2311},{"style":736},[2312],{"type":382,"value":1900},{"type":373,"tag":477,"props":2314,"children":2315},{"style":680},[2316],{"type":382,"value":2014},{"type":373,"tag":477,"props":2318,"children":2319},{"style":736},[2320],{"type":382,"value":1400},{"type":373,"tag":477,"props":2322,"children":2323},{"style":680},[2324],{"type":382,"value":2023},{"type":373,"tag":477,"props":2326,"children":2327},{"style":736},[2328],{"type":382,"value":2329},");\n",{"type":373,"tag":477,"props":2331,"children":2333},{"class":479,"line":2332},30,[2334,2338,2342,2346,2351,2355,2359,2363,2367,2371,2376],{"type":373,"tag":477,"props":2335,"children":2336},{"style":730},[2337],{"type":382,"value":2220},{"type":373,"tag":477,"props":2339,"children":2340},{"style":736},[2341],{"type":382,"value":2225},{"type":373,"tag":477,"props":2343,"children":2344},{"style":730},[2345],{"type":382,"value":2230},{"type":373,"tag":477,"props":2347,"children":2348},{"style":702},[2349],{"type":382,"value":2350}," 413",{"type":373,"tag":477,"props":2352,"children":2353},{"style":736},[2354],{"type":382,"value":2240},{"type":373,"tag":477,"props":2356,"children":2357},{"style":730},[2358],{"type":382,"value":2290},{"type":373,"tag":477,"props":2360,"children":2361},{"style":730},[2362],{"type":382,"value":900},{"type":373,"tag":477,"props":2364,"children":2365},{"style":674},[2366],{"type":382,"value":2299},{"type":373,"tag":477,"props":2368,"children":2369},{"style":736},[2370],{"type":382,"value":1075},{"type":373,"tag":477,"props":2372,"children":2373},{"style":680},[2374],{"type":382,"value":2375},"\"payload is over 256 KiB, send a reference and let the customer fetch it\"",{"type":373,"tag":477,"props":2377,"children":2378},{"style":736},[2379],{"type":382,"value":2329},{"type":373,"tag":477,"props":2381,"children":2383},{"class":479,"line":2382},31,[2384],{"type":373,"tag":477,"props":2385,"children":2386},{"style":835},[2387],{"type":382,"value":2388},"      // 429 means 10,000 messages are already waiting to be prepared. Retry later with the same key.\n",{"type":373,"tag":477,"props":2390,"children":2392},{"class":479,"line":2391},32,[2393],{"type":373,"tag":477,"props":2394,"children":2395},{"style":736},[2396],{"type":382,"value":2397},"    }\n",{"type":373,"tag":477,"props":2399,"children":2401},{"class":479,"line":2400},33,[2402,2407],{"type":373,"tag":477,"props":2403,"children":2404},{"style":730},[2405],{"type":382,"value":2406},"    throw",{"type":373,"tag":477,"props":2408,"children":2409},{"style":736},[2410],{"type":382,"value":2411}," err;\n",{"type":373,"tag":477,"props":2413,"children":2415},{"class":479,"line":2414},34,[2416],{"type":373,"tag":477,"props":2417,"children":2418},{"style":736},[2419],{"type":382,"value":2420},"  }\n",{"type":373,"tag":477,"props":2422,"children":2424},{"class":479,"line":2423},35,[2425],{"type":373,"tag":477,"props":2426,"children":2427},{"style":736},[2428],{"type":382,"value":1264},{"type":373,"tag":374,"props":2430,"children":2431},{},[2432],{"type":382,"value":2433},"A few rules that keep this correct:",{"type":373,"tag":540,"props":2435,"children":2436},{},[2437,2447,2457],{"type":373,"tag":431,"props":2438,"children":2439},{},[2440,2445],{"type":373,"tag":378,"props":2441,"children":2442},{},[2443],{"type":382,"value":2444},"Publish after commit.",{"type":382,"value":2446}," If you publish inside the transaction and it rolls back, the customer receives an event that never happened. If your process can die between commit and publish, write the event to an outbox table in the same transaction and publish from a worker. The idempotency key makes the worker's retries safe.",{"type":373,"tag":431,"props":2448,"children":2449},{},[2450,2455],{"type":373,"tag":378,"props":2451,"children":2452},{},[2453],{"type":382,"value":2454},"Send IDs and state, not secrets.",{"type":382,"value":2456}," Payloads are logged for 35 days in your delivery history. Keep tokens, card data and passwords out of them.",{"type":373,"tag":431,"props":2458,"children":2459},{},[2460,2465],{"type":373,"tag":378,"props":2461,"children":2462},{},[2463],{"type":382,"value":2464},"Keep payloads small.",{"type":382,"value":2466}," The limit is 256 KiB. For large objects, send an ID and a URL your customer can fetch.",{"type":373,"tag":533,"props":2468,"children":2470},{"id":2469},"_5-inspect-what-was-delivered",[2471],{"type":382,"value":2472},"5. Inspect what was delivered",{"type":373,"tag":374,"props":2474,"children":2475},{},[2476,2482],{"type":373,"tag":385,"props":2477,"children":2479},{"className":2478},[],[2480],{"type":382,"value":2481},"messages.get",{"type":382,"value":2483}," returns the payload plus one delivery per endpoint, with every attempt's status code, duration and error. A message that was just accepted may still be in preparation and have no deliveries yet.",{"type":373,"tag":468,"props":2485,"children":2487},{"className":823,"code":2486,"language":825,"meta":345,"style":345},"// inspect.ts\nimport { relay } from \"./relay.js\";\n\nexport async function showMessage(messageId: string) {\n  const message = await relay.outbound.messages.get(messageId);\n  for (const delivery of message.deliveries ?? []) {\n    console.log(`endpoint ${delivery.output_id}:`);\n    for (const attempt of delivery.attempts ?? []) {\n      console.log(`  #${attempt.attempt_no} ${attempt.status_code ?? \"-\"} ${attempt.outcome ?? \"\"} ${attempt.error ?? \"\"} (${attempt.duration_ms ?? 0} ms)`);\n    }\n  }\n}\n\n// What did one endpoint receive? Filter by status, event type or message.\nexport async function failedDeliveries(endpointId: string) {\n  return relay.outbound.endpoints.deliveries(endpointId, { status: \"failed\", limit: 20 });\n}\n",[2488],{"type":373,"tag":385,"props":2489,"children":2490},{"__ignoreMap":345},[2491,2499,2522,2529,2570,2604,2646,2691,2729,2867,2874,2881,2888,2895,2903,2944,2985],{"type":373,"tag":477,"props":2492,"children":2493},{"class":479,"line":480},[2494],{"type":373,"tag":477,"props":2495,"children":2496},{"style":835},[2497],{"type":382,"value":2498},"// inspect.ts\n",{"type":373,"tag":477,"props":2500,"children":2501},{"class":479,"line":489},[2502,2506,2510,2514,2518],{"type":373,"tag":477,"props":2503,"children":2504},{"style":730},[2505],{"type":382,"value":846},{"type":373,"tag":477,"props":2507,"children":2508},{"style":736},[2509],{"type":382,"value":1006},{"type":373,"tag":477,"props":2511,"children":2512},{"style":730},[2513],{"type":382,"value":856},{"type":373,"tag":477,"props":2515,"children":2516},{"style":680},[2517],{"type":382,"value":1015},{"type":373,"tag":477,"props":2519,"children":2520},{"style":736},[2521],{"type":382,"value":866},{"type":373,"tag":477,"props":2523,"children":2524},{"class":479,"line":498},[2525],{"type":373,"tag":477,"props":2526,"children":2527},{"emptyLinePlaceholder":721},[2528],{"type":382,"value":724},{"type":373,"tag":477,"props":2530,"children":2531},{"class":479,"line":507},[2532,2536,2540,2544,2549,2553,2558,2562,2566],{"type":373,"tag":477,"props":2533,"children":2534},{"style":730},[2535],{"type":382,"value":733},{"type":373,"tag":477,"props":2537,"children":2538},{"style":730},[2539],{"type":382,"value":1038},{"type":373,"tag":477,"props":2541,"children":2542},{"style":730},[2543],{"type":382,"value":1043},{"type":373,"tag":477,"props":2545,"children":2546},{"style":674},[2547],{"type":382,"value":2548}," showMessage",{"type":373,"tag":477,"props":2550,"children":2551},{"style":736},[2552],{"type":382,"value":1075},{"type":373,"tag":477,"props":2554,"children":2555},{"style":1382},[2556],{"type":382,"value":2557},"messageId",{"type":373,"tag":477,"props":2559,"children":2560},{"style":730},[2561],{"type":382,"value":1390},{"type":373,"tag":477,"props":2563,"children":2564},{"style":702},[2565],{"type":382,"value":1409},{"type":373,"tag":477,"props":2567,"children":2568},{"style":736},[2569],{"type":382,"value":1450},{"type":373,"tag":477,"props":2571,"children":2572},{"class":479,"line":516},[2573,2577,2582,2586,2590,2594,2599],{"type":373,"tag":477,"props":2574,"children":2575},{"style":730},[2576],{"type":382,"value":1494},{"type":373,"tag":477,"props":2578,"children":2579},{"style":702},[2580],{"type":382,"value":2581}," message",{"type":373,"tag":477,"props":2583,"children":2584},{"style":730},[2585],{"type":382,"value":895},{"type":373,"tag":477,"props":2587,"children":2588},{"style":730},[2589],{"type":382,"value":1508},{"type":373,"tag":477,"props":2591,"children":2592},{"style":736},[2593],{"type":382,"value":1951},{"type":373,"tag":477,"props":2595,"children":2596},{"style":674},[2597],{"type":382,"value":2598},"get",{"type":373,"tag":477,"props":2600,"children":2601},{"style":736},[2602],{"type":382,"value":2603},"(messageId);\n",{"type":373,"tag":477,"props":2605,"children":2606},{"class":479,"line":525},[2607,2612,2616,2621,2626,2631,2636,2641],{"type":373,"tag":477,"props":2608,"children":2609},{"style":730},[2610],{"type":382,"value":2611},"  for",{"type":373,"tag":477,"props":2613,"children":2614},{"style":736},[2615],{"type":382,"value":601},{"type":373,"tag":477,"props":2617,"children":2618},{"style":730},[2619],{"type":382,"value":2620},"const",{"type":373,"tag":477,"props":2622,"children":2623},{"style":702},[2624],{"type":382,"value":2625}," delivery",{"type":373,"tag":477,"props":2627,"children":2628},{"style":730},[2629],{"type":382,"value":2630}," of",{"type":373,"tag":477,"props":2632,"children":2633},{"style":736},[2634],{"type":382,"value":2635}," message.deliveries ",{"type":373,"tag":477,"props":2637,"children":2638},{"style":730},[2639],{"type":382,"value":2640},"??",{"type":373,"tag":477,"props":2642,"children":2643},{"style":736},[2644],{"type":382,"value":2645}," []) {\n",{"type":373,"tag":477,"props":2647,"children":2648},{"class":479,"line":946},[2649,2654,2659,2663,2668,2673,2677,2682,2687],{"type":373,"tag":477,"props":2650,"children":2651},{"style":736},[2652],{"type":382,"value":2653},"    console.",{"type":373,"tag":477,"props":2655,"children":2656},{"style":674},[2657],{"type":382,"value":2658},"log",{"type":373,"tag":477,"props":2660,"children":2661},{"style":736},[2662],{"type":382,"value":1075},{"type":373,"tag":477,"props":2664,"children":2665},{"style":680},[2666],{"type":382,"value":2667},"`endpoint ${",{"type":373,"tag":477,"props":2669,"children":2670},{"style":736},[2671],{"type":382,"value":2672},"delivery",{"type":373,"tag":477,"props":2674,"children":2675},{"style":680},[2676],{"type":382,"value":2014},{"type":373,"tag":477,"props":2678,"children":2679},{"style":736},[2680],{"type":382,"value":2681},"output_id",{"type":373,"tag":477,"props":2683,"children":2684},{"style":680},[2685],{"type":382,"value":2686},"}:`",{"type":373,"tag":477,"props":2688,"children":2689},{"style":736},[2690],{"type":382,"value":2329},{"type":373,"tag":477,"props":2692,"children":2693},{"class":479,"line":1153},[2694,2699,2703,2707,2712,2716,2721,2725],{"type":373,"tag":477,"props":2695,"children":2696},{"style":730},[2697],{"type":382,"value":2698},"    for",{"type":373,"tag":477,"props":2700,"children":2701},{"style":736},[2702],{"type":382,"value":601},{"type":373,"tag":477,"props":2704,"children":2705},{"style":730},[2706],{"type":382,"value":2620},{"type":373,"tag":477,"props":2708,"children":2709},{"style":702},[2710],{"type":382,"value":2711}," attempt",{"type":373,"tag":477,"props":2713,"children":2714},{"style":730},[2715],{"type":382,"value":2630},{"type":373,"tag":477,"props":2717,"children":2718},{"style":736},[2719],{"type":382,"value":2720}," delivery.attempts ",{"type":373,"tag":477,"props":2722,"children":2723},{"style":730},[2724],{"type":382,"value":2640},{"type":373,"tag":477,"props":2726,"children":2727},{"style":736},[2728],{"type":382,"value":2645},{"type":373,"tag":477,"props":2730,"children":2731},{"class":479,"line":1162},[2732,2737,2741,2745,2750,2755,2759,2764,2769,2773,2777,2782,2787,2792,2796,2800,2805,2809,2814,2818,2822,2827,2831,2836,2840,2844,2849,2853,2858,2863],{"type":373,"tag":477,"props":2733,"children":2734},{"style":736},[2735],{"type":382,"value":2736},"      console.",{"type":373,"tag":477,"props":2738,"children":2739},{"style":674},[2740],{"type":382,"value":2658},{"type":373,"tag":477,"props":2742,"children":2743},{"style":736},[2744],{"type":382,"value":1075},{"type":373,"tag":477,"props":2746,"children":2747},{"style":680},[2748],{"type":382,"value":2749},"`  #${",{"type":373,"tag":477,"props":2751,"children":2752},{"style":736},[2753],{"type":382,"value":2754},"attempt",{"type":373,"tag":477,"props":2756,"children":2757},{"style":680},[2758],{"type":382,"value":2014},{"type":373,"tag":477,"props":2760,"children":2761},{"style":736},[2762],{"type":382,"value":2763},"attempt_no",{"type":373,"tag":477,"props":2765,"children":2766},{"style":680},[2767],{"type":382,"value":2768},"} ${",{"type":373,"tag":477,"props":2770,"children":2771},{"style":736},[2772],{"type":382,"value":2754},{"type":373,"tag":477,"props":2774,"children":2775},{"style":680},[2776],{"type":382,"value":2014},{"type":373,"tag":477,"props":2778,"children":2779},{"style":736},[2780],{"type":382,"value":2781},"status_code",{"type":373,"tag":477,"props":2783,"children":2784},{"style":730},[2785],{"type":382,"value":2786}," ??",{"type":373,"tag":477,"props":2788,"children":2789},{"style":680},[2790],{"type":382,"value":2791}," \"-\"} ${",{"type":373,"tag":477,"props":2793,"children":2794},{"style":736},[2795],{"type":382,"value":2754},{"type":373,"tag":477,"props":2797,"children":2798},{"style":680},[2799],{"type":382,"value":2014},{"type":373,"tag":477,"props":2801,"children":2802},{"style":736},[2803],{"type":382,"value":2804},"outcome",{"type":373,"tag":477,"props":2806,"children":2807},{"style":730},[2808],{"type":382,"value":2786},{"type":373,"tag":477,"props":2810,"children":2811},{"style":680},[2812],{"type":382,"value":2813}," \"\"} ${",{"type":373,"tag":477,"props":2815,"children":2816},{"style":736},[2817],{"type":382,"value":2754},{"type":373,"tag":477,"props":2819,"children":2820},{"style":680},[2821],{"type":382,"value":2014},{"type":373,"tag":477,"props":2823,"children":2824},{"style":736},[2825],{"type":382,"value":2826},"error",{"type":373,"tag":477,"props":2828,"children":2829},{"style":730},[2830],{"type":382,"value":2786},{"type":373,"tag":477,"props":2832,"children":2833},{"style":680},[2834],{"type":382,"value":2835}," \"\"} (${",{"type":373,"tag":477,"props":2837,"children":2838},{"style":736},[2839],{"type":382,"value":2754},{"type":373,"tag":477,"props":2841,"children":2842},{"style":680},[2843],{"type":382,"value":2014},{"type":373,"tag":477,"props":2845,"children":2846},{"style":736},[2847],{"type":382,"value":2848},"duration_ms",{"type":373,"tag":477,"props":2850,"children":2851},{"style":730},[2852],{"type":382,"value":2786},{"type":373,"tag":477,"props":2854,"children":2855},{"style":702},[2856],{"type":382,"value":2857}," 0",{"type":373,"tag":477,"props":2859,"children":2860},{"style":680},[2861],{"type":382,"value":2862},"} ms)`",{"type":373,"tag":477,"props":2864,"children":2865},{"style":736},[2866],{"type":382,"value":2329},{"type":373,"tag":477,"props":2868,"children":2869},{"class":479,"line":1191},[2870],{"type":373,"tag":477,"props":2871,"children":2872},{"style":736},[2873],{"type":382,"value":2397},{"type":373,"tag":477,"props":2875,"children":2876},{"class":479,"line":1208},[2877],{"type":373,"tag":477,"props":2878,"children":2879},{"style":736},[2880],{"type":382,"value":2420},{"type":373,"tag":477,"props":2882,"children":2883},{"class":479,"line":1250},[2884],{"type":373,"tag":477,"props":2885,"children":2886},{"style":736},[2887],{"type":382,"value":1264},{"type":373,"tag":477,"props":2889,"children":2890},{"class":479,"line":1258},[2891],{"type":373,"tag":477,"props":2892,"children":2893},{"emptyLinePlaceholder":721},[2894],{"type":382,"value":724},{"type":373,"tag":477,"props":2896,"children":2897},{"class":479,"line":1620},[2898],{"type":373,"tag":477,"props":2899,"children":2900},{"style":835},[2901],{"type":382,"value":2902},"// What did one endpoint receive? Filter by status, event type or message.\n",{"type":373,"tag":477,"props":2904,"children":2905},{"class":479,"line":1628},[2906,2910,2914,2918,2923,2927,2932,2936,2940],{"type":373,"tag":477,"props":2907,"children":2908},{"style":730},[2909],{"type":382,"value":733},{"type":373,"tag":477,"props":2911,"children":2912},{"style":730},[2913],{"type":382,"value":1038},{"type":373,"tag":477,"props":2915,"children":2916},{"style":730},[2917],{"type":382,"value":1043},{"type":373,"tag":477,"props":2919,"children":2920},{"style":674},[2921],{"type":382,"value":2922}," failedDeliveries",{"type":373,"tag":477,"props":2924,"children":2925},{"style":736},[2926],{"type":382,"value":1075},{"type":373,"tag":477,"props":2928,"children":2929},{"style":1382},[2930],{"type":382,"value":2931},"endpointId",{"type":373,"tag":477,"props":2933,"children":2934},{"style":730},[2935],{"type":382,"value":1390},{"type":373,"tag":477,"props":2937,"children":2938},{"style":702},[2939],{"type":382,"value":1409},{"type":373,"tag":477,"props":2941,"children":2942},{"style":736},[2943],{"type":382,"value":1450},{"type":373,"tag":477,"props":2945,"children":2946},{"class":479,"line":1636},[2947,2951,2955,2960,2965,2970,2975,2980],{"type":373,"tag":477,"props":2948,"children":2949},{"style":730},[2950],{"type":382,"value":1660},{"type":373,"tag":477,"props":2952,"children":2953},{"style":736},[2954],{"type":382,"value":1513},{"type":373,"tag":477,"props":2956,"children":2957},{"style":674},[2958],{"type":382,"value":2959},"deliveries",{"type":373,"tag":477,"props":2961,"children":2962},{"style":736},[2963],{"type":382,"value":2964},"(endpointId, { status: ",{"type":373,"tag":477,"props":2966,"children":2967},{"style":680},[2968],{"type":382,"value":2969},"\"failed\"",{"type":373,"tag":477,"props":2971,"children":2972},{"style":736},[2973],{"type":382,"value":2974},", limit: ",{"type":373,"tag":477,"props":2976,"children":2977},{"style":702},[2978],{"type":382,"value":2979},"20",{"type":373,"tag":477,"props":2981,"children":2982},{"style":736},[2983],{"type":382,"value":2984}," });\n",{"type":373,"tag":477,"props":2986,"children":2987},{"class":479,"line":1645},[2988],{"type":373,"tag":477,"props":2989,"children":2990},{"style":736},[2991],{"type":382,"value":1264},{"type":373,"tag":374,"props":2993,"children":2994},{},[2995,2997,3003,3005,3011,3013,3019,3021,3027,3029,3035,3037,3043,3045,3051],{"type":382,"value":2996},"Delivery statuses are ",{"type":373,"tag":385,"props":2998,"children":3000},{"className":2999},[],[3001],{"type":382,"value":3002},"received",{"type":382,"value":3004}," (queued), ",{"type":373,"tag":385,"props":3006,"children":3008},{"className":3007},[],[3009],{"type":382,"value":3010},"stalled",{"type":382,"value":3012}," (a retry is scheduled), ",{"type":373,"tag":385,"props":3014,"children":3016},{"className":3015},[],[3017],{"type":382,"value":3018},"sent",{"type":382,"value":3020}," (the endpoint answered ",{"type":373,"tag":385,"props":3022,"children":3024},{"className":3023},[],[3025],{"type":382,"value":3026},"2xx",{"type":382,"value":3028},"), ",{"type":373,"tag":385,"props":3030,"children":3032},{"className":3031},[],[3033],{"type":382,"value":3034},"failed",{"type":382,"value":3036}," (retries ran out or the endpoint answered ",{"type":373,"tag":385,"props":3038,"children":3040},{"className":3039},[],[3041],{"type":382,"value":3042},"410 Gone",{"type":382,"value":3044},") and ",{"type":373,"tag":385,"props":3046,"children":3048},{"className":3047},[],[3049],{"type":382,"value":3050},"rejected",{"type":382,"value":3052}," (skipped while the endpoint was paused or disabled).",{"type":373,"tag":533,"props":3054,"children":3056},{"id":3055},"_6-retry-one-delivery-and-recover-after-an-outage",[3057],{"type":382,"value":3058},"6. Retry one delivery and recover after an outage",{"type":373,"tag":374,"props":3060,"children":3061},{},[3062,3064,3070],{"type":382,"value":3063},"When a customer says \"we missed an event\", re-send it without publishing again. Every copy keeps the original ",{"type":373,"tag":385,"props":3065,"children":3067},{"className":3066},[],[3068],{"type":382,"value":3069},"webhook-id",{"type":382,"value":3071},", so a receiver that deduplicates will not process it twice.",{"type":373,"tag":468,"props":3073,"children":3075},{"className":823,"code":3074,"language":825,"meta":345,"style":345},"// recovery.ts\nimport { relay } from \"./relay.js\";\n\n// One message to one endpoint, now.\nexport async function retryOne(endpointId: string, messageId: string) {\n  const task = await relay.outbound.endpoints.retry(endpointId, messageId);\n  return waitForTask(task.id);\n}\n\n// Everything that exhausted its retries since the customer's outage started.\nexport async function recoverSince(endpointId: string, since: Date) {\n  const task = await relay.outbound.endpoints.recover(endpointId, { since: since.toISOString() });\n  return waitForTask(task.id);\n}\n\n// Messages skipped while the endpoint was paused or disabled: resume first, then replay.\nexport async function resumeAndReplay(endpointId: string, since: Date) {\n  await relay.outbound.endpoints.resume(endpointId);\n  const task = await relay.outbound.endpoints.replayMissing(endpointId, { since: since.toISOString() });\n  return waitForTask(task.id);\n}\n\nasync function waitForTask(taskId: string) {\n  for (;;) {\n    const task = await relay.outbound.recoveryTasks.get(taskId);\n    if (task.status === \"completed\" || task.status === \"failed\") return task;\n    await new Promise((resolve) => setTimeout(resolve, 2000));\n  }\n}\n",[3076],{"type":373,"tag":385,"props":3077,"children":3078},{"__ignoreMap":345},[3079,3087,3110,3117,3125,3181,3215,3232,3239,3246,3254,3312,3355,3370,3377,3384,3392,3448,3469,3509,3524,3531,3538,3575,3587,3620,3673,3729,3736],{"type":373,"tag":477,"props":3080,"children":3081},{"class":479,"line":480},[3082],{"type":373,"tag":477,"props":3083,"children":3084},{"style":835},[3085],{"type":382,"value":3086},"// recovery.ts\n",{"type":373,"tag":477,"props":3088,"children":3089},{"class":479,"line":489},[3090,3094,3098,3102,3106],{"type":373,"tag":477,"props":3091,"children":3092},{"style":730},[3093],{"type":382,"value":846},{"type":373,"tag":477,"props":3095,"children":3096},{"style":736},[3097],{"type":382,"value":1006},{"type":373,"tag":477,"props":3099,"children":3100},{"style":730},[3101],{"type":382,"value":856},{"type":373,"tag":477,"props":3103,"children":3104},{"style":680},[3105],{"type":382,"value":1015},{"type":373,"tag":477,"props":3107,"children":3108},{"style":736},[3109],{"type":382,"value":866},{"type":373,"tag":477,"props":3111,"children":3112},{"class":479,"line":498},[3113],{"type":373,"tag":477,"props":3114,"children":3115},{"emptyLinePlaceholder":721},[3116],{"type":382,"value":724},{"type":373,"tag":477,"props":3118,"children":3119},{"class":479,"line":507},[3120],{"type":373,"tag":477,"props":3121,"children":3122},{"style":835},[3123],{"type":382,"value":3124},"// One message to one endpoint, now.\n",{"type":373,"tag":477,"props":3126,"children":3127},{"class":479,"line":516},[3128,3132,3136,3140,3145,3149,3153,3157,3161,3165,3169,3173,3177],{"type":373,"tag":477,"props":3129,"children":3130},{"style":730},[3131],{"type":382,"value":733},{"type":373,"tag":477,"props":3133,"children":3134},{"style":730},[3135],{"type":382,"value":1038},{"type":373,"tag":477,"props":3137,"children":3138},{"style":730},[3139],{"type":382,"value":1043},{"type":373,"tag":477,"props":3141,"children":3142},{"style":674},[3143],{"type":382,"value":3144}," retryOne",{"type":373,"tag":477,"props":3146,"children":3147},{"style":736},[3148],{"type":382,"value":1075},{"type":373,"tag":477,"props":3150,"children":3151},{"style":1382},[3152],{"type":382,"value":2931},{"type":373,"tag":477,"props":3154,"children":3155},{"style":730},[3156],{"type":382,"value":1390},{"type":373,"tag":477,"props":3158,"children":3159},{"style":702},[3160],{"type":382,"value":1409},{"type":373,"tag":477,"props":3162,"children":3163},{"style":736},[3164],{"type":382,"value":443},{"type":373,"tag":477,"props":3166,"children":3167},{"style":1382},[3168],{"type":382,"value":2557},{"type":373,"tag":477,"props":3170,"children":3171},{"style":730},[3172],{"type":382,"value":1390},{"type":373,"tag":477,"props":3174,"children":3175},{"style":702},[3176],{"type":382,"value":1409},{"type":373,"tag":477,"props":3178,"children":3179},{"style":736},[3180],{"type":382,"value":1450},{"type":373,"tag":477,"props":3182,"children":3183},{"class":479,"line":525},[3184,3188,3193,3197,3201,3205,3210],{"type":373,"tag":477,"props":3185,"children":3186},{"style":730},[3187],{"type":382,"value":1494},{"type":373,"tag":477,"props":3189,"children":3190},{"style":702},[3191],{"type":382,"value":3192}," task",{"type":373,"tag":477,"props":3194,"children":3195},{"style":730},[3196],{"type":382,"value":895},{"type":373,"tag":477,"props":3198,"children":3199},{"style":730},[3200],{"type":382,"value":1508},{"type":373,"tag":477,"props":3202,"children":3203},{"style":736},[3204],{"type":382,"value":1513},{"type":373,"tag":477,"props":3206,"children":3207},{"style":674},[3208],{"type":382,"value":3209},"retry",{"type":373,"tag":477,"props":3211,"children":3212},{"style":736},[3213],{"type":382,"value":3214},"(endpointId, messageId);\n",{"type":373,"tag":477,"props":3216,"children":3217},{"class":479,"line":946},[3218,3222,3227],{"type":373,"tag":477,"props":3219,"children":3220},{"style":730},[3221],{"type":382,"value":1660},{"type":373,"tag":477,"props":3223,"children":3224},{"style":674},[3225],{"type":382,"value":3226}," waitForTask",{"type":373,"tag":477,"props":3228,"children":3229},{"style":736},[3230],{"type":382,"value":3231},"(task.id);\n",{"type":373,"tag":477,"props":3233,"children":3234},{"class":479,"line":1153},[3235],{"type":373,"tag":477,"props":3236,"children":3237},{"style":736},[3238],{"type":382,"value":1264},{"type":373,"tag":477,"props":3240,"children":3241},{"class":479,"line":1162},[3242],{"type":373,"tag":477,"props":3243,"children":3244},{"emptyLinePlaceholder":721},[3245],{"type":382,"value":724},{"type":373,"tag":477,"props":3247,"children":3248},{"class":479,"line":1191},[3249],{"type":373,"tag":477,"props":3250,"children":3251},{"style":835},[3252],{"type":382,"value":3253},"// Everything that exhausted its retries since the customer's outage started.\n",{"type":373,"tag":477,"props":3255,"children":3256},{"class":479,"line":1208},[3257,3261,3265,3269,3274,3278,3282,3286,3290,3294,3299,3303,3308],{"type":373,"tag":477,"props":3258,"children":3259},{"style":730},[3260],{"type":382,"value":733},{"type":373,"tag":477,"props":3262,"children":3263},{"style":730},[3264],{"type":382,"value":1038},{"type":373,"tag":477,"props":3266,"children":3267},{"style":730},[3268],{"type":382,"value":1043},{"type":373,"tag":477,"props":3270,"children":3271},{"style":674},[3272],{"type":382,"value":3273}," recoverSince",{"type":373,"tag":477,"props":3275,"children":3276},{"style":736},[3277],{"type":382,"value":1075},{"type":373,"tag":477,"props":3279,"children":3280},{"style":1382},[3281],{"type":382,"value":2931},{"type":373,"tag":477,"props":3283,"children":3284},{"style":730},[3285],{"type":382,"value":1390},{"type":373,"tag":477,"props":3287,"children":3288},{"style":702},[3289],{"type":382,"value":1409},{"type":373,"tag":477,"props":3291,"children":3292},{"style":736},[3293],{"type":382,"value":443},{"type":373,"tag":477,"props":3295,"children":3296},{"style":1382},[3297],{"type":382,"value":3298},"since",{"type":373,"tag":477,"props":3300,"children":3301},{"style":730},[3302],{"type":382,"value":1390},{"type":373,"tag":477,"props":3304,"children":3305},{"style":674},[3306],{"type":382,"value":3307}," Date",{"type":373,"tag":477,"props":3309,"children":3310},{"style":736},[3311],{"type":382,"value":1450},{"type":373,"tag":477,"props":3313,"children":3314},{"class":479,"line":1250},[3315,3319,3323,3327,3331,3335,3340,3345,3350],{"type":373,"tag":477,"props":3316,"children":3317},{"style":730},[3318],{"type":382,"value":1494},{"type":373,"tag":477,"props":3320,"children":3321},{"style":702},[3322],{"type":382,"value":3192},{"type":373,"tag":477,"props":3324,"children":3325},{"style":730},[3326],{"type":382,"value":895},{"type":373,"tag":477,"props":3328,"children":3329},{"style":730},[3330],{"type":382,"value":1508},{"type":373,"tag":477,"props":3332,"children":3333},{"style":736},[3334],{"type":382,"value":1513},{"type":373,"tag":477,"props":3336,"children":3337},{"style":674},[3338],{"type":382,"value":3339},"recover",{"type":373,"tag":477,"props":3341,"children":3342},{"style":736},[3343],{"type":382,"value":3344},"(endpointId, { since: since.",{"type":373,"tag":477,"props":3346,"children":3347},{"style":674},[3348],{"type":382,"value":3349},"toISOString",{"type":373,"tag":477,"props":3351,"children":3352},{"style":736},[3353],{"type":382,"value":3354},"() });\n",{"type":373,"tag":477,"props":3356,"children":3357},{"class":479,"line":1258},[3358,3362,3366],{"type":373,"tag":477,"props":3359,"children":3360},{"style":730},[3361],{"type":382,"value":1660},{"type":373,"tag":477,"props":3363,"children":3364},{"style":674},[3365],{"type":382,"value":3226},{"type":373,"tag":477,"props":3367,"children":3368},{"style":736},[3369],{"type":382,"value":3231},{"type":373,"tag":477,"props":3371,"children":3372},{"class":479,"line":1620},[3373],{"type":373,"tag":477,"props":3374,"children":3375},{"style":736},[3376],{"type":382,"value":1264},{"type":373,"tag":477,"props":3378,"children":3379},{"class":479,"line":1628},[3380],{"type":373,"tag":477,"props":3381,"children":3382},{"emptyLinePlaceholder":721},[3383],{"type":382,"value":724},{"type":373,"tag":477,"props":3385,"children":3386},{"class":479,"line":1636},[3387],{"type":373,"tag":477,"props":3388,"children":3389},{"style":835},[3390],{"type":382,"value":3391},"// Messages skipped while the endpoint was paused or disabled: resume first, then replay.\n",{"type":373,"tag":477,"props":3393,"children":3394},{"class":479,"line":1645},[3395,3399,3403,3407,3412,3416,3420,3424,3428,3432,3436,3440,3444],{"type":373,"tag":477,"props":3396,"children":3397},{"style":730},[3398],{"type":382,"value":733},{"type":373,"tag":477,"props":3400,"children":3401},{"style":730},[3402],{"type":382,"value":1038},{"type":373,"tag":477,"props":3404,"children":3405},{"style":730},[3406],{"type":382,"value":1043},{"type":373,"tag":477,"props":3408,"children":3409},{"style":674},[3410],{"type":382,"value":3411}," resumeAndReplay",{"type":373,"tag":477,"props":3413,"children":3414},{"style":736},[3415],{"type":382,"value":1075},{"type":373,"tag":477,"props":3417,"children":3418},{"style":1382},[3419],{"type":382,"value":2931},{"type":373,"tag":477,"props":3421,"children":3422},{"style":730},[3423],{"type":382,"value":1390},{"type":373,"tag":477,"props":3425,"children":3426},{"style":702},[3427],{"type":382,"value":1409},{"type":373,"tag":477,"props":3429,"children":3430},{"style":736},[3431],{"type":382,"value":443},{"type":373,"tag":477,"props":3433,"children":3434},{"style":1382},[3435],{"type":382,"value":3298},{"type":373,"tag":477,"props":3437,"children":3438},{"style":730},[3439],{"type":382,"value":1390},{"type":373,"tag":477,"props":3441,"children":3442},{"style":674},[3443],{"type":382,"value":3307},{"type":373,"tag":477,"props":3445,"children":3446},{"style":736},[3447],{"type":382,"value":1450},{"type":373,"tag":477,"props":3449,"children":3450},{"class":479,"line":1654},[3451,3455,3459,3464],{"type":373,"tag":477,"props":3452,"children":3453},{"style":730},[3454],{"type":382,"value":1061},{"type":373,"tag":477,"props":3456,"children":3457},{"style":736},[3458],{"type":382,"value":1513},{"type":373,"tag":477,"props":3460,"children":3461},{"style":674},[3462],{"type":382,"value":3463},"resume",{"type":373,"tag":477,"props":3465,"children":3466},{"style":736},[3467],{"type":382,"value":3468},"(endpointId);\n",{"type":373,"tag":477,"props":3470,"children":3471},{"class":479,"line":1668},[3472,3476,3480,3484,3488,3492,3497,3501,3505],{"type":373,"tag":477,"props":3473,"children":3474},{"style":730},[3475],{"type":382,"value":1494},{"type":373,"tag":477,"props":3477,"children":3478},{"style":702},[3479],{"type":382,"value":3192},{"type":373,"tag":477,"props":3481,"children":3482},{"style":730},[3483],{"type":382,"value":895},{"type":373,"tag":477,"props":3485,"children":3486},{"style":730},[3487],{"type":382,"value":1508},{"type":373,"tag":477,"props":3489,"children":3490},{"style":736},[3491],{"type":382,"value":1513},{"type":373,"tag":477,"props":3493,"children":3494},{"style":674},[3495],{"type":382,"value":3496},"replayMissing",{"type":373,"tag":477,"props":3498,"children":3499},{"style":736},[3500],{"type":382,"value":3344},{"type":373,"tag":477,"props":3502,"children":3503},{"style":674},[3504],{"type":382,"value":3349},{"type":373,"tag":477,"props":3506,"children":3507},{"style":736},[3508],{"type":382,"value":3354},{"type":373,"tag":477,"props":3510,"children":3511},{"class":479,"line":2083},[3512,3516,3520],{"type":373,"tag":477,"props":3513,"children":3514},{"style":730},[3515],{"type":382,"value":1660},{"type":373,"tag":477,"props":3517,"children":3518},{"style":674},[3519],{"type":382,"value":3226},{"type":373,"tag":477,"props":3521,"children":3522},{"style":736},[3523],{"type":382,"value":3231},{"type":373,"tag":477,"props":3525,"children":3526},{"class":479,"line":2092},[3527],{"type":373,"tag":477,"props":3528,"children":3529},{"style":736},[3530],{"type":382,"value":1264},{"type":373,"tag":477,"props":3532,"children":3533},{"class":479,"line":2126},[3534],{"type":373,"tag":477,"props":3535,"children":3536},{"emptyLinePlaceholder":721},[3537],{"type":382,"value":724},{"type":373,"tag":477,"props":3539,"children":3540},{"class":479,"line":2135},[3541,3546,3550,3554,3558,3563,3567,3571],{"type":373,"tag":477,"props":3542,"children":3543},{"style":730},[3544],{"type":382,"value":3545},"async",{"type":373,"tag":477,"props":3547,"children":3548},{"style":730},[3549],{"type":382,"value":1043},{"type":373,"tag":477,"props":3551,"children":3552},{"style":674},[3553],{"type":382,"value":3226},{"type":373,"tag":477,"props":3555,"children":3556},{"style":736},[3557],{"type":382,"value":1075},{"type":373,"tag":477,"props":3559,"children":3560},{"style":1382},[3561],{"type":382,"value":3562},"taskId",{"type":373,"tag":477,"props":3564,"children":3565},{"style":730},[3566],{"type":382,"value":1390},{"type":373,"tag":477,"props":3568,"children":3569},{"style":702},[3570],{"type":382,"value":1409},{"type":373,"tag":477,"props":3572,"children":3573},{"style":736},[3574],{"type":382,"value":1450},{"type":373,"tag":477,"props":3576,"children":3577},{"class":479,"line":2144},[3578,3582],{"type":373,"tag":477,"props":3579,"children":3580},{"style":730},[3581],{"type":382,"value":2611},{"type":373,"tag":477,"props":3583,"children":3584},{"style":736},[3585],{"type":382,"value":3586}," (;;) {\n",{"type":373,"tag":477,"props":3588,"children":3589},{"class":479,"line":2153},[3590,3594,3598,3602,3606,3611,3615],{"type":373,"tag":477,"props":3591,"children":3592},{"style":730},[3593],{"type":382,"value":1933},{"type":373,"tag":477,"props":3595,"children":3596},{"style":702},[3597],{"type":382,"value":3192},{"type":373,"tag":477,"props":3599,"children":3600},{"style":730},[3601],{"type":382,"value":895},{"type":373,"tag":477,"props":3603,"children":3604},{"style":730},[3605],{"type":382,"value":1508},{"type":373,"tag":477,"props":3607,"children":3608},{"style":736},[3609],{"type":382,"value":3610}," relay.outbound.recoveryTasks.",{"type":373,"tag":477,"props":3612,"children":3613},{"style":674},[3614],{"type":382,"value":2598},{"type":373,"tag":477,"props":3616,"children":3617},{"style":736},[3618],{"type":382,"value":3619},"(taskId);\n",{"type":373,"tag":477,"props":3621,"children":3622},{"class":479,"line":2167},[3623,3627,3632,3636,3641,3646,3651,3655,3660,3664,3668],{"type":373,"tag":477,"props":3624,"children":3625},{"style":730},[3626],{"type":382,"value":2192},{"type":373,"tag":477,"props":3628,"children":3629},{"style":736},[3630],{"type":382,"value":3631}," (task.status ",{"type":373,"tag":477,"props":3633,"children":3634},{"style":730},[3635],{"type":382,"value":2230},{"type":373,"tag":477,"props":3637,"children":3638},{"style":680},[3639],{"type":382,"value":3640}," \"completed\"",{"type":373,"tag":477,"props":3642,"children":3643},{"style":730},[3644],{"type":382,"value":3645}," ||",{"type":373,"tag":477,"props":3647,"children":3648},{"style":736},[3649],{"type":382,"value":3650}," task.status ",{"type":373,"tag":477,"props":3652,"children":3653},{"style":730},[3654],{"type":382,"value":2230},{"type":373,"tag":477,"props":3656,"children":3657},{"style":680},[3658],{"type":382,"value":3659}," \"failed\"",{"type":373,"tag":477,"props":3661,"children":3662},{"style":736},[3663],{"type":382,"value":2240},{"type":373,"tag":477,"props":3665,"children":3666},{"style":730},[3667],{"type":382,"value":2245},{"type":373,"tag":477,"props":3669,"children":3670},{"style":736},[3671],{"type":382,"value":3672}," task;\n",{"type":373,"tag":477,"props":3674,"children":3675},{"class":479,"line":2186},[3676,3681,3685,3690,3695,3700,3704,3709,3714,3719,3724],{"type":373,"tag":477,"props":3677,"children":3678},{"style":730},[3679],{"type":382,"value":3680},"    await",{"type":373,"tag":477,"props":3682,"children":3683},{"style":730},[3684],{"type":382,"value":900},{"type":373,"tag":477,"props":3686,"children":3687},{"style":702},[3688],{"type":382,"value":3689}," Promise",{"type":373,"tag":477,"props":3691,"children":3692},{"style":736},[3693],{"type":382,"value":3694},"((",{"type":373,"tag":477,"props":3696,"children":3697},{"style":1382},[3698],{"type":382,"value":3699},"resolve",{"type":373,"tag":477,"props":3701,"children":3702},{"style":736},[3703],{"type":382,"value":2240},{"type":373,"tag":477,"props":3705,"children":3706},{"style":730},[3707],{"type":382,"value":3708},"=>",{"type":373,"tag":477,"props":3710,"children":3711},{"style":674},[3712],{"type":382,"value":3713}," setTimeout",{"type":373,"tag":477,"props":3715,"children":3716},{"style":736},[3717],{"type":382,"value":3718},"(resolve, ",{"type":373,"tag":477,"props":3720,"children":3721},{"style":702},[3722],{"type":382,"value":3723},"2000",{"type":373,"tag":477,"props":3725,"children":3726},{"style":736},[3727],{"type":382,"value":3728},"));\n",{"type":373,"tag":477,"props":3730,"children":3731},{"class":479,"line":2214},[3732],{"type":373,"tag":477,"props":3733,"children":3734},{"style":736},[3735],{"type":382,"value":2420},{"type":373,"tag":477,"props":3737,"children":3738},{"class":479,"line":2263},[3739],{"type":373,"tag":477,"props":3740,"children":3741},{"style":736},[3742],{"type":382,"value":1264},{"type":373,"tag":533,"props":3744,"children":3746},{"id":3745},"_7-report-failing-endpoints",[3747],{"type":382,"value":3748},"7. Report failing endpoints",{"type":373,"tag":374,"props":3750,"children":3751},{},[3752,3754,3760],{"type":382,"value":3753},"With dozens of customers, some endpoint is always down. An endpoint becomes ",{"type":373,"tag":385,"props":3755,"children":3757},{"className":3756},[],[3758],{"type":382,"value":3759},"failing",{"type":382,"value":3761}," after 5 failed attempts in a row or one exhausted delivery. Run a report like this from a cron job or your admin dashboard instead of waiting for customers to notice.",{"type":373,"tag":468,"props":3763,"children":3765},{"className":823,"code":3764,"language":825,"meta":345,"style":345},"// health.ts\nimport { relay } from \"./relay.js\";\n\nexport async function failingEndpointReport() {\n  const { endpoints, stats } = await relay.outbound.health();\n  console.log(`24h: ${stats.attempts} attempts, ${stats.failures} failures; failing endpoints: ${endpoints.failing}`);\n  if (endpoints.failing === 0) return [];\n\n  // Longest failing first, across all customers.\n  const failing = await relay.outbound.endpoints.listAll({ state: \"failing\", limit: 20 });\n  return failing.map((e) => ({\n    customer: e.consumer,\n    url: e.url,\n    failingSince: e.failing_since,\n    failures24h: e.stats?.failures ?? 0,\n  }));\n}\n",[3766],{"type":373,"tag":385,"props":3767,"children":3768},{"__ignoreMap":345},[3769,3777,3800,3807,3831,3884,3961,3995,4002,4010,4061,4100,4108,4116,4124,4144,4152],{"type":373,"tag":477,"props":3770,"children":3771},{"class":479,"line":480},[3772],{"type":373,"tag":477,"props":3773,"children":3774},{"style":835},[3775],{"type":382,"value":3776},"// health.ts\n",{"type":373,"tag":477,"props":3778,"children":3779},{"class":479,"line":489},[3780,3784,3788,3792,3796],{"type":373,"tag":477,"props":3781,"children":3782},{"style":730},[3783],{"type":382,"value":846},{"type":373,"tag":477,"props":3785,"children":3786},{"style":736},[3787],{"type":382,"value":1006},{"type":373,"tag":477,"props":3789,"children":3790},{"style":730},[3791],{"type":382,"value":856},{"type":373,"tag":477,"props":3793,"children":3794},{"style":680},[3795],{"type":382,"value":1015},{"type":373,"tag":477,"props":3797,"children":3798},{"style":736},[3799],{"type":382,"value":866},{"type":373,"tag":477,"props":3801,"children":3802},{"class":479,"line":498},[3803],{"type":373,"tag":477,"props":3804,"children":3805},{"emptyLinePlaceholder":721},[3806],{"type":382,"value":724},{"type":373,"tag":477,"props":3808,"children":3809},{"class":479,"line":507},[3810,3814,3818,3822,3827],{"type":373,"tag":477,"props":3811,"children":3812},{"style":730},[3813],{"type":382,"value":733},{"type":373,"tag":477,"props":3815,"children":3816},{"style":730},[3817],{"type":382,"value":1038},{"type":373,"tag":477,"props":3819,"children":3820},{"style":730},[3821],{"type":382,"value":1043},{"type":373,"tag":477,"props":3823,"children":3824},{"style":674},[3825],{"type":382,"value":3826}," failingEndpointReport",{"type":373,"tag":477,"props":3828,"children":3829},{"style":736},[3830],{"type":382,"value":1053},{"type":373,"tag":477,"props":3832,"children":3833},{"class":479,"line":516},[3834,3838,3842,3847,3851,3856,3861,3865,3869,3874,3879],{"type":373,"tag":477,"props":3835,"children":3836},{"style":730},[3837],{"type":382,"value":1494},{"type":373,"tag":477,"props":3839,"children":3840},{"style":736},[3841],{"type":382,"value":1395},{"type":373,"tag":477,"props":3843,"children":3844},{"style":702},[3845],{"type":382,"value":3846},"endpoints",{"type":373,"tag":477,"props":3848,"children":3849},{"style":736},[3850],{"type":382,"value":443},{"type":373,"tag":477,"props":3852,"children":3853},{"style":702},[3854],{"type":382,"value":3855},"stats",{"type":373,"tag":477,"props":3857,"children":3858},{"style":736},[3859],{"type":382,"value":3860}," } ",{"type":373,"tag":477,"props":3862,"children":3863},{"style":730},[3864],{"type":382,"value":744},{"type":373,"tag":477,"props":3866,"children":3867},{"style":730},[3868],{"type":382,"value":1508},{"type":373,"tag":477,"props":3870,"children":3871},{"style":736},[3872],{"type":382,"value":3873}," relay.outbound.",{"type":373,"tag":477,"props":3875,"children":3876},{"style":674},[3877],{"type":382,"value":3878},"health",{"type":373,"tag":477,"props":3880,"children":3881},{"style":736},[3882],{"type":382,"value":3883},"();\n",{"type":373,"tag":477,"props":3885,"children":3886},{"class":479,"line":525},[3887,3892,3896,3900,3905,3909,3913,3918,3923,3927,3931,3936,3941,3945,3949,3953,3957],{"type":373,"tag":477,"props":3888,"children":3889},{"style":736},[3890],{"type":382,"value":3891},"  console.",{"type":373,"tag":477,"props":3893,"children":3894},{"style":674},[3895],{"type":382,"value":2658},{"type":373,"tag":477,"props":3897,"children":3898},{"style":736},[3899],{"type":382,"value":1075},{"type":373,"tag":477,"props":3901,"children":3902},{"style":680},[3903],{"type":382,"value":3904},"`24h: ${",{"type":373,"tag":477,"props":3906,"children":3907},{"style":736},[3908],{"type":382,"value":3855},{"type":373,"tag":477,"props":3910,"children":3911},{"style":680},[3912],{"type":382,"value":2014},{"type":373,"tag":477,"props":3914,"children":3915},{"style":736},[3916],{"type":382,"value":3917},"attempts",{"type":373,"tag":477,"props":3919,"children":3920},{"style":680},[3921],{"type":382,"value":3922},"} attempts, ${",{"type":373,"tag":477,"props":3924,"children":3925},{"style":736},[3926],{"type":382,"value":3855},{"type":373,"tag":477,"props":3928,"children":3929},{"style":680},[3930],{"type":382,"value":2014},{"type":373,"tag":477,"props":3932,"children":3933},{"style":736},[3934],{"type":382,"value":3935},"failures",{"type":373,"tag":477,"props":3937,"children":3938},{"style":680},[3939],{"type":382,"value":3940},"} failures; failing endpoints: ${",{"type":373,"tag":477,"props":3942,"children":3943},{"style":736},[3944],{"type":382,"value":3846},{"type":373,"tag":477,"props":3946,"children":3947},{"style":680},[3948],{"type":382,"value":2014},{"type":373,"tag":477,"props":3950,"children":3951},{"style":736},[3952],{"type":382,"value":3759},{"type":373,"tag":477,"props":3954,"children":3955},{"style":680},[3956],{"type":382,"value":2023},{"type":373,"tag":477,"props":3958,"children":3959},{"style":736},[3960],{"type":382,"value":2329},{"type":373,"tag":477,"props":3962,"children":3963},{"class":479,"line":946},[3964,3969,3974,3978,3982,3986,3990],{"type":373,"tag":477,"props":3965,"children":3966},{"style":730},[3967],{"type":382,"value":3968},"  if",{"type":373,"tag":477,"props":3970,"children":3971},{"style":736},[3972],{"type":382,"value":3973}," (endpoints.failing ",{"type":373,"tag":477,"props":3975,"children":3976},{"style":730},[3977],{"type":382,"value":2230},{"type":373,"tag":477,"props":3979,"children":3980},{"style":702},[3981],{"type":382,"value":2857},{"type":373,"tag":477,"props":3983,"children":3984},{"style":736},[3985],{"type":382,"value":2240},{"type":373,"tag":477,"props":3987,"children":3988},{"style":730},[3989],{"type":382,"value":2245},{"type":373,"tag":477,"props":3991,"children":3992},{"style":736},[3993],{"type":382,"value":3994}," [];\n",{"type":373,"tag":477,"props":3996,"children":3997},{"class":479,"line":1153},[3998],{"type":373,"tag":477,"props":3999,"children":4000},{"emptyLinePlaceholder":721},[4001],{"type":382,"value":724},{"type":373,"tag":477,"props":4003,"children":4004},{"class":479,"line":1162},[4005],{"type":373,"tag":477,"props":4006,"children":4007},{"style":835},[4008],{"type":382,"value":4009},"  // Longest failing first, across all customers.\n",{"type":373,"tag":477,"props":4011,"children":4012},{"class":479,"line":1191},[4013,4017,4022,4026,4030,4034,4039,4044,4049,4053,4057],{"type":373,"tag":477,"props":4014,"children":4015},{"style":730},[4016],{"type":382,"value":1494},{"type":373,"tag":477,"props":4018,"children":4019},{"style":702},[4020],{"type":382,"value":4021}," failing",{"type":373,"tag":477,"props":4023,"children":4024},{"style":730},[4025],{"type":382,"value":895},{"type":373,"tag":477,"props":4027,"children":4028},{"style":730},[4029],{"type":382,"value":1508},{"type":373,"tag":477,"props":4031,"children":4032},{"style":736},[4033],{"type":382,"value":1513},{"type":373,"tag":477,"props":4035,"children":4036},{"style":674},[4037],{"type":382,"value":4038},"listAll",{"type":373,"tag":477,"props":4040,"children":4041},{"style":736},[4042],{"type":382,"value":4043},"({ state: ",{"type":373,"tag":477,"props":4045,"children":4046},{"style":680},[4047],{"type":382,"value":4048},"\"failing\"",{"type":373,"tag":477,"props":4050,"children":4051},{"style":736},[4052],{"type":382,"value":2974},{"type":373,"tag":477,"props":4054,"children":4055},{"style":702},[4056],{"type":382,"value":2979},{"type":373,"tag":477,"props":4058,"children":4059},{"style":736},[4060],{"type":382,"value":2984},{"type":373,"tag":477,"props":4062,"children":4063},{"class":479,"line":1208},[4064,4068,4073,4078,4082,4087,4091,4095],{"type":373,"tag":477,"props":4065,"children":4066},{"style":730},[4067],{"type":382,"value":1660},{"type":373,"tag":477,"props":4069,"children":4070},{"style":736},[4071],{"type":382,"value":4072}," failing.",{"type":373,"tag":477,"props":4074,"children":4075},{"style":674},[4076],{"type":382,"value":4077},"map",{"type":373,"tag":477,"props":4079,"children":4080},{"style":736},[4081],{"type":382,"value":3694},{"type":373,"tag":477,"props":4083,"children":4084},{"style":1382},[4085],{"type":382,"value":4086},"e",{"type":373,"tag":477,"props":4088,"children":4089},{"style":736},[4090],{"type":382,"value":2240},{"type":373,"tag":477,"props":4092,"children":4093},{"style":730},[4094],{"type":382,"value":3708},{"type":373,"tag":477,"props":4096,"children":4097},{"style":736},[4098],{"type":382,"value":4099}," ({\n",{"type":373,"tag":477,"props":4101,"children":4102},{"class":479,"line":1250},[4103],{"type":373,"tag":477,"props":4104,"children":4105},{"style":736},[4106],{"type":382,"value":4107},"    customer: e.consumer,\n",{"type":373,"tag":477,"props":4109,"children":4110},{"class":479,"line":1258},[4111],{"type":373,"tag":477,"props":4112,"children":4113},{"style":736},[4114],{"type":382,"value":4115},"    url: e.url,\n",{"type":373,"tag":477,"props":4117,"children":4118},{"class":479,"line":1620},[4119],{"type":373,"tag":477,"props":4120,"children":4121},{"style":736},[4122],{"type":382,"value":4123},"    failingSince: e.failing_since,\n",{"type":373,"tag":477,"props":4125,"children":4126},{"class":479,"line":1628},[4127,4132,4136,4140],{"type":373,"tag":477,"props":4128,"children":4129},{"style":736},[4130],{"type":382,"value":4131},"    failures24h: e.stats?.failures ",{"type":373,"tag":477,"props":4133,"children":4134},{"style":730},[4135],{"type":382,"value":2640},{"type":373,"tag":477,"props":4137,"children":4138},{"style":702},[4139],{"type":382,"value":2857},{"type":373,"tag":477,"props":4141,"children":4142},{"style":736},[4143],{"type":382,"value":927},{"type":373,"tag":477,"props":4145,"children":4146},{"class":479,"line":1636},[4147],{"type":373,"tag":477,"props":4148,"children":4149},{"style":736},[4150],{"type":382,"value":4151},"  }));\n",{"type":373,"tag":477,"props":4153,"children":4154},{"class":479,"line":1645},[4155],{"type":373,"tag":477,"props":4156,"children":4157},{"style":736},[4158],{"type":382,"value":1264},{"type":373,"tag":533,"props":4160,"children":4162},{"id":4161},"_8-rotate-a-customers-signing-secret",[4163],{"type":382,"value":4164},"8. Rotate a customer's signing secret",{"type":373,"tag":374,"props":4166,"children":4167},{},[4168,4174,4176,4182],{"type":373,"tag":385,"props":4169,"children":4171},{"className":4170},[],[4172],{"type":382,"value":4173},"rotateSecret",{"type":382,"value":4175}," returns a new ",{"type":373,"tag":385,"props":4177,"children":4179},{"className":4178},[],[4180],{"type":382,"value":4181},"whsec_",{"type":382,"value":4183}," secret. For the next 24 hours every delivery carries two signatures, one per secret, so the customer can switch keys without dropping a webhook.",{"type":373,"tag":468,"props":4185,"children":4187},{"className":823,"code":4186,"language":825,"meta":345,"style":345},"const newSecret = await relay.outbound.endpoints.rotateSecret(endpointId);\n",[4188],{"type":373,"tag":385,"props":4189,"children":4190},{"__ignoreMap":345},[4191],{"type":373,"tag":477,"props":4192,"children":4193},{"class":479,"line":480},[4194,4198,4203,4207,4211,4215,4219],{"type":373,"tag":477,"props":4195,"children":4196},{"style":730},[4197],{"type":382,"value":2620},{"type":373,"tag":477,"props":4199,"children":4200},{"style":702},[4201],{"type":382,"value":4202}," newSecret",{"type":373,"tag":477,"props":4204,"children":4205},{"style":730},[4206],{"type":382,"value":895},{"type":373,"tag":477,"props":4208,"children":4209},{"style":730},[4210],{"type":382,"value":1508},{"type":373,"tag":477,"props":4212,"children":4213},{"style":736},[4214],{"type":382,"value":1513},{"type":373,"tag":477,"props":4216,"children":4217},{"style":674},[4218],{"type":382,"value":4173},{"type":373,"tag":477,"props":4220,"children":4221},{"style":736},[4222],{"type":382,"value":3468},{"type":373,"tag":533,"props":4224,"children":4226},{"id":4225},"run-it-end-to-end",[4227],{"type":382,"value":4228},"Run it end to end",{"type":373,"tag":374,"props":4230,"children":4231},{},[4232],{"type":382,"value":4233},"Put the pieces together in one script and run it against your Webhook Bin URL:",{"type":373,"tag":468,"props":4235,"children":4237},{"className":823,"code":4236,"language":825,"meta":345,"style":345},"// main.ts\nimport { relay } from \"./relay.js\";\nimport { syncEventCatalog } from \"./catalog.js\";\nimport { addCustomerEndpoint } from \"./onboarding.js\";\nimport { onInvoicePaid } from \"./billing.js\";\nimport { showMessage } from \"./inspect.js\";\nimport { failingEndpointReport } from \"./health.js\";\n\nconst url = process.env.CUSTOMER_WEBHOOK_URL;\nif (!url) throw new Error(\"set CUSTOMER_WEBHOOK_URL\");\n\nawait syncEventCatalog();\n\nconst customer = { id: \"customer_42\", name: \"Acme\" };\nconst existing = await relay.outbound.endpoints.list(customer.id).catch(() => []);\nif (!existing.some((e) => e.url === url)) {\n  const { endpointId, signingSecret } = await addCustomerEndpoint(customer, url);\n  console.log(\"endpoint\", endpointId, \"secret\", signingSecret);\n}\n\nconst receipt = await onInvoicePaid({ id: \"inv_123\", customerId: customer.id, amount: 4900, currency: \"usd\" });\nconsole.log(\"published\", receipt?.id, \"to\", receipt?.endpoint_ids.length, \"endpoint(s)\");\n\nawait new Promise((resolve) => setTimeout(resolve, 3000));\nif (receipt) await showMessage(receipt.id);\nconsole.log(await failingEndpointReport());\n",[4238],{"type":373,"tag":385,"props":4239,"children":4240},{"__ignoreMap":345},[4241,4249,4272,4297,4322,4347,4372,4397,4404,4434,4481,4488,4504,4511,4550,4602,4657,4702,4737,4744,4751,4804,4858,4865,4913,4938],{"type":373,"tag":477,"props":4242,"children":4243},{"class":479,"line":480},[4244],{"type":373,"tag":477,"props":4245,"children":4246},{"style":835},[4247],{"type":382,"value":4248},"// main.ts\n",{"type":373,"tag":477,"props":4250,"children":4251},{"class":479,"line":489},[4252,4256,4260,4264,4268],{"type":373,"tag":477,"props":4253,"children":4254},{"style":730},[4255],{"type":382,"value":846},{"type":373,"tag":477,"props":4257,"children":4258},{"style":736},[4259],{"type":382,"value":1006},{"type":373,"tag":477,"props":4261,"children":4262},{"style":730},[4263],{"type":382,"value":856},{"type":373,"tag":477,"props":4265,"children":4266},{"style":680},[4267],{"type":382,"value":1015},{"type":373,"tag":477,"props":4269,"children":4270},{"style":736},[4271],{"type":382,"value":866},{"type":373,"tag":477,"props":4273,"children":4274},{"class":479,"line":498},[4275,4279,4284,4288,4293],{"type":373,"tag":477,"props":4276,"children":4277},{"style":730},[4278],{"type":382,"value":846},{"type":373,"tag":477,"props":4280,"children":4281},{"style":736},[4282],{"type":382,"value":4283}," { syncEventCatalog } ",{"type":373,"tag":477,"props":4285,"children":4286},{"style":730},[4287],{"type":382,"value":856},{"type":373,"tag":477,"props":4289,"children":4290},{"style":680},[4291],{"type":382,"value":4292}," \"./catalog.js\"",{"type":373,"tag":477,"props":4294,"children":4295},{"style":736},[4296],{"type":382,"value":866},{"type":373,"tag":477,"props":4298,"children":4299},{"class":479,"line":507},[4300,4304,4309,4313,4318],{"type":373,"tag":477,"props":4301,"children":4302},{"style":730},[4303],{"type":382,"value":846},{"type":373,"tag":477,"props":4305,"children":4306},{"style":736},[4307],{"type":382,"value":4308}," { addCustomerEndpoint } ",{"type":373,"tag":477,"props":4310,"children":4311},{"style":730},[4312],{"type":382,"value":856},{"type":373,"tag":477,"props":4314,"children":4315},{"style":680},[4316],{"type":382,"value":4317}," \"./onboarding.js\"",{"type":373,"tag":477,"props":4319,"children":4320},{"style":736},[4321],{"type":382,"value":866},{"type":373,"tag":477,"props":4323,"children":4324},{"class":479,"line":516},[4325,4329,4334,4338,4343],{"type":373,"tag":477,"props":4326,"children":4327},{"style":730},[4328],{"type":382,"value":846},{"type":373,"tag":477,"props":4330,"children":4331},{"style":736},[4332],{"type":382,"value":4333}," { onInvoicePaid } ",{"type":373,"tag":477,"props":4335,"children":4336},{"style":730},[4337],{"type":382,"value":856},{"type":373,"tag":477,"props":4339,"children":4340},{"style":680},[4341],{"type":382,"value":4342}," \"./billing.js\"",{"type":373,"tag":477,"props":4344,"children":4345},{"style":736},[4346],{"type":382,"value":866},{"type":373,"tag":477,"props":4348,"children":4349},{"class":479,"line":525},[4350,4354,4359,4363,4368],{"type":373,"tag":477,"props":4351,"children":4352},{"style":730},[4353],{"type":382,"value":846},{"type":373,"tag":477,"props":4355,"children":4356},{"style":736},[4357],{"type":382,"value":4358}," { showMessage } ",{"type":373,"tag":477,"props":4360,"children":4361},{"style":730},[4362],{"type":382,"value":856},{"type":373,"tag":477,"props":4364,"children":4365},{"style":680},[4366],{"type":382,"value":4367}," \"./inspect.js\"",{"type":373,"tag":477,"props":4369,"children":4370},{"style":736},[4371],{"type":382,"value":866},{"type":373,"tag":477,"props":4373,"children":4374},{"class":479,"line":946},[4375,4379,4384,4388,4393],{"type":373,"tag":477,"props":4376,"children":4377},{"style":730},[4378],{"type":382,"value":846},{"type":373,"tag":477,"props":4380,"children":4381},{"style":736},[4382],{"type":382,"value":4383}," { failingEndpointReport } ",{"type":373,"tag":477,"props":4385,"children":4386},{"style":730},[4387],{"type":382,"value":856},{"type":373,"tag":477,"props":4389,"children":4390},{"style":680},[4391],{"type":382,"value":4392}," \"./health.js\"",{"type":373,"tag":477,"props":4394,"children":4395},{"style":736},[4396],{"type":382,"value":866},{"type":373,"tag":477,"props":4398,"children":4399},{"class":479,"line":1153},[4400],{"type":373,"tag":477,"props":4401,"children":4402},{"emptyLinePlaceholder":721},[4403],{"type":382,"value":724},{"type":373,"tag":477,"props":4405,"children":4406},{"class":479,"line":1162},[4407,4411,4416,4420,4425,4430],{"type":373,"tag":477,"props":4408,"children":4409},{"style":730},[4410],{"type":382,"value":2620},{"type":373,"tag":477,"props":4412,"children":4413},{"style":702},[4414],{"type":382,"value":4415}," url",{"type":373,"tag":477,"props":4417,"children":4418},{"style":730},[4419],{"type":382,"value":895},{"type":373,"tag":477,"props":4421,"children":4422},{"style":736},[4423],{"type":382,"value":4424}," process.env.",{"type":373,"tag":477,"props":4426,"children":4427},{"style":702},[4428],{"type":382,"value":4429},"CUSTOMER_WEBHOOK_URL",{"type":373,"tag":477,"props":4431,"children":4432},{"style":736},[4433],{"type":382,"value":866},{"type":373,"tag":477,"props":4435,"children":4436},{"class":479,"line":1191},[4437,4442,4446,4451,4456,4460,4464,4468,4472,4477],{"type":373,"tag":477,"props":4438,"children":4439},{"style":730},[4440],{"type":382,"value":4441},"if",{"type":373,"tag":477,"props":4443,"children":4444},{"style":736},[4445],{"type":382,"value":601},{"type":373,"tag":477,"props":4447,"children":4448},{"style":730},[4449],{"type":382,"value":4450},"!",{"type":373,"tag":477,"props":4452,"children":4453},{"style":736},[4454],{"type":382,"value":4455},"url) ",{"type":373,"tag":477,"props":4457,"children":4458},{"style":730},[4459],{"type":382,"value":2290},{"type":373,"tag":477,"props":4461,"children":4462},{"style":730},[4463],{"type":382,"value":900},{"type":373,"tag":477,"props":4465,"children":4466},{"style":674},[4467],{"type":382,"value":2299},{"type":373,"tag":477,"props":4469,"children":4470},{"style":736},[4471],{"type":382,"value":1075},{"type":373,"tag":477,"props":4473,"children":4474},{"style":680},[4475],{"type":382,"value":4476},"\"set CUSTOMER_WEBHOOK_URL\"",{"type":373,"tag":477,"props":4478,"children":4479},{"style":736},[4480],{"type":382,"value":2329},{"type":373,"tag":477,"props":4482,"children":4483},{"class":479,"line":1208},[4484],{"type":373,"tag":477,"props":4485,"children":4486},{"emptyLinePlaceholder":721},[4487],{"type":382,"value":724},{"type":373,"tag":477,"props":4489,"children":4490},{"class":479,"line":1250},[4491,4496,4500],{"type":373,"tag":477,"props":4492,"children":4493},{"style":730},[4494],{"type":382,"value":4495},"await",{"type":373,"tag":477,"props":4497,"children":4498},{"style":674},[4499],{"type":382,"value":1048},{"type":373,"tag":477,"props":4501,"children":4502},{"style":736},[4503],{"type":382,"value":3883},{"type":373,"tag":477,"props":4505,"children":4506},{"class":479,"line":1258},[4507],{"type":373,"tag":477,"props":4508,"children":4509},{"emptyLinePlaceholder":721},[4510],{"type":382,"value":724},{"type":373,"tag":477,"props":4512,"children":4513},{"class":479,"line":1620},[4514,4518,4523,4527,4532,4536,4541,4546],{"type":373,"tag":477,"props":4515,"children":4516},{"style":730},[4517],{"type":382,"value":2620},{"type":373,"tag":477,"props":4519,"children":4520},{"style":702},[4521],{"type":382,"value":4522}," customer",{"type":373,"tag":477,"props":4524,"children":4525},{"style":730},[4526],{"type":382,"value":895},{"type":373,"tag":477,"props":4528,"children":4529},{"style":736},[4530],{"type":382,"value":4531}," { id: ",{"type":373,"tag":477,"props":4533,"children":4534},{"style":680},[4535],{"type":382,"value":1125},{"type":373,"tag":477,"props":4537,"children":4538},{"style":736},[4539],{"type":382,"value":4540},", name: ",{"type":373,"tag":477,"props":4542,"children":4543},{"style":680},[4544],{"type":382,"value":4545},"\"Acme\"",{"type":373,"tag":477,"props":4547,"children":4548},{"style":736},[4549],{"type":382,"value":1864},{"type":373,"tag":477,"props":4551,"children":4552},{"class":479,"line":1628},[4553,4557,4562,4566,4570,4574,4579,4584,4588,4593,4597],{"type":373,"tag":477,"props":4554,"children":4555},{"style":730},[4556],{"type":382,"value":2620},{"type":373,"tag":477,"props":4558,"children":4559},{"style":702},[4560],{"type":382,"value":4561}," existing",{"type":373,"tag":477,"props":4563,"children":4564},{"style":730},[4565],{"type":382,"value":895},{"type":373,"tag":477,"props":4567,"children":4568},{"style":730},[4569],{"type":382,"value":1508},{"type":373,"tag":477,"props":4571,"children":4572},{"style":736},[4573],{"type":382,"value":1513},{"type":373,"tag":477,"props":4575,"children":4576},{"style":674},[4577],{"type":382,"value":4578},"list",{"type":373,"tag":477,"props":4580,"children":4581},{"style":736},[4582],{"type":382,"value":4583},"(customer.id).",{"type":373,"tag":477,"props":4585,"children":4586},{"style":674},[4587],{"type":382,"value":2178},{"type":373,"tag":477,"props":4589,"children":4590},{"style":736},[4591],{"type":382,"value":4592},"(() ",{"type":373,"tag":477,"props":4594,"children":4595},{"style":730},[4596],{"type":382,"value":3708},{"type":373,"tag":477,"props":4598,"children":4599},{"style":736},[4600],{"type":382,"value":4601}," []);\n",{"type":373,"tag":477,"props":4603,"children":4604},{"class":479,"line":1636},[4605,4609,4613,4617,4622,4627,4631,4635,4639,4643,4648,4652],{"type":373,"tag":477,"props":4606,"children":4607},{"style":730},[4608],{"type":382,"value":4441},{"type":373,"tag":477,"props":4610,"children":4611},{"style":736},[4612],{"type":382,"value":601},{"type":373,"tag":477,"props":4614,"children":4615},{"style":730},[4616],{"type":382,"value":4450},{"type":373,"tag":477,"props":4618,"children":4619},{"style":736},[4620],{"type":382,"value":4621},"existing.",{"type":373,"tag":477,"props":4623,"children":4624},{"style":674},[4625],{"type":382,"value":4626},"some",{"type":373,"tag":477,"props":4628,"children":4629},{"style":736},[4630],{"type":382,"value":3694},{"type":373,"tag":477,"props":4632,"children":4633},{"style":1382},[4634],{"type":382,"value":4086},{"type":373,"tag":477,"props":4636,"children":4637},{"style":736},[4638],{"type":382,"value":2240},{"type":373,"tag":477,"props":4640,"children":4641},{"style":730},[4642],{"type":382,"value":3708},{"type":373,"tag":477,"props":4644,"children":4645},{"style":736},[4646],{"type":382,"value":4647}," e.url ",{"type":373,"tag":477,"props":4649,"children":4650},{"style":730},[4651],{"type":382,"value":2230},{"type":373,"tag":477,"props":4653,"children":4654},{"style":736},[4655],{"type":382,"value":4656}," url)) {\n",{"type":373,"tag":477,"props":4658,"children":4659},{"class":479,"line":1645},[4660,4664,4668,4672,4676,4681,4685,4689,4693,4697],{"type":373,"tag":477,"props":4661,"children":4662},{"style":730},[4663],{"type":382,"value":1494},{"type":373,"tag":477,"props":4665,"children":4666},{"style":736},[4667],{"type":382,"value":1395},{"type":373,"tag":477,"props":4669,"children":4670},{"style":702},[4671],{"type":382,"value":2931},{"type":373,"tag":477,"props":4673,"children":4674},{"style":736},[4675],{"type":382,"value":443},{"type":373,"tag":477,"props":4677,"children":4678},{"style":702},[4679],{"type":382,"value":4680},"signingSecret",{"type":373,"tag":477,"props":4682,"children":4683},{"style":736},[4684],{"type":382,"value":3860},{"type":373,"tag":477,"props":4686,"children":4687},{"style":730},[4688],{"type":382,"value":744},{"type":373,"tag":477,"props":4690,"children":4691},{"style":730},[4692],{"type":382,"value":1508},{"type":373,"tag":477,"props":4694,"children":4695},{"style":674},[4696],{"type":382,"value":1375},{"type":373,"tag":477,"props":4698,"children":4699},{"style":736},[4700],{"type":382,"value":4701},"(customer, url);\n",{"type":373,"tag":477,"props":4703,"children":4704},{"class":479,"line":1654},[4705,4709,4713,4717,4722,4727,4732],{"type":373,"tag":477,"props":4706,"children":4707},{"style":736},[4708],{"type":382,"value":3891},{"type":373,"tag":477,"props":4710,"children":4711},{"style":674},[4712],{"type":382,"value":2658},{"type":373,"tag":477,"props":4714,"children":4715},{"style":736},[4716],{"type":382,"value":1075},{"type":373,"tag":477,"props":4718,"children":4719},{"style":680},[4720],{"type":382,"value":4721},"\"endpoint\"",{"type":373,"tag":477,"props":4723,"children":4724},{"style":736},[4725],{"type":382,"value":4726},", endpointId, ",{"type":373,"tag":477,"props":4728,"children":4729},{"style":680},[4730],{"type":382,"value":4731},"\"secret\"",{"type":373,"tag":477,"props":4733,"children":4734},{"style":736},[4735],{"type":382,"value":4736},", signingSecret);\n",{"type":373,"tag":477,"props":4738,"children":4739},{"class":479,"line":1668},[4740],{"type":373,"tag":477,"props":4741,"children":4742},{"style":736},[4743],{"type":382,"value":1264},{"type":373,"tag":477,"props":4745,"children":4746},{"class":479,"line":2083},[4747],{"type":373,"tag":477,"props":4748,"children":4749},{"emptyLinePlaceholder":721},[4750],{"type":382,"value":724},{"type":373,"tag":477,"props":4752,"children":4753},{"class":479,"line":2092},[4754,4758,4762,4766,4770,4774,4779,4783,4788,4792,4796,4800],{"type":373,"tag":477,"props":4755,"children":4756},{"style":730},[4757],{"type":382,"value":2620},{"type":373,"tag":477,"props":4759,"children":4760},{"style":702},[4761],{"type":382,"value":1938},{"type":373,"tag":477,"props":4763,"children":4764},{"style":730},[4765],{"type":382,"value":895},{"type":373,"tag":477,"props":4767,"children":4768},{"style":730},[4769],{"type":382,"value":1508},{"type":373,"tag":477,"props":4771,"children":4772},{"style":674},[4773],{"type":382,"value":1891},{"type":373,"tag":477,"props":4775,"children":4776},{"style":736},[4777],{"type":382,"value":4778},"({ id: ",{"type":373,"tag":477,"props":4780,"children":4781},{"style":680},[4782],{"type":382,"value":1115},{"type":373,"tag":477,"props":4784,"children":4785},{"style":736},[4786],{"type":382,"value":4787},", customerId: customer.id, amount: ",{"type":373,"tag":477,"props":4789,"children":4790},{"style":702},[4791],{"type":382,"value":1135},{"type":373,"tag":477,"props":4793,"children":4794},{"style":736},[4795],{"type":382,"value":1140},{"type":373,"tag":477,"props":4797,"children":4798},{"style":680},[4799],{"type":382,"value":1145},{"type":373,"tag":477,"props":4801,"children":4802},{"style":736},[4803],{"type":382,"value":2984},{"type":373,"tag":477,"props":4805,"children":4806},{"class":479,"line":2126},[4807,4812,4816,4820,4825,4830,4835,4840,4845,4849,4854],{"type":373,"tag":477,"props":4808,"children":4809},{"style":736},[4810],{"type":382,"value":4811},"console.",{"type":373,"tag":477,"props":4813,"children":4814},{"style":674},[4815],{"type":382,"value":2658},{"type":373,"tag":477,"props":4817,"children":4818},{"style":736},[4819],{"type":382,"value":1075},{"type":373,"tag":477,"props":4821,"children":4822},{"style":680},[4823],{"type":382,"value":4824},"\"published\"",{"type":373,"tag":477,"props":4826,"children":4827},{"style":736},[4828],{"type":382,"value":4829},", receipt?.id, ",{"type":373,"tag":477,"props":4831,"children":4832},{"style":680},[4833],{"type":382,"value":4834},"\"to\"",{"type":373,"tag":477,"props":4836,"children":4837},{"style":736},[4838],{"type":382,"value":4839},", receipt?.endpoint_ids.",{"type":373,"tag":477,"props":4841,"children":4842},{"style":702},[4843],{"type":382,"value":4844},"length",{"type":373,"tag":477,"props":4846,"children":4847},{"style":736},[4848],{"type":382,"value":443},{"type":373,"tag":477,"props":4850,"children":4851},{"style":680},[4852],{"type":382,"value":4853},"\"endpoint(s)\"",{"type":373,"tag":477,"props":4855,"children":4856},{"style":736},[4857],{"type":382,"value":2329},{"type":373,"tag":477,"props":4859,"children":4860},{"class":479,"line":2135},[4861],{"type":373,"tag":477,"props":4862,"children":4863},{"emptyLinePlaceholder":721},[4864],{"type":382,"value":724},{"type":373,"tag":477,"props":4866,"children":4867},{"class":479,"line":2144},[4868,4872,4876,4880,4884,4888,4892,4896,4900,4904,4909],{"type":373,"tag":477,"props":4869,"children":4870},{"style":730},[4871],{"type":382,"value":4495},{"type":373,"tag":477,"props":4873,"children":4874},{"style":730},[4875],{"type":382,"value":900},{"type":373,"tag":477,"props":4877,"children":4878},{"style":702},[4879],{"type":382,"value":3689},{"type":373,"tag":477,"props":4881,"children":4882},{"style":736},[4883],{"type":382,"value":3694},{"type":373,"tag":477,"props":4885,"children":4886},{"style":1382},[4887],{"type":382,"value":3699},{"type":373,"tag":477,"props":4889,"children":4890},{"style":736},[4891],{"type":382,"value":2240},{"type":373,"tag":477,"props":4893,"children":4894},{"style":730},[4895],{"type":382,"value":3708},{"type":373,"tag":477,"props":4897,"children":4898},{"style":674},[4899],{"type":382,"value":3713},{"type":373,"tag":477,"props":4901,"children":4902},{"style":736},[4903],{"type":382,"value":3718},{"type":373,"tag":477,"props":4905,"children":4906},{"style":702},[4907],{"type":382,"value":4908},"3000",{"type":373,"tag":477,"props":4910,"children":4911},{"style":736},[4912],{"type":382,"value":3728},{"type":373,"tag":477,"props":4914,"children":4915},{"class":479,"line":2153},[4916,4920,4925,4929,4933],{"type":373,"tag":477,"props":4917,"children":4918},{"style":730},[4919],{"type":382,"value":4441},{"type":373,"tag":477,"props":4921,"children":4922},{"style":736},[4923],{"type":382,"value":4924}," (receipt) ",{"type":373,"tag":477,"props":4926,"children":4927},{"style":730},[4928],{"type":382,"value":4495},{"type":373,"tag":477,"props":4930,"children":4931},{"style":674},[4932],{"type":382,"value":2548},{"type":373,"tag":477,"props":4934,"children":4935},{"style":736},[4936],{"type":382,"value":4937},"(receipt.id);\n",{"type":373,"tag":477,"props":4939,"children":4940},{"class":479,"line":2167},[4941,4945,4949,4953,4957,4961],{"type":373,"tag":477,"props":4942,"children":4943},{"style":736},[4944],{"type":382,"value":4811},{"type":373,"tag":477,"props":4946,"children":4947},{"style":674},[4948],{"type":382,"value":2658},{"type":373,"tag":477,"props":4950,"children":4951},{"style":736},[4952],{"type":382,"value":1075},{"type":373,"tag":477,"props":4954,"children":4955},{"style":730},[4956],{"type":382,"value":4495},{"type":373,"tag":477,"props":4958,"children":4959},{"style":674},[4960],{"type":382,"value":3826},{"type":373,"tag":477,"props":4962,"children":4963},{"style":736},[4964],{"type":382,"value":4965},"());\n",{"type":373,"tag":468,"props":4967,"children":4969},{"className":662,"code":4968,"language":664,"meta":345,"style":345},"npx tsx main.ts\n",[4970],{"type":373,"tag":385,"props":4971,"children":4972},{"__ignoreMap":345},[4973],{"type":373,"tag":477,"props":4974,"children":4975},{"class":479,"line":480},[4976,4981,4985],{"type":373,"tag":477,"props":4977,"children":4978},{"style":674},[4979],{"type":382,"value":4980},"npx",{"type":373,"tag":477,"props":4982,"children":4983},{"style":680},[4984],{"type":382,"value":710},{"type":373,"tag":477,"props":4986,"children":4987},{"style":680},[4988],{"type":382,"value":4989}," main.ts\n",{"type":373,"tag":374,"props":4991,"children":4992},{},[4993,4995,5001,5003,5008,5009,5015,5016,5022,5023,5029,5030,5036,5038,5043],{"type":382,"value":4994},"The bin shows a ",{"type":373,"tag":385,"props":4996,"children":4998},{"className":4997},[],[4999],{"type":382,"value":5000},"POST",{"type":382,"value":5002}," with ",{"type":373,"tag":385,"props":5004,"children":5006},{"className":5005},[],[5007],{"type":382,"value":3069},{"type":382,"value":443},{"type":373,"tag":385,"props":5010,"children":5012},{"className":5011},[],[5013],{"type":382,"value":5014},"webhook-timestamp",{"type":382,"value":443},{"type":373,"tag":385,"props":5017,"children":5019},{"className":5018},[],[5020],{"type":382,"value":5021},"webhook-signature",{"type":382,"value":443},{"type":373,"tag":385,"props":5024,"children":5026},{"className":5025},[],[5027],{"type":382,"value":5028},"webhook-event-type: invoice.paid",{"type":382,"value":804},{"type":373,"tag":385,"props":5031,"children":5033},{"className":5032},[],[5034],{"type":382,"value":5035},"webhook-consumer: customer_42",{"type":382,"value":5037},". Run the script again: the publish returns the same receipt ",{"type":373,"tag":385,"props":5039,"children":5041},{"className":5040},[],[5042],{"type":382,"value":1400},{"type":382,"value":5044}," and the bin receives nothing new, because the idempotency key matched.",{"type":373,"tag":533,"props":5046,"children":5048},{"id":5047},"what-your-customers-do",[5049],{"type":382,"value":5050},"What your customers do",{"type":373,"tag":374,"props":5052,"children":5053},{},[5054,5056,5061,5063,5068,5070,5075,5077,5083],{"type":382,"value":5055},"Send each customer their ",{"type":373,"tag":385,"props":5057,"children":5059},{"className":5058},[],[5060],{"type":382,"value":4181},{"type":382,"value":5062}," secret and the ",{"type":373,"tag":404,"props":5064,"children":5065},{"href":71},[5066],{"type":382,"value":5067},"receiving guide",{"type":382,"value":5069},", which has drop-in verification code for Node.js and Go. Any ",{"type":373,"tag":404,"props":5071,"children":5073},{"href":414,"rel":5072},[416],[5074],{"type":382,"value":355},{"type":382,"value":5076}," library works too. You can test signatures by hand with the ",{"type":373,"tag":404,"props":5078,"children":5080},{"href":5079},"/standard-webhooks-signature-generator/",[5081],{"type":382,"value":5082},"Standard Webhooks signature generator",{"type":382,"value":2014},{"type":373,"tag":533,"props":5085,"children":5087},{"id":5086},"next-steps",[5088],{"type":382,"value":5089},"Next steps",{"type":373,"tag":540,"props":5091,"children":5092},{},[5093,5110,5119,5134,5145],{"type":373,"tag":431,"props":5094,"children":5095},{},[5096,5100,5102,5108],{"type":373,"tag":404,"props":5097,"children":5098},{"href":68},[5099],{"type":382,"value":69},{"type":382,"value":5101},": the same flow with ",{"type":373,"tag":385,"props":5103,"children":5105},{"className":5104},[],[5106],{"type":382,"value":5107},"curl",{"type":382,"value":5109}," and the full REST reference.",{"type":373,"tag":431,"props":5111,"children":5112},{},[5113,5117],{"type":373,"tag":404,"props":5114,"children":5115},{"href":74},[5116],{"type":382,"value":75},{"type":382,"value":5118},": delivery statuses, health, Functions and limits.",{"type":373,"tag":431,"props":5120,"children":5121},{},[5122,5127,5128,5133],{"type":373,"tag":404,"props":5123,"children":5124},{"href":206},[5125],{"type":382,"value":5126},"Send webhooks from a Go service",{"type":382,"value":804},{"type":373,"tag":404,"props":5129,"children":5130},{"href":209},[5131],{"type":382,"value":5132},"add webhooks to a Next.js SaaS app",{"type":382,"value":2014},{"type":373,"tag":431,"props":5135,"children":5136},{},[5137,5143],{"type":373,"tag":404,"props":5138,"children":5140},{"href":5139},"/blog/webhook-best-practices/",[5141],{"type":382,"value":5142},"Webhook best practices",{"type":382,"value":5144},": a checklist for senders and receivers.",{"type":373,"tag":431,"props":5146,"children":5147},{},[5148,5153],{"type":373,"tag":404,"props":5149,"children":5150},{"href":406},[5151],{"type":382,"value":5152},"Webhooks as a service pricing and plans",{"type":382,"value":2014},{"type":373,"tag":5155,"props":5156,"children":5157},"style",{},[5158],{"type":382,"value":5159},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":345,"searchDepth":498,"depth":498,"links":5161},[5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173],{"id":535,"depth":489,"text":538},{"id":656,"depth":489,"text":659},{"id":955,"depth":489,"text":958},{"id":1280,"depth":489,"text":1283},{"id":1689,"depth":489,"text":1692},{"id":2469,"depth":489,"text":2472},{"id":3055,"depth":489,"text":3058},{"id":3745,"depth":489,"text":3748},{"id":4161,"depth":489,"text":4164},{"id":4225,"depth":489,"text":4228},{"id":5047,"depth":489,"text":5050},{"id":5086,"depth":489,"text":5089},"markdown","content:docs:tutorials:outbound:1.send-webhooks-nodejs.md","content","docs/tutorials/outbound/1.send-webhooks-nodejs.md","docs/tutorials/outbound/1.send-webhooks-nodejs","md",{"loc":203},1792946448145]