[{"data":1,"prerenderedAt":1670},["ShallowReactive",2],{"navigation_docs":3,"-docs-webhooks-receiver-examples":268,"-docs-webhooks-receiver-examples-surround":1665},[4,22,35,56,80,135,170,198,222,243],{"title":5,"path":6,"stem":7,"children":8,"page":21},"Getting Started","\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started",[9,13,17],{"title":10,"path":11,"stem":12},"Overview","\u002Fdocs\u002Fgetting-started\u002Foverview","docs\u002F1.getting-started\u002F1.overview",{"title":14,"path":15,"stem":16},"Integration checklist","\u002Fdocs\u002Fgetting-started\u002Fintegration-checklist","docs\u002F1.getting-started\u002F2.integration-checklist",{"title":18,"path":19,"stem":20},"Environments and base URLs","\u002Fdocs\u002Fgetting-started\u002Fenvironments-and-base-urls","docs\u002F1.getting-started\u002F3.environments-and-base-urls",false,{"title":23,"path":24,"stem":25,"children":26,"page":21},"Troubleshooting","\u002Fdocs\u002Ftroubleshooting","docs\u002F10.troubleshooting",[27,31],{"title":28,"path":29,"stem":30},"Common errors","\u002Fdocs\u002Ftroubleshooting\u002Fcommon-errors","docs\u002F10.troubleshooting\u002F1.common-errors",{"title":32,"path":33,"stem":34},"Support escalation","\u002Fdocs\u002Ftroubleshooting\u002Fsupport-escalation","docs\u002F10.troubleshooting\u002F2.support-escalation",{"title":36,"path":37,"stem":38,"children":39,"page":21},"Integration Flow","\u002Fdocs\u002Fintegration-flow","docs\u002F2.integration-flow",[40,44,48,52],{"title":41,"path":42,"stem":43},"Architecture","\u002Fdocs\u002Fintegration-flow\u002Farchitecture","docs\u002F2.integration-flow\u002F1.architecture",{"title":45,"path":46,"stem":47},"Launch session model","\u002Fdocs\u002Fintegration-flow\u002Flaunch-session-model","docs\u002F2.integration-flow\u002F2.launch-session-model",{"title":49,"path":50,"stem":51},"Order and wallet saga","\u002Fdocs\u002Fintegration-flow\u002Forder-and-wallet-saga","docs\u002F2.integration-flow\u002F3.order-and-wallet-saga",{"title":53,"path":54,"stem":55},"FX fees and rounding","\u002Fdocs\u002Fintegration-flow\u002Ffx-fees-and-rounding","docs\u002F2.integration-flow\u002F4.fx-fees-and-rounding",{"title":57,"path":58,"stem":59,"children":60,"page":21},"Dashboard","\u002Fdocs\u002Fdashboard","docs\u002F3.dashboard",[61,64,68,72,76],{"title":10,"path":62,"stem":63},"\u002Fdocs\u002Fdashboard\u002Foverview","docs\u002F3.dashboard\u002F1.overview",{"title":65,"path":66,"stem":67},"API keys","\u002Fdocs\u002Fdashboard\u002Fapi-keys","docs\u002F3.dashboard\u002F2.api-keys",{"title":69,"path":70,"stem":71},"Wallet adapter settings","\u002Fdocs\u002Fdashboard\u002Fwallet-adapter-settings","docs\u002F3.dashboard\u002F3.wallet-adapter-settings",{"title":73,"path":74,"stem":75},"Webhook endpoints","\u002Fdocs\u002Fdashboard\u002Fwebhook-endpoints","docs\u002F3.dashboard\u002F4.webhook-endpoints",{"title":77,"path":78,"stem":79},"Market visibility","\u002Fdocs\u002Fdashboard\u002Fmarket-visibility","docs\u002F3.dashboard\u002F5.market-visibility",{"title":81,"path":82,"stem":83,"children":84,"page":21},"Operator Api","\u002Fdocs\u002Foperator-api","docs\u002F4.operator-api",[85,89,92,96,100,104,107,111,115,119,123,127,131],{"title":86,"path":87,"stem":88},"Authentication","\u002Fdocs\u002Foperator-api\u002Fauthentication","docs\u002F4.operator-api\u002F1.authentication",{"title":73,"path":90,"stem":91},"\u002Fdocs\u002Foperator-api\u002Fwebhook-endpoints","docs\u002F4.operator-api\u002F10.webhook-endpoints",{"title":93,"path":94,"stem":95},"Webhook deliveries","\u002Fdocs\u002Foperator-api\u002Fwebhook-deliveries","docs\u002F4.operator-api\u002F11.webhook-deliveries",{"title":97,"path":98,"stem":99},"Simulator","\u002Fdocs\u002Foperator-api\u002Fsimulator","docs\u002F4.operator-api\u002F12.simulator",{"title":101,"path":102,"stem":103},"Error codes","\u002Fdocs\u002Foperator-api\u002Ferror-codes","docs\u002F4.operator-api\u002F13.error-codes",{"title":65,"path":105,"stem":106},"\u002Fdocs\u002Foperator-api\u002Fapi-keys","docs\u002F4.operator-api\u002F2.api-keys",{"title":108,"path":109,"stem":110},"Session","\u002Fdocs\u002Foperator-api\u002Fsession","docs\u002F4.operator-api\u002F3.session",{"title":112,"path":113,"stem":114},"Launch","\u002Fdocs\u002Foperator-api\u002Flaunch","docs\u002F4.operator-api\u002F4.launch",{"title":116,"path":117,"stem":118},"Users","\u002Fdocs\u002Foperator-api\u002Fusers","docs\u002F4.operator-api\u002F5.users",{"title":120,"path":121,"stem":122},"Markets","\u002Fdocs\u002Foperator-api\u002Fmarkets","docs\u002F4.operator-api\u002F6.markets",{"title":124,"path":125,"stem":126},"Trades","\u002Fdocs\u002Foperator-api\u002Ftrades","docs\u002F4.operator-api\u002F7.trades",{"title":128,"path":129,"stem":130},"Redemptions","\u002Fdocs\u002Foperator-api\u002Fredemptions","docs\u002F4.operator-api\u002F8.redemptions",{"title":132,"path":133,"stem":134},"Balance operations","\u002Fdocs\u002Foperator-api\u002Fbalance-operations","docs\u002F4.operator-api\u002F9.balance-operations",{"title":136,"path":137,"stem":138,"children":139,"page":21},"Wallet Adapter","\u002Fdocs\u002Fwallet-adapter","docs\u002F5.wallet-adapter",[140,143,146,150,154,158,162,166],{"title":10,"path":141,"stem":142},"\u002Fdocs\u002Fwallet-adapter\u002Foverview","docs\u002F5.wallet-adapter\u002F1.overview",{"title":86,"path":144,"stem":145},"\u002Fdocs\u002Fwallet-adapter\u002Fauthentication","docs\u002F5.wallet-adapter\u002F2.authentication",{"title":147,"path":148,"stem":149},"Balance","\u002Fdocs\u002Fwallet-adapter\u002Fbalance","docs\u002F5.wallet-adapter\u002F3.balance",{"title":151,"path":152,"stem":153},"Debit","\u002Fdocs\u002Fwallet-adapter\u002Fdebit","docs\u002F5.wallet-adapter\u002F4.debit",{"title":155,"path":156,"stem":157},"Credit","\u002Fdocs\u002Fwallet-adapter\u002Fcredit","docs\u002F5.wallet-adapter\u002F5.credit",{"title":159,"path":160,"stem":161},"Debit reversal","\u002Fdocs\u002Fwallet-adapter\u002Fdebit-reversal","docs\u002F5.wallet-adapter\u002F6.debit-reversal",{"title":163,"path":164,"stem":165},"Operation lookup","\u002Fdocs\u002Fwallet-adapter\u002Foperation-lookup","docs\u002F5.wallet-adapter\u002F7.operation-lookup",{"title":167,"path":168,"stem":169},"Idempotency","\u002Fdocs\u002Fwallet-adapter\u002Fidempotency","docs\u002F5.wallet-adapter\u002F8.idempotency",{"title":171,"path":172,"stem":173,"children":174,"page":21},"Webhooks","\u002Fdocs\u002Fwebhooks","docs\u002F6.webhooks",[175,178,182,186,190,194],{"title":10,"path":176,"stem":177},"\u002Fdocs\u002Fwebhooks\u002Foverview","docs\u002F6.webhooks\u002F1.overview",{"title":179,"path":180,"stem":181},"Signatures","\u002Fdocs\u002Fwebhooks\u002Fsignatures","docs\u002F6.webhooks\u002F2.signatures",{"title":183,"path":184,"stem":185},"Event envelope","\u002Fdocs\u002Fwebhooks\u002Fevent-envelope","docs\u002F6.webhooks\u002F3.event-envelope",{"title":187,"path":188,"stem":189},"Event types","\u002Fdocs\u002Fwebhooks\u002Fevent-types","docs\u002F6.webhooks\u002F4.event-types",{"title":191,"path":192,"stem":193},"Retry and replay","\u002Fdocs\u002Fwebhooks\u002Fretry-and-replay","docs\u002F6.webhooks\u002F5.retry-and-replay",{"title":195,"path":196,"stem":197},"Receiver examples","\u002Fdocs\u002Fwebhooks\u002Freceiver-examples","docs\u002F6.webhooks\u002F6.receiver-examples",{"title":199,"path":200,"stem":201,"children":202,"page":21},"Testing And Staging","\u002Fdocs\u002Ftesting-and-staging","docs\u002F7.testing-and-staging",[203,207,210,214,218],{"title":204,"path":205,"stem":206},"Staging overview","\u002Fdocs\u002Ftesting-and-staging\u002Fstaging-overview","docs\u002F7.testing-and-staging\u002F1.staging-overview",{"title":97,"path":208,"stem":209},"\u002Fdocs\u002Ftesting-and-staging\u002Fsimulator","docs\u002F7.testing-and-staging\u002F2.simulator",{"title":211,"path":212,"stem":213},"Wallet failure drills","\u002Fdocs\u002Ftesting-and-staging\u002Fwallet-failure-drills","docs\u002F7.testing-and-staging\u002F3.wallet-failure-drills",{"title":215,"path":216,"stem":217},"Webhook drills","\u002Fdocs\u002Ftesting-and-staging\u002Fwebhook-drills","docs\u002F7.testing-and-staging\u002F4.webhook-drills",{"title":219,"path":220,"stem":221},"Production cutover rehearsal","\u002Fdocs\u002Ftesting-and-staging\u002Fproduction-cutover-rehearsal","docs\u002F7.testing-and-staging\u002F5.production-cutover-rehearsal",{"title":223,"path":224,"stem":225,"children":226,"page":21},"Production Readiness","\u002Fdocs\u002Fproduction-readiness","docs\u002F8.production-readiness",[227,231,235,239],{"title":228,"path":229,"stem":230},"Checklist","\u002Fdocs\u002Fproduction-readiness\u002Fchecklist","docs\u002F8.production-readiness\u002F1.checklist",{"title":232,"path":233,"stem":234},"Operational runbook","\u002Fdocs\u002Fproduction-readiness\u002Foperational-runbook","docs\u002F8.production-readiness\u002F2.operational-runbook",{"title":236,"path":237,"stem":238},"Security","\u002Fdocs\u002Fproduction-readiness\u002Fsecurity","docs\u002F8.production-readiness\u002F3.security",{"title":240,"path":241,"stem":242},"Rollback","\u002Fdocs\u002Fproduction-readiness\u002Frollback","docs\u002F8.production-readiness\u002F4.rollback",{"title":244,"path":245,"stem":246,"children":247,"page":21},"Reference","\u002Fdocs\u002Freference","docs\u002F9.reference",[248,252,256,260,264],{"title":249,"path":250,"stem":251},"Statuses","\u002Fdocs\u002Freference\u002Fstatuses","docs\u002F9.reference\u002F1.statuses",{"title":253,"path":254,"stem":255},"Scopes","\u002Fdocs\u002Freference\u002Fscopes","docs\u002F9.reference\u002F2.scopes",{"title":257,"path":258,"stem":259},"Units and money","\u002Fdocs\u002Freference\u002Funits-and-money","docs\u002F9.reference\u002F3.units-and-money",{"title":261,"path":262,"stem":263},"Changelog","\u002Fdocs\u002Freference\u002Fchangelog","docs\u002F9.reference\u002F4.changelog",{"title":265,"path":266,"stem":267},"Virtual AMM","\u002Fdocs\u002Freference\u002Fvirtual-amm","docs\u002F9.reference\u002F5.virtual-amm",{"id":269,"title":195,"body":270,"description":1659,"extension":1660,"links":1661,"meta":1662,"navigation":358,"path":196,"seo":1663,"stem":197,"__hash__":1664},"docs\u002Fdocs\u002F6.webhooks\u002F6.receiver-examples.md",{"type":271,"value":272,"toc":1653},"minimark",[273,277,281,286,1570,1573,1577,1585,1589,1619,1623,1649],[274,275,195],"h1",{"id":276},"receiver-examples",[278,279,280],"p",{},"Examples below show safe minimum flow.",[282,283,285],"h2",{"id":284},"node-example","Node example",[287,288,293],"pre",{"className":289,"code":290,"language":291,"meta":292,"style":292},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { createHmac, timingSafeEqual } from 'node:crypto'\nimport express from 'express'\n\nconst app = express()\napp.use('\u002Fwebhooks\u002Fopenpoly', express.raw({ type: 'application\u002Fjson' }))\n\nconst processedEventIds = new Set\u003Cstring>()\nconst secret = process.env.OPENPOLY_WEBHOOK_SECRET!\nconst maxSkewMs = 5 * 60_000\n\nfunction sign(timestamp: string, rawBody: Buffer) {\n  const payload = `${timestamp}.${rawBody.toString('utf8')}`\n  const digest = createHmac('sha256', secret).update(payload).digest('hex')\n  return `v1=${digest}`\n}\n\napp.post('\u002Fwebhooks\u002Fopenpoly', async (req, res) => {\n  const eventId = String(req.header('x-polynion-event-id') || '')\n  const timestamp = String(req.header('x-polynion-timestamp') || '')\n  const signature = String(req.header('x-polynion-signature') || '')\n  const rawBody = Buffer.isBuffer(req.body) ? req.body : Buffer.from('')\n\n  if (!eventId || !timestamp || !signature) {\n    return res.status(401).json({ error: 'MISSING_SIGNATURE_HEADERS' })\n  }\n\n  const parsedTs = Date.parse(timestamp)\n  if (!Number.isFinite(parsedTs) || Math.abs(Date.now() - parsedTs) > maxSkewMs) {\n    return res.status(401).json({ error: 'TIMESTAMP_SKEW_TOO_LARGE' })\n  }\n\n  const expected = sign(timestamp, rawBody)\n  const expectedBuf = Buffer.from(expected)\n  const gotBuf = Buffer.from(signature)\n  if (expectedBuf.length !== gotBuf.length || !timingSafeEqual(expectedBuf, gotBuf)) {\n    return res.status(401).json({ error: 'INVALID_SIGNATURE' })\n  }\n\n  const payload = JSON.parse(rawBody.toString('utf8'))\n  if (payload.event_id !== eventId) {\n    return res.status(400).json({ error: 'EVENT_ID_MISMATCH' })\n  }\n\n  if (processedEventIds.has(eventId)) {\n    return res.status(409).json({ error: 'DUPLICATE_EVENT_ID' })\n  }\n\n  await persistIncomingEvent(payload)\n  await applyBusinessSideEffects(payload)\n  processedEventIds.add(eventId)\n\n  return res.status(200).json({ ok: true })\n})\n","ts","",[294,295,296,335,353,360,380,436,441,469,495,515,520,556,603,660,678,684,689,730,772,809,846,899,904,938,983,989,994,1018,1081,1121,1126,1131,1153,1176,1198,1242,1282,1287,1292,1326,1348,1389,1394,1399,1422,1463,1468,1473,1488,1502,1519,1524,1563],"code",{"__ignoreMap":292},[297,298,301,305,309,313,316,319,322,325,328,332],"span",{"class":299,"line":300},"line",1,[297,302,304],{"class":303},"s7zQu","import",[297,306,308],{"class":307},"sMK4o"," {",[297,310,312],{"class":311},"sTEyZ"," createHmac",[297,314,315],{"class":307},",",[297,317,318],{"class":311}," timingSafeEqual",[297,320,321],{"class":307}," }",[297,323,324],{"class":303}," from",[297,326,327],{"class":307}," '",[297,329,331],{"class":330},"sfazB","node:crypto",[297,333,334],{"class":307},"'\n",[297,336,338,340,343,346,348,351],{"class":299,"line":337},2,[297,339,304],{"class":303},[297,341,342],{"class":311}," express ",[297,344,345],{"class":303},"from",[297,347,327],{"class":307},[297,349,350],{"class":330},"express",[297,352,334],{"class":307},[297,354,356],{"class":299,"line":355},3,[297,357,359],{"emptyLinePlaceholder":358},true,"\n",[297,361,363,367,370,373,377],{"class":299,"line":362},4,[297,364,366],{"class":365},"spNyl","const",[297,368,369],{"class":311}," app ",[297,371,372],{"class":307},"=",[297,374,376],{"class":375},"s2Zo4"," express",[297,378,379],{"class":311},"()\n",[297,381,383,386,389,392,395,398,401,403,405,407,409,412,414,417,421,424,426,429,431,433],{"class":299,"line":382},5,[297,384,385],{"class":311},"app",[297,387,388],{"class":307},".",[297,390,391],{"class":375},"use",[297,393,394],{"class":311},"(",[297,396,397],{"class":307},"'",[297,399,400],{"class":330},"\u002Fwebhooks\u002Fopenpoly",[297,402,397],{"class":307},[297,404,315],{"class":307},[297,406,376],{"class":311},[297,408,388],{"class":307},[297,410,411],{"class":375},"raw",[297,413,394],{"class":311},[297,415,416],{"class":307},"{",[297,418,420],{"class":419},"swJcz"," type",[297,422,423],{"class":307},":",[297,425,327],{"class":307},[297,427,428],{"class":330},"application\u002Fjson",[297,430,397],{"class":307},[297,432,321],{"class":307},[297,434,435],{"class":311},"))\n",[297,437,439],{"class":299,"line":438},6,[297,440,359],{"emptyLinePlaceholder":358},[297,442,444,446,449,451,454,457,460,464,467],{"class":299,"line":443},7,[297,445,366],{"class":365},[297,447,448],{"class":311}," processedEventIds ",[297,450,372],{"class":307},[297,452,453],{"class":307}," new",[297,455,456],{"class":375}," Set",[297,458,459],{"class":307},"\u003C",[297,461,463],{"class":462},"sBMFI","string",[297,465,466],{"class":307},">",[297,468,379],{"class":311},[297,470,472,474,477,479,482,484,487,489,492],{"class":299,"line":471},8,[297,473,366],{"class":365},[297,475,476],{"class":311}," secret ",[297,478,372],{"class":307},[297,480,481],{"class":311}," process",[297,483,388],{"class":307},[297,485,486],{"class":311},"env",[297,488,388],{"class":307},[297,490,491],{"class":311},"OPENPOLY_WEBHOOK_SECRET",[297,493,494],{"class":307},"!\n",[297,496,498,500,503,505,509,512],{"class":299,"line":497},9,[297,499,366],{"class":365},[297,501,502],{"class":311}," maxSkewMs ",[297,504,372],{"class":307},[297,506,508],{"class":507},"sbssI"," 5",[297,510,511],{"class":307}," *",[297,513,514],{"class":507}," 60_000\n",[297,516,518],{"class":299,"line":517},10,[297,519,359],{"emptyLinePlaceholder":358},[297,521,523,526,529,531,535,537,540,542,545,547,550,553],{"class":299,"line":522},11,[297,524,525],{"class":365},"function",[297,527,528],{"class":375}," sign",[297,530,394],{"class":307},[297,532,534],{"class":533},"sHdIc","timestamp",[297,536,423],{"class":307},[297,538,539],{"class":462}," string",[297,541,315],{"class":307},[297,543,544],{"class":533}," rawBody",[297,546,423],{"class":307},[297,548,549],{"class":462}," Buffer",[297,551,552],{"class":307},")",[297,554,555],{"class":307}," {\n",[297,557,559,562,565,568,571,573,576,578,581,584,586,589,591,593,596,598,600],{"class":299,"line":558},12,[297,560,561],{"class":365},"  const",[297,563,564],{"class":311}," payload",[297,566,567],{"class":307}," =",[297,569,570],{"class":307}," `${",[297,572,534],{"class":311},[297,574,575],{"class":307},"}",[297,577,388],{"class":330},[297,579,580],{"class":307},"${",[297,582,583],{"class":311},"rawBody",[297,585,388],{"class":307},[297,587,588],{"class":375},"toString",[297,590,394],{"class":311},[297,592,397],{"class":307},[297,594,595],{"class":330},"utf8",[297,597,397],{"class":307},[297,599,552],{"class":311},[297,601,602],{"class":307},"}`\n",[297,604,606,608,611,613,615,617,619,622,624,626,629,631,633,636,638,641,643,645,648,650,652,655,657],{"class":299,"line":605},13,[297,607,561],{"class":365},[297,609,610],{"class":311}," digest",[297,612,567],{"class":307},[297,614,312],{"class":375},[297,616,394],{"class":419},[297,618,397],{"class":307},[297,620,621],{"class":330},"sha256",[297,623,397],{"class":307},[297,625,315],{"class":307},[297,627,628],{"class":311}," secret",[297,630,552],{"class":419},[297,632,388],{"class":307},[297,634,635],{"class":375},"update",[297,637,394],{"class":419},[297,639,640],{"class":311},"payload",[297,642,552],{"class":419},[297,644,388],{"class":307},[297,646,647],{"class":375},"digest",[297,649,394],{"class":419},[297,651,397],{"class":307},[297,653,654],{"class":330},"hex",[297,656,397],{"class":307},[297,658,659],{"class":419},")\n",[297,661,663,666,669,672,674,676],{"class":299,"line":662},14,[297,664,665],{"class":303},"  return",[297,667,668],{"class":307}," `",[297,670,671],{"class":330},"v1=",[297,673,580],{"class":307},[297,675,647],{"class":311},[297,677,602],{"class":307},[297,679,681],{"class":299,"line":680},15,[297,682,683],{"class":307},"}\n",[297,685,687],{"class":299,"line":686},16,[297,688,359],{"emptyLinePlaceholder":358},[297,690,692,694,696,699,701,703,705,707,709,712,715,718,720,723,725,728],{"class":299,"line":691},17,[297,693,385],{"class":311},[297,695,388],{"class":307},[297,697,698],{"class":375},"post",[297,700,394],{"class":311},[297,702,397],{"class":307},[297,704,400],{"class":330},[297,706,397],{"class":307},[297,708,315],{"class":307},[297,710,711],{"class":365}," async",[297,713,714],{"class":307}," (",[297,716,717],{"class":533},"req",[297,719,315],{"class":307},[297,721,722],{"class":533}," res",[297,724,552],{"class":307},[297,726,727],{"class":365}," =>",[297,729,555],{"class":307},[297,731,733,735,738,740,743,745,747,749,752,754,756,759,761,764,767,770],{"class":299,"line":732},18,[297,734,561],{"class":365},[297,736,737],{"class":311}," eventId",[297,739,567],{"class":307},[297,741,742],{"class":375}," String",[297,744,394],{"class":419},[297,746,717],{"class":311},[297,748,388],{"class":307},[297,750,751],{"class":375},"header",[297,753,394],{"class":419},[297,755,397],{"class":307},[297,757,758],{"class":330},"x-polynion-event-id",[297,760,397],{"class":307},[297,762,763],{"class":419},") ",[297,765,766],{"class":307},"||",[297,768,769],{"class":307}," ''",[297,771,659],{"class":419},[297,773,775,777,780,782,784,786,788,790,792,794,796,799,801,803,805,807],{"class":299,"line":774},19,[297,776,561],{"class":365},[297,778,779],{"class":311}," timestamp",[297,781,567],{"class":307},[297,783,742],{"class":375},[297,785,394],{"class":419},[297,787,717],{"class":311},[297,789,388],{"class":307},[297,791,751],{"class":375},[297,793,394],{"class":419},[297,795,397],{"class":307},[297,797,798],{"class":330},"x-polynion-timestamp",[297,800,397],{"class":307},[297,802,763],{"class":419},[297,804,766],{"class":307},[297,806,769],{"class":307},[297,808,659],{"class":419},[297,810,812,814,817,819,821,823,825,827,829,831,833,836,838,840,842,844],{"class":299,"line":811},20,[297,813,561],{"class":365},[297,815,816],{"class":311}," signature",[297,818,567],{"class":307},[297,820,742],{"class":375},[297,822,394],{"class":419},[297,824,717],{"class":311},[297,826,388],{"class":307},[297,828,751],{"class":375},[297,830,394],{"class":419},[297,832,397],{"class":307},[297,834,835],{"class":330},"x-polynion-signature",[297,837,397],{"class":307},[297,839,763],{"class":419},[297,841,766],{"class":307},[297,843,769],{"class":307},[297,845,659],{"class":419},[297,847,849,851,853,855,857,859,862,864,866,868,871,873,876,879,881,883,886,888,890,892,894,897],{"class":299,"line":848},21,[297,850,561],{"class":365},[297,852,544],{"class":311},[297,854,567],{"class":307},[297,856,549],{"class":311},[297,858,388],{"class":307},[297,860,861],{"class":375},"isBuffer",[297,863,394],{"class":419},[297,865,717],{"class":311},[297,867,388],{"class":307},[297,869,870],{"class":311},"body",[297,872,763],{"class":419},[297,874,875],{"class":307},"?",[297,877,878],{"class":311}," req",[297,880,388],{"class":307},[297,882,870],{"class":311},[297,884,885],{"class":307}," :",[297,887,549],{"class":311},[297,889,388],{"class":307},[297,891,345],{"class":375},[297,893,394],{"class":419},[297,895,896],{"class":307},"''",[297,898,659],{"class":419},[297,900,902],{"class":299,"line":901},22,[297,903,359],{"emptyLinePlaceholder":358},[297,905,907,910,912,915,918,921,924,926,928,930,933,935],{"class":299,"line":906},23,[297,908,909],{"class":303},"  if",[297,911,714],{"class":419},[297,913,914],{"class":307},"!",[297,916,917],{"class":311},"eventId",[297,919,920],{"class":307}," ||",[297,922,923],{"class":307}," !",[297,925,534],{"class":311},[297,927,920],{"class":307},[297,929,923],{"class":307},[297,931,932],{"class":311},"signature",[297,934,763],{"class":419},[297,936,937],{"class":307},"{\n",[297,939,941,944,946,948,951,953,956,958,960,963,965,967,970,972,974,977,979,981],{"class":299,"line":940},24,[297,942,943],{"class":303},"    return",[297,945,722],{"class":311},[297,947,388],{"class":307},[297,949,950],{"class":375},"status",[297,952,394],{"class":419},[297,954,955],{"class":507},"401",[297,957,552],{"class":419},[297,959,388],{"class":307},[297,961,962],{"class":375},"json",[297,964,394],{"class":419},[297,966,416],{"class":307},[297,968,969],{"class":419}," error",[297,971,423],{"class":307},[297,973,327],{"class":307},[297,975,976],{"class":330},"MISSING_SIGNATURE_HEADERS",[297,978,397],{"class":307},[297,980,321],{"class":307},[297,982,659],{"class":419},[297,984,986],{"class":299,"line":985},25,[297,987,988],{"class":307},"  }\n",[297,990,992],{"class":299,"line":991},26,[297,993,359],{"emptyLinePlaceholder":358},[297,995,997,999,1002,1004,1007,1009,1012,1014,1016],{"class":299,"line":996},27,[297,998,561],{"class":365},[297,1000,1001],{"class":311}," parsedTs",[297,1003,567],{"class":307},[297,1005,1006],{"class":311}," Date",[297,1008,388],{"class":307},[297,1010,1011],{"class":375},"parse",[297,1013,394],{"class":419},[297,1015,534],{"class":311},[297,1017,659],{"class":419},[297,1019,1021,1023,1025,1027,1030,1032,1035,1037,1040,1042,1044,1047,1049,1052,1054,1057,1059,1062,1065,1068,1070,1072,1074,1077,1079],{"class":299,"line":1020},28,[297,1022,909],{"class":303},[297,1024,714],{"class":419},[297,1026,914],{"class":307},[297,1028,1029],{"class":311},"Number",[297,1031,388],{"class":307},[297,1033,1034],{"class":375},"isFinite",[297,1036,394],{"class":419},[297,1038,1039],{"class":311},"parsedTs",[297,1041,763],{"class":419},[297,1043,766],{"class":307},[297,1045,1046],{"class":311}," Math",[297,1048,388],{"class":307},[297,1050,1051],{"class":375},"abs",[297,1053,394],{"class":419},[297,1055,1056],{"class":311},"Date",[297,1058,388],{"class":307},[297,1060,1061],{"class":375},"now",[297,1063,1064],{"class":419},"() ",[297,1066,1067],{"class":307},"-",[297,1069,1001],{"class":311},[297,1071,763],{"class":419},[297,1073,466],{"class":307},[297,1075,1076],{"class":311}," maxSkewMs",[297,1078,763],{"class":419},[297,1080,937],{"class":307},[297,1082,1084,1086,1088,1090,1092,1094,1096,1098,1100,1102,1104,1106,1108,1110,1112,1115,1117,1119],{"class":299,"line":1083},29,[297,1085,943],{"class":303},[297,1087,722],{"class":311},[297,1089,388],{"class":307},[297,1091,950],{"class":375},[297,1093,394],{"class":419},[297,1095,955],{"class":507},[297,1097,552],{"class":419},[297,1099,388],{"class":307},[297,1101,962],{"class":375},[297,1103,394],{"class":419},[297,1105,416],{"class":307},[297,1107,969],{"class":419},[297,1109,423],{"class":307},[297,1111,327],{"class":307},[297,1113,1114],{"class":330},"TIMESTAMP_SKEW_TOO_LARGE",[297,1116,397],{"class":307},[297,1118,321],{"class":307},[297,1120,659],{"class":419},[297,1122,1124],{"class":299,"line":1123},30,[297,1125,988],{"class":307},[297,1127,1129],{"class":299,"line":1128},31,[297,1130,359],{"emptyLinePlaceholder":358},[297,1132,1134,1136,1139,1141,1143,1145,1147,1149,1151],{"class":299,"line":1133},32,[297,1135,561],{"class":365},[297,1137,1138],{"class":311}," expected",[297,1140,567],{"class":307},[297,1142,528],{"class":375},[297,1144,394],{"class":419},[297,1146,534],{"class":311},[297,1148,315],{"class":307},[297,1150,544],{"class":311},[297,1152,659],{"class":419},[297,1154,1156,1158,1161,1163,1165,1167,1169,1171,1174],{"class":299,"line":1155},33,[297,1157,561],{"class":365},[297,1159,1160],{"class":311}," expectedBuf",[297,1162,567],{"class":307},[297,1164,549],{"class":311},[297,1166,388],{"class":307},[297,1168,345],{"class":375},[297,1170,394],{"class":419},[297,1172,1173],{"class":311},"expected",[297,1175,659],{"class":419},[297,1177,1179,1181,1184,1186,1188,1190,1192,1194,1196],{"class":299,"line":1178},34,[297,1180,561],{"class":365},[297,1182,1183],{"class":311}," gotBuf",[297,1185,567],{"class":307},[297,1187,549],{"class":311},[297,1189,388],{"class":307},[297,1191,345],{"class":375},[297,1193,394],{"class":419},[297,1195,932],{"class":311},[297,1197,659],{"class":419},[297,1199,1201,1203,1205,1208,1210,1213,1216,1218,1220,1222,1224,1226,1229,1231,1233,1235,1237,1240],{"class":299,"line":1200},35,[297,1202,909],{"class":303},[297,1204,714],{"class":419},[297,1206,1207],{"class":311},"expectedBuf",[297,1209,388],{"class":307},[297,1211,1212],{"class":311},"length",[297,1214,1215],{"class":307}," !==",[297,1217,1183],{"class":311},[297,1219,388],{"class":307},[297,1221,1212],{"class":311},[297,1223,920],{"class":307},[297,1225,923],{"class":307},[297,1227,1228],{"class":375},"timingSafeEqual",[297,1230,394],{"class":419},[297,1232,1207],{"class":311},[297,1234,315],{"class":307},[297,1236,1183],{"class":311},[297,1238,1239],{"class":419},")) ",[297,1241,937],{"class":307},[297,1243,1245,1247,1249,1251,1253,1255,1257,1259,1261,1263,1265,1267,1269,1271,1273,1276,1278,1280],{"class":299,"line":1244},36,[297,1246,943],{"class":303},[297,1248,722],{"class":311},[297,1250,388],{"class":307},[297,1252,950],{"class":375},[297,1254,394],{"class":419},[297,1256,955],{"class":507},[297,1258,552],{"class":419},[297,1260,388],{"class":307},[297,1262,962],{"class":375},[297,1264,394],{"class":419},[297,1266,416],{"class":307},[297,1268,969],{"class":419},[297,1270,423],{"class":307},[297,1272,327],{"class":307},[297,1274,1275],{"class":330},"INVALID_SIGNATURE",[297,1277,397],{"class":307},[297,1279,321],{"class":307},[297,1281,659],{"class":419},[297,1283,1285],{"class":299,"line":1284},37,[297,1286,988],{"class":307},[297,1288,1290],{"class":299,"line":1289},38,[297,1291,359],{"emptyLinePlaceholder":358},[297,1293,1295,1297,1299,1301,1304,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324],{"class":299,"line":1294},39,[297,1296,561],{"class":365},[297,1298,564],{"class":311},[297,1300,567],{"class":307},[297,1302,1303],{"class":311}," JSON",[297,1305,388],{"class":307},[297,1307,1011],{"class":375},[297,1309,394],{"class":419},[297,1311,583],{"class":311},[297,1313,388],{"class":307},[297,1315,588],{"class":375},[297,1317,394],{"class":419},[297,1319,397],{"class":307},[297,1321,595],{"class":330},[297,1323,397],{"class":307},[297,1325,435],{"class":419},[297,1327,1329,1331,1333,1335,1337,1340,1342,1344,1346],{"class":299,"line":1328},40,[297,1330,909],{"class":303},[297,1332,714],{"class":419},[297,1334,640],{"class":311},[297,1336,388],{"class":307},[297,1338,1339],{"class":311},"event_id",[297,1341,1215],{"class":307},[297,1343,737],{"class":311},[297,1345,763],{"class":419},[297,1347,937],{"class":307},[297,1349,1351,1353,1355,1357,1359,1361,1364,1366,1368,1370,1372,1374,1376,1378,1380,1383,1385,1387],{"class":299,"line":1350},41,[297,1352,943],{"class":303},[297,1354,722],{"class":311},[297,1356,388],{"class":307},[297,1358,950],{"class":375},[297,1360,394],{"class":419},[297,1362,1363],{"class":507},"400",[297,1365,552],{"class":419},[297,1367,388],{"class":307},[297,1369,962],{"class":375},[297,1371,394],{"class":419},[297,1373,416],{"class":307},[297,1375,969],{"class":419},[297,1377,423],{"class":307},[297,1379,327],{"class":307},[297,1381,1382],{"class":330},"EVENT_ID_MISMATCH",[297,1384,397],{"class":307},[297,1386,321],{"class":307},[297,1388,659],{"class":419},[297,1390,1392],{"class":299,"line":1391},42,[297,1393,988],{"class":307},[297,1395,1397],{"class":299,"line":1396},43,[297,1398,359],{"emptyLinePlaceholder":358},[297,1400,1402,1404,1406,1409,1411,1414,1416,1418,1420],{"class":299,"line":1401},44,[297,1403,909],{"class":303},[297,1405,714],{"class":419},[297,1407,1408],{"class":311},"processedEventIds",[297,1410,388],{"class":307},[297,1412,1413],{"class":375},"has",[297,1415,394],{"class":419},[297,1417,917],{"class":311},[297,1419,1239],{"class":419},[297,1421,937],{"class":307},[297,1423,1425,1427,1429,1431,1433,1435,1438,1440,1442,1444,1446,1448,1450,1452,1454,1457,1459,1461],{"class":299,"line":1424},45,[297,1426,943],{"class":303},[297,1428,722],{"class":311},[297,1430,388],{"class":307},[297,1432,950],{"class":375},[297,1434,394],{"class":419},[297,1436,1437],{"class":507},"409",[297,1439,552],{"class":419},[297,1441,388],{"class":307},[297,1443,962],{"class":375},[297,1445,394],{"class":419},[297,1447,416],{"class":307},[297,1449,969],{"class":419},[297,1451,423],{"class":307},[297,1453,327],{"class":307},[297,1455,1456],{"class":330},"DUPLICATE_EVENT_ID",[297,1458,397],{"class":307},[297,1460,321],{"class":307},[297,1462,659],{"class":419},[297,1464,1466],{"class":299,"line":1465},46,[297,1467,988],{"class":307},[297,1469,1471],{"class":299,"line":1470},47,[297,1472,359],{"emptyLinePlaceholder":358},[297,1474,1476,1479,1482,1484,1486],{"class":299,"line":1475},48,[297,1477,1478],{"class":303},"  await",[297,1480,1481],{"class":375}," persistIncomingEvent",[297,1483,394],{"class":419},[297,1485,640],{"class":311},[297,1487,659],{"class":419},[297,1489,1491,1493,1496,1498,1500],{"class":299,"line":1490},49,[297,1492,1478],{"class":303},[297,1494,1495],{"class":375}," applyBusinessSideEffects",[297,1497,394],{"class":419},[297,1499,640],{"class":311},[297,1501,659],{"class":419},[297,1503,1505,1508,1510,1513,1515,1517],{"class":299,"line":1504},50,[297,1506,1507],{"class":311},"  processedEventIds",[297,1509,388],{"class":307},[297,1511,1512],{"class":375},"add",[297,1514,394],{"class":419},[297,1516,917],{"class":311},[297,1518,659],{"class":419},[297,1520,1522],{"class":299,"line":1521},51,[297,1523,359],{"emptyLinePlaceholder":358},[297,1525,1527,1529,1531,1533,1535,1537,1540,1542,1544,1546,1548,1550,1553,1555,1559,1561],{"class":299,"line":1526},52,[297,1528,665],{"class":303},[297,1530,722],{"class":311},[297,1532,388],{"class":307},[297,1534,950],{"class":375},[297,1536,394],{"class":419},[297,1538,1539],{"class":507},"200",[297,1541,552],{"class":419},[297,1543,388],{"class":307},[297,1545,962],{"class":375},[297,1547,394],{"class":419},[297,1549,416],{"class":307},[297,1551,1552],{"class":419}," ok",[297,1554,423],{"class":307},[297,1556,1558],{"class":1557},"sfNiH"," true",[297,1560,321],{"class":307},[297,1562,659],{"class":419},[297,1564,1566,1568],{"class":299,"line":1565},53,[297,1567,575],{"class":307},[297,1569,659],{"class":311},[278,1571,1572],{},"Replace in-memory dedupe with DB table or durable cache.",[282,1574,1576],{"id":1575},"generic-pseudocode","Generic pseudocode",[287,1578,1583],{"className":1579,"code":1581,"language":1582,"meta":292},[1580],"language-text","read raw_body\nread event_id, timestamp, signature headers\nif any missing -> 401\n\nif timestamp older\u002Fnewer than allowed skew -> 401\n\nexpected = hmac_sha256_hex(secret, \"{timestamp}.{raw_body}\")\nif \"v1={expected}\" != signature using constant-time compare -> 401\n\npayload = parse_json(raw_body)\nif payload.event_id != header event_id -> 400\n\nif event_id already processed -> 409\n\nbegin durable transaction\n  store inbound event log\n  apply business effect\n  mark event_id processed\ncommit\n\nreturn 200\n","text",[294,1584,1581],{"__ignoreMap":292},[282,1586,1588],{"id":1587},"response-behavior","Response behavior",[1590,1591,1592,1603,1608,1613],"ul",{},[1593,1594,1595,1596,1598,1599,1602],"li",{},"return ",[294,1597,1539],{}," or other ",[294,1600,1601],{},"2xx"," after durable success",[1593,1604,1595,1605,1607],{},[294,1606,955],{}," for missing or bad signature",[1593,1609,1595,1610,1612],{},[294,1611,1437],{}," for duplicate already-processed event",[1593,1614,1595,1615,1618],{},[294,1616,1617],{},"500"," for transient internal failure -> OpenPoly retries",[282,1620,1622],{"id":1621},"common-mistakes","Common mistakes",[1590,1624,1625,1628,1631,1640,1646],{},[1593,1626,1627],{},"parsing JSON before reading raw body",[1593,1629,1630],{},"rebuilding JSON string before signature verification",[1593,1632,1633,1634,1637,1638],{},"deduping by ",[294,1635,1636],{},"aggregate_id"," instead of ",[294,1639,1339],{},[1593,1641,1642,1643,1645],{},"returning ",[294,1644,1539],{}," before durable commit",[1593,1647,1648],{},"deleting dedupe record too early",[1650,1651,1652],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":292,"searchDepth":337,"depth":337,"links":1654},[1655,1656,1657,1658],{"id":284,"depth":337,"text":285},{"id":1575,"depth":337,"text":1576},{"id":1587,"depth":337,"text":1588},{"id":1621,"depth":337,"text":1622},"Implementation examples for verifying and storing webhook deliveries.","md",null,{},{"title":195,"description":1659},"Jh_255AahOiOSlny3iAPMXoudYeZe_2KjQxVk5vG_v8",[1666,1668],{"title":191,"path":192,"stem":193,"description":1667,"children":-1},"Retry policy, terminal failures, and dashboard replay behavior.",{"title":204,"path":205,"stem":206,"description":1669,"children":-1},"Use staging to validate the same integration contract before production.",1781957290954]