[{"data":1,"prerenderedAt":1240},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fintegrations\u002Fwebhooks":121,"\u002Fdocs\u002Fintegrations\u002Fwebhooks-surround":1235},[4,15,34,41,48,95,107,114],{"title":5,"path":6,"stem":7,"children":8},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,11],{"title":10,"path":6,"stem":7},"Introduction",{"title":12,"path":13,"stem":14},"Quickstart","\u002Fdocs\u002Fgetting-started\u002Fquickstart","1.docs\u002F1.getting-started\u002F2.quickstart",{"title":16,"path":17,"stem":18,"children":19,"icon":33},"Forms & Fields","\u002Fdocs\u002Fforms","1.docs\u002F2.forms\u002F1.index",[20,21,25,29],{"title":16,"path":17,"stem":18},{"title":22,"path":23,"stem":24},"Form Settings","\u002Fdocs\u002Fforms\u002Fsettings","1.docs\u002F2.forms\u002F2.settings",{"title":26,"path":27,"stem":28},"Notifications & Auto-responses","\u002Fdocs\u002Fforms\u002Fnotifications","1.docs\u002F2.forms\u002F3.notifications",{"title":30,"path":31,"stem":32},"After Submission","\u002Fdocs\u002Fforms\u002Fafter-submission","1.docs\u002F2.forms\u002F4.after-submission","i-lucide-file-text",{"title":35,"path":36,"stem":37,"children":38,"icon":40},"Submissions","\u002Fdocs\u002Fsubmissions","1.docs\u002F3.submissions\u002F1.index",[39],{"title":35,"path":36,"stem":37},"i-lucide-inbox",{"title":42,"path":43,"stem":44,"children":45,"icon":47},"Spam Protection","\u002Fdocs\u002Fspam-protection","1.docs\u002F4.spam-protection\u002F1.index",[46],{"title":42,"path":43,"stem":44},"i-lucide-shield-check",{"title":49,"path":50,"stem":51,"children":52,"icon":94},"Integrations","\u002Fdocs\u002Fintegrations","1.docs\u002F5.integrations\u002F1.index",[53,54,58,62,66,70,74,78,82,86,90],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57},"Pipedrive","\u002Fdocs\u002Fintegrations\u002Fpipedrive","1.docs\u002F5.integrations\u002F10.pipedrive",{"title":59,"path":60,"stem":61},"Attio","\u002Fdocs\u002Fintegrations\u002Fattio","1.docs\u002F5.integrations\u002F11.attio",{"title":63,"path":64,"stem":65},"Webhooks","\u002Fdocs\u002Fintegrations\u002Fwebhooks","1.docs\u002F5.integrations\u002F2.webhooks",{"title":67,"path":68,"stem":69},"Slack","\u002Fdocs\u002Fintegrations\u002Fslack","1.docs\u002F5.integrations\u002F3.slack",{"title":71,"path":72,"stem":73},"Zapier","\u002Fdocs\u002Fintegrations\u002Fzapier","1.docs\u002F5.integrations\u002F4.zapier",{"title":75,"path":76,"stem":77},"Microsoft Teams","\u002Fdocs\u002Fintegrations\u002Fteams","1.docs\u002F5.integrations\u002F5.teams",{"title":79,"path":80,"stem":81},"Discord","\u002Fdocs\u002Fintegrations\u002Fdiscord","1.docs\u002F5.integrations\u002F6.discord",{"title":83,"path":84,"stem":85},"Make","\u002Fdocs\u002Fintegrations\u002Fmake","1.docs\u002F5.integrations\u002F7.make",{"title":87,"path":88,"stem":89},"n8n","\u002Fdocs\u002Fintegrations\u002Fn8n","1.docs\u002F5.integrations\u002F8.n8n",{"title":91,"path":92,"stem":93},"Airtable","\u002Fdocs\u002Fintegrations\u002Fairtable","1.docs\u002F5.integrations\u002F9.airtable","i-lucide-webhook",{"title":96,"path":97,"stem":98,"children":99,"icon":106},"Domains","\u002Fdocs\u002Fdomains","1.docs\u002F6.domains\u002F1.index",[100,102],{"title":101,"path":97,"stem":98},"Custom Domains",{"title":103,"path":104,"stem":105},"Import forms from your website","\u002Fdocs\u002Fdomains\u002Fimport-forms","1.docs\u002F6.domains\u002F2.import-forms","i-lucide-globe",{"title":108,"path":109,"stem":110,"children":111,"icon":113},"Teams & Members","\u002Fdocs\u002Fteams","1.docs\u002F7.teams\u002F1.index",[112],{"title":108,"path":109,"stem":110},"i-lucide-users",{"title":115,"path":116,"stem":117,"children":118,"icon":120},"Billing & Plans","\u002Fdocs\u002Fbilling","1.docs\u002F8.billing\u002F1.index",[119],{"title":115,"path":116,"stem":117},"i-lucide-credit-card",{"id":122,"title":63,"body":123,"dateModified":1228,"datePublished":1228,"description":1229,"extension":1230,"meta":1231,"navigation":530,"path":64,"seo":1232,"sitemap":1233,"stem":65,"__hash__":1234},"docs\u002F1.docs\u002F5.integrations\u002F2.webhooks.md",{"type":124,"value":125,"toc":1219},"minimark",[126,130,135,170,180,184,187,212,216,480,484,491,1154,1158,1165,1172,1186,1190,1208,1212,1215],[127,128,129],"p",{},"A webhook integration POSTs each new submission to an HTTPS endpoint you control.\nEvery delivery is signed so you can verify it genuinely came from Formiary.",[131,132,134],"h2",{"id":133},"setup","Setup",[136,137,138,146,153,160,163],"ol",{},[139,140,141,142,145],"li",{},"Open a form and go to the ",[143,144,49],"strong",{}," tab.",[139,147,148,149,152],{},"Add a ",[143,150,151],{},"Webhook"," integration.",[139,154,155,156,159],{},"Enter the ",[143,157,158],{},"HTTPS endpoint URL"," each submission should be POSTed to.",[139,161,162],{},"Choose which events to subscribe to.",[139,164,165,166,169],{},"On creation, Formiary shows a ",[143,167,168],{},"signing secret",".",[171,172,173],"warning",{},[127,174,175,176,179],{},"The signing secret is shown ",[143,177,178],{},"only once, on creation",". Copy and store it\nsecurely — it can't be retrieved later. You'll use it to verify signatures.",[131,181,183],{"id":182},"request-headers","Request headers",[127,185,186],{},"Every delivery includes these headers:",[188,189,190,196,202],"ul",{},[139,191,192],{},[193,194,195],"code",{},"Content-Type: application\u002Fjson",[139,197,198,201],{},[193,199,200],{},"X-Formiary-Event: submission.created"," — the event type.",[139,203,204,207,208,211],{},[193,205,206],{},"X-Formiary-Signature: sha256=\u003Chex>"," — an HMAC-SHA256 of the ",[143,209,210],{},"raw request\nbody bytes",", keyed by your signing secret. The body is canonical JSON (sorted\nkeys, compact separators); always verify against the raw bytes you receive, not\na re-serialized object.",[131,213,215],{"id":214},"payload-envelope","Payload envelope",[217,218,223],"pre",{"className":219,"code":220,"language":221,"meta":222,"style":222},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"event\": \"submission.created\",\n  \"meta\": {\n    \"deliveryId\": \"…\",\n    \"formIntegrationId\": \"…\",\n    \"formId\": \"…\",\n    \"submissionId\": null,        \u002F\u002F null for test events\n    \"timestamp\": \"2026-06-15T…\",\n    \"test\": true                 \u002F\u002F present and true only for test events\n  },\n  \"data\": { \"submission\": { \"id\": \"…\", \"values\": [ … ] } }\n}\n","json","",[193,224,225,234,262,277,300,320,340,359,380,398,404,474],{"__ignoreMap":222},[226,227,230],"span",{"class":228,"line":229},"line",1,[226,231,233],{"class":232},"sMK4o","{\n",[226,235,237,240,244,247,250,253,257,259],{"class":228,"line":236},2,[226,238,239],{"class":232},"  \"",[226,241,243],{"class":242},"spNyl","event",[226,245,246],{"class":232},"\"",[226,248,249],{"class":232},":",[226,251,252],{"class":232}," \"",[226,254,256],{"class":255},"sfazB","submission.created",[226,258,246],{"class":232},[226,260,261],{"class":232},",\n",[226,263,265,267,270,272,274],{"class":228,"line":264},3,[226,266,239],{"class":232},[226,268,269],{"class":242},"meta",[226,271,246],{"class":232},[226,273,249],{"class":232},[226,275,276],{"class":232}," {\n",[226,278,280,283,287,289,291,293,296,298],{"class":228,"line":279},4,[226,281,282],{"class":232},"    \"",[226,284,286],{"class":285},"sBMFI","deliveryId",[226,288,246],{"class":232},[226,290,249],{"class":232},[226,292,252],{"class":232},[226,294,295],{"class":255},"…",[226,297,246],{"class":232},[226,299,261],{"class":232},[226,301,303,305,308,310,312,314,316,318],{"class":228,"line":302},5,[226,304,282],{"class":232},[226,306,307],{"class":285},"formIntegrationId",[226,309,246],{"class":232},[226,311,249],{"class":232},[226,313,252],{"class":232},[226,315,295],{"class":255},[226,317,246],{"class":232},[226,319,261],{"class":232},[226,321,323,325,328,330,332,334,336,338],{"class":228,"line":322},6,[226,324,282],{"class":232},[226,326,327],{"class":285},"formId",[226,329,246],{"class":232},[226,331,249],{"class":232},[226,333,252],{"class":232},[226,335,295],{"class":255},[226,337,246],{"class":232},[226,339,261],{"class":232},[226,341,343,345,348,350,352,355],{"class":228,"line":342},7,[226,344,282],{"class":232},[226,346,347],{"class":285},"submissionId",[226,349,246],{"class":232},[226,351,249],{"class":232},[226,353,354],{"class":232}," null,",[226,356,358],{"class":357},"sHwdD","        \u002F\u002F null for test events\n",[226,360,362,364,367,369,371,373,376,378],{"class":228,"line":361},8,[226,363,282],{"class":232},[226,365,366],{"class":285},"timestamp",[226,368,246],{"class":232},[226,370,249],{"class":232},[226,372,252],{"class":232},[226,374,375],{"class":255},"2026-06-15T…",[226,377,246],{"class":232},[226,379,261],{"class":232},[226,381,383,385,388,390,392,395],{"class":228,"line":382},9,[226,384,282],{"class":232},[226,386,387],{"class":285},"test",[226,389,246],{"class":232},[226,391,249],{"class":232},[226,393,394],{"class":232}," true",[226,396,397],{"class":357},"                 \u002F\u002F present and true only for test events\n",[226,399,401],{"class":228,"line":400},10,[226,402,403],{"class":232},"  },\n",[226,405,407,409,412,414,416,419,421,424,426,428,430,432,436,438,440,442,444,446,449,451,454,456,458,461,465,468,471],{"class":228,"line":406},11,[226,408,239],{"class":232},[226,410,411],{"class":242},"data",[226,413,246],{"class":232},[226,415,249],{"class":232},[226,417,418],{"class":232}," {",[226,420,252],{"class":232},[226,422,423],{"class":285},"submission",[226,425,246],{"class":232},[226,427,249],{"class":232},[226,429,418],{"class":232},[226,431,252],{"class":232},[226,433,435],{"class":434},"sbssI","id",[226,437,246],{"class":232},[226,439,249],{"class":232},[226,441,252],{"class":232},[226,443,295],{"class":255},[226,445,246],{"class":232},[226,447,448],{"class":232},",",[226,450,252],{"class":232},[226,452,453],{"class":434},"values",[226,455,246],{"class":232},[226,457,249],{"class":232},[226,459,460],{"class":232}," [",[226,462,464],{"class":463},"sTEyZ"," … ",[226,466,467],{"class":232},"]",[226,469,470],{"class":232}," }",[226,472,473],{"class":232}," }\n",[226,475,477],{"class":228,"line":476},12,[226,478,479],{"class":232},"}\n",[131,481,483],{"id":482},"verifying-the-signature","Verifying the signature",[127,485,486,487,490],{},"Compute an HMAC-SHA256 of the raw request body using your signing secret and\ncompare it to the ",[193,488,489],{},"X-Formiary-Signature"," header. Reject any request whose\ncomputed signature doesn't match.",[492,493,494,961,1056],"code-group",{},[217,495,500],{"className":496,"code":497,"filename":498,"language":499,"meta":222,"style":222},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import crypto from 'node:crypto';\n\n\u002F\u002F Mount with a raw body parser so you verify the exact bytes received.\napp.post('\u002Fwebhooks\u002Fformiary', express.raw({ type: 'application\u002Fjson' }), (req, res) => {\n  const received = req.header('X-Formiary-Signature') ?? '';\n  const expected = 'sha256=' + crypto\n    .createHmac('sha256', process.env.FORMIARY_SIGNING_SECRET)\n    .update(req.body) \u002F\u002F raw request bytes, not a re-serialized object\n    .digest('hex');\n\n  const valid = received.length === expected.length &&\n    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));\n  if (!valid) return res.status(401).send('invalid signature');\n\n  const event = JSON.parse(req.body.toString('utf8'));\n  \u002F\u002F handle event.event \u002F event.data ...\n  res.sendStatus(200);\n});\n","Node.js","js",[193,501,502,526,532,537,612,650,672,707,728,748,752,780,825,876,881,925,931,951],{"__ignoreMap":222},[226,503,504,508,511,514,517,520,523],{"class":228,"line":229},[226,505,507],{"class":506},"s7zQu","import",[226,509,510],{"class":463}," crypto ",[226,512,513],{"class":506},"from",[226,515,516],{"class":232}," '",[226,518,519],{"class":255},"node:crypto",[226,521,522],{"class":232},"'",[226,524,525],{"class":232},";\n",[226,527,528],{"class":228,"line":236},[226,529,531],{"emptyLinePlaceholder":530},true,"\n",[226,533,534],{"class":228,"line":264},[226,535,536],{"class":357},"\u002F\u002F Mount with a raw body parser so you verify the exact bytes received.\n",[226,538,539,542,544,548,551,553,556,558,560,563,565,568,570,573,577,579,581,584,586,588,591,593,596,600,602,605,607,610],{"class":228,"line":279},[226,540,541],{"class":463},"app",[226,543,169],{"class":232},[226,545,547],{"class":546},"s2Zo4","post",[226,549,550],{"class":463},"(",[226,552,522],{"class":232},[226,554,555],{"class":255},"\u002Fwebhooks\u002Fformiary",[226,557,522],{"class":232},[226,559,448],{"class":232},[226,561,562],{"class":463}," express",[226,564,169],{"class":232},[226,566,567],{"class":546},"raw",[226,569,550],{"class":463},[226,571,572],{"class":232},"{",[226,574,576],{"class":575},"swJcz"," type",[226,578,249],{"class":232},[226,580,516],{"class":232},[226,582,583],{"class":255},"application\u002Fjson",[226,585,522],{"class":232},[226,587,470],{"class":232},[226,589,590],{"class":463},")",[226,592,448],{"class":232},[226,594,595],{"class":232}," (",[226,597,599],{"class":598},"sHdIc","req",[226,601,448],{"class":232},[226,603,604],{"class":598}," res",[226,606,590],{"class":232},[226,608,609],{"class":242}," =>",[226,611,276],{"class":232},[226,613,614,617,620,623,626,628,631,633,635,637,639,642,645,648],{"class":228,"line":302},[226,615,616],{"class":242},"  const",[226,618,619],{"class":463}," received",[226,621,622],{"class":232}," =",[226,624,625],{"class":463}," req",[226,627,169],{"class":232},[226,629,630],{"class":546},"header",[226,632,550],{"class":575},[226,634,522],{"class":232},[226,636,489],{"class":255},[226,638,522],{"class":232},[226,640,641],{"class":575},") ",[226,643,644],{"class":232},"??",[226,646,647],{"class":232}," ''",[226,649,525],{"class":232},[226,651,652,654,657,659,661,664,666,669],{"class":228,"line":322},[226,653,616],{"class":242},[226,655,656],{"class":463}," expected",[226,658,622],{"class":232},[226,660,516],{"class":232},[226,662,663],{"class":255},"sha256=",[226,665,522],{"class":232},[226,667,668],{"class":232}," +",[226,670,671],{"class":463}," crypto\n",[226,673,674,677,680,682,684,687,689,691,694,696,699,701,704],{"class":228,"line":342},[226,675,676],{"class":232},"    .",[226,678,679],{"class":546},"createHmac",[226,681,550],{"class":575},[226,683,522],{"class":232},[226,685,686],{"class":255},"sha256",[226,688,522],{"class":232},[226,690,448],{"class":232},[226,692,693],{"class":463}," process",[226,695,169],{"class":232},[226,697,698],{"class":463},"env",[226,700,169],{"class":232},[226,702,703],{"class":463},"FORMIARY_SIGNING_SECRET",[226,705,706],{"class":575},")\n",[226,708,709,711,714,716,718,720,723,725],{"class":228,"line":361},[226,710,676],{"class":232},[226,712,713],{"class":546},"update",[226,715,550],{"class":575},[226,717,599],{"class":463},[226,719,169],{"class":232},[226,721,722],{"class":463},"body",[226,724,641],{"class":575},[226,726,727],{"class":357},"\u002F\u002F raw request bytes, not a re-serialized object\n",[226,729,730,732,735,737,739,742,744,746],{"class":228,"line":382},[226,731,676],{"class":232},[226,733,734],{"class":546},"digest",[226,736,550],{"class":575},[226,738,522],{"class":232},[226,740,741],{"class":255},"hex",[226,743,522],{"class":232},[226,745,590],{"class":575},[226,747,525],{"class":232},[226,749,750],{"class":228,"line":400},[226,751,531],{"emptyLinePlaceholder":530},[226,753,754,756,759,761,763,765,768,771,773,775,777],{"class":228,"line":406},[226,755,616],{"class":242},[226,757,758],{"class":463}," valid",[226,760,622],{"class":232},[226,762,619],{"class":463},[226,764,169],{"class":232},[226,766,767],{"class":463},"length",[226,769,770],{"class":232}," ===",[226,772,656],{"class":463},[226,774,169],{"class":232},[226,776,767],{"class":463},[226,778,779],{"class":232}," &&\n",[226,781,782,785,787,790,792,795,797,799,801,804,806,808,811,813,815,817,820,823],{"class":228,"line":476},[226,783,784],{"class":463},"    crypto",[226,786,169],{"class":232},[226,788,789],{"class":546},"timingSafeEqual",[226,791,550],{"class":575},[226,793,794],{"class":463},"Buffer",[226,796,169],{"class":232},[226,798,513],{"class":546},[226,800,550],{"class":575},[226,802,803],{"class":463},"received",[226,805,590],{"class":575},[226,807,448],{"class":232},[226,809,810],{"class":463}," Buffer",[226,812,169],{"class":232},[226,814,513],{"class":546},[226,816,550],{"class":575},[226,818,819],{"class":463},"expected",[226,821,822],{"class":575},"))",[226,824,525],{"class":232},[226,826,828,831,833,836,839,841,844,846,848,851,853,856,858,860,863,865,867,870,872,874],{"class":228,"line":827},13,[226,829,830],{"class":506},"  if",[226,832,595],{"class":575},[226,834,835],{"class":232},"!",[226,837,838],{"class":463},"valid",[226,840,641],{"class":575},[226,842,843],{"class":506},"return",[226,845,604],{"class":463},[226,847,169],{"class":232},[226,849,850],{"class":546},"status",[226,852,550],{"class":575},[226,854,855],{"class":434},"401",[226,857,590],{"class":575},[226,859,169],{"class":232},[226,861,862],{"class":546},"send",[226,864,550],{"class":575},[226,866,522],{"class":232},[226,868,869],{"class":255},"invalid signature",[226,871,522],{"class":232},[226,873,590],{"class":575},[226,875,525],{"class":232},[226,877,879],{"class":228,"line":878},14,[226,880,531],{"emptyLinePlaceholder":530},[226,882,884,886,889,891,894,896,899,901,903,905,907,909,912,914,916,919,921,923],{"class":228,"line":883},15,[226,885,616],{"class":242},[226,887,888],{"class":463}," event",[226,890,622],{"class":232},[226,892,893],{"class":463}," JSON",[226,895,169],{"class":232},[226,897,898],{"class":546},"parse",[226,900,550],{"class":575},[226,902,599],{"class":463},[226,904,169],{"class":232},[226,906,722],{"class":463},[226,908,169],{"class":232},[226,910,911],{"class":546},"toString",[226,913,550],{"class":575},[226,915,522],{"class":232},[226,917,918],{"class":255},"utf8",[226,920,522],{"class":232},[226,922,822],{"class":575},[226,924,525],{"class":232},[226,926,928],{"class":228,"line":927},16,[226,929,930],{"class":357},"  \u002F\u002F handle event.event \u002F event.data ...\n",[226,932,934,937,939,942,944,947,949],{"class":228,"line":933},17,[226,935,936],{"class":463},"  res",[226,938,169],{"class":232},[226,940,941],{"class":546},"sendStatus",[226,943,550],{"class":575},[226,945,946],{"class":434},"200",[226,948,590],{"class":575},[226,950,525],{"class":232},[226,952,954,957,959],{"class":228,"line":953},18,[226,955,956],{"class":232},"}",[226,958,590],{"class":463},[226,960,525],{"class":232},[217,962,967],{"className":963,"code":964,"filename":965,"language":966,"meta":222,"style":222},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import hashlib\nimport hmac\nimport os\nfrom flask import request, abort\n\nSECRET = os.environ[\"FORMIARY_SIGNING_SECRET\"].encode()\n\n@app.post(\"\u002Fwebhooks\u002Fformiary\")\ndef formiary_webhook():\n    raw = request.get_data()  # raw request bytes\n    expected = \"sha256=\" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()\n    received = request.headers.get(\"X-Formiary-Signature\", \"\")\n    if not hmac.compare_digest(expected, received):\n        abort(401)\n\n    event = request.get_json()\n    # handle event[\"event\"] \u002F event[\"data\"] ...\n    return \"\", 200\n","Python","python",[193,968,969,974,979,984,989,993,998,1002,1007,1012,1017,1022,1027,1032,1037,1041,1046,1051],{"__ignoreMap":222},[226,970,971],{"class":228,"line":229},[226,972,973],{},"import hashlib\n",[226,975,976],{"class":228,"line":236},[226,977,978],{},"import hmac\n",[226,980,981],{"class":228,"line":264},[226,982,983],{},"import os\n",[226,985,986],{"class":228,"line":279},[226,987,988],{},"from flask import request, abort\n",[226,990,991],{"class":228,"line":302},[226,992,531],{"emptyLinePlaceholder":530},[226,994,995],{"class":228,"line":322},[226,996,997],{},"SECRET = os.environ[\"FORMIARY_SIGNING_SECRET\"].encode()\n",[226,999,1000],{"class":228,"line":342},[226,1001,531],{"emptyLinePlaceholder":530},[226,1003,1004],{"class":228,"line":361},[226,1005,1006],{},"@app.post(\"\u002Fwebhooks\u002Fformiary\")\n",[226,1008,1009],{"class":228,"line":382},[226,1010,1011],{},"def formiary_webhook():\n",[226,1013,1014],{"class":228,"line":400},[226,1015,1016],{},"    raw = request.get_data()  # raw request bytes\n",[226,1018,1019],{"class":228,"line":406},[226,1020,1021],{},"    expected = \"sha256=\" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()\n",[226,1023,1024],{"class":228,"line":476},[226,1025,1026],{},"    received = request.headers.get(\"X-Formiary-Signature\", \"\")\n",[226,1028,1029],{"class":228,"line":827},[226,1030,1031],{},"    if not hmac.compare_digest(expected, received):\n",[226,1033,1034],{"class":228,"line":878},[226,1035,1036],{},"        abort(401)\n",[226,1038,1039],{"class":228,"line":883},[226,1040,531],{"emptyLinePlaceholder":530},[226,1042,1043],{"class":228,"line":927},[226,1044,1045],{},"    event = request.get_json()\n",[226,1047,1048],{"class":228,"line":933},[226,1049,1050],{},"    # handle event[\"event\"] \u002F event[\"data\"] ...\n",[226,1052,1053],{"class":228,"line":953},[226,1054,1055],{},"    return \"\", 200\n",[217,1057,1062],{"className":1058,"code":1059,"filename":1060,"language":1061,"meta":222,"style":222},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","func formiaryWebhook(w http.ResponseWriter, r *http.Request) {\n    body, err := io.ReadAll(r.Body)\n    if err != nil {\n        http.Error(w, \"bad request\", http.StatusBadRequest)\n        return\n    }\n\n    mac := hmac.New(sha256.New, []byte(os.Getenv(\"FORMIARY_SIGNING_SECRET\")))\n    mac.Write(body) \u002F\u002F raw request bytes\n    expected := \"sha256=\" + hex.EncodeToString(mac.Sum(nil))\n\n    if !hmac.Equal([]byte(expected), []byte(r.Header.Get(\"X-Formiary-Signature\"))) {\n        http.Error(w, \"invalid signature\", http.StatusUnauthorized)\n        return\n    }\n\n    \u002F\u002F unmarshal body and handle the event ...\n    w.WriteHeader(http.StatusOK)\n}\n","Go","go",[193,1063,1064,1069,1074,1079,1084,1089,1094,1098,1103,1108,1113,1117,1122,1127,1131,1135,1139,1144,1149],{"__ignoreMap":222},[226,1065,1066],{"class":228,"line":229},[226,1067,1068],{},"func formiaryWebhook(w http.ResponseWriter, r *http.Request) {\n",[226,1070,1071],{"class":228,"line":236},[226,1072,1073],{},"    body, err := io.ReadAll(r.Body)\n",[226,1075,1076],{"class":228,"line":264},[226,1077,1078],{},"    if err != nil {\n",[226,1080,1081],{"class":228,"line":279},[226,1082,1083],{},"        http.Error(w, \"bad request\", http.StatusBadRequest)\n",[226,1085,1086],{"class":228,"line":302},[226,1087,1088],{},"        return\n",[226,1090,1091],{"class":228,"line":322},[226,1092,1093],{},"    }\n",[226,1095,1096],{"class":228,"line":342},[226,1097,531],{"emptyLinePlaceholder":530},[226,1099,1100],{"class":228,"line":361},[226,1101,1102],{},"    mac := hmac.New(sha256.New, []byte(os.Getenv(\"FORMIARY_SIGNING_SECRET\")))\n",[226,1104,1105],{"class":228,"line":382},[226,1106,1107],{},"    mac.Write(body) \u002F\u002F raw request bytes\n",[226,1109,1110],{"class":228,"line":400},[226,1111,1112],{},"    expected := \"sha256=\" + hex.EncodeToString(mac.Sum(nil))\n",[226,1114,1115],{"class":228,"line":406},[226,1116,531],{"emptyLinePlaceholder":530},[226,1118,1119],{"class":228,"line":476},[226,1120,1121],{},"    if !hmac.Equal([]byte(expected), []byte(r.Header.Get(\"X-Formiary-Signature\"))) {\n",[226,1123,1124],{"class":228,"line":827},[226,1125,1126],{},"        http.Error(w, \"invalid signature\", http.StatusUnauthorized)\n",[226,1128,1129],{"class":228,"line":878},[226,1130,1088],{},[226,1132,1133],{"class":228,"line":883},[226,1134,1093],{},[226,1136,1137],{"class":228,"line":927},[226,1138,531],{"emptyLinePlaceholder":530},[226,1140,1141],{"class":228,"line":933},[226,1142,1143],{},"    \u002F\u002F unmarshal body and handle the event ...\n",[226,1145,1146],{"class":228,"line":953},[226,1147,1148],{},"    w.WriteHeader(http.StatusOK)\n",[226,1150,1152],{"class":228,"line":1151},19,[226,1153,479],{},[131,1155,1157],{"id":1156},"responding-retries-dead-lettering","Responding, retries & dead-lettering",[127,1159,1160,1161,1164],{},"Respond with a ",[143,1162,1163],{},"2xx"," status to acknowledge a delivery. Any other status (or a\nconnection error \u002F timeout) marks the attempt as failed and schedules a retry\nwith backoff.",[127,1166,1167,1168,1171],{},"After repeated failures a delivery is ",[143,1169,1170],{},"dead-lettered"," and stops retrying\nautomatically. You can manually retry a failed or dead-lettered delivery from its\nrow in the delivery log. A manual retry preserves the attempt counter, so\nretrying a dead-lettered delivery grants exactly one more attempt before it\nre-dead-letters.",[1173,1174,1175],"note",{},[127,1176,1177,1178,1181,1182,1185],{},"Deliveries are ",[143,1179,1180],{},"at-least-once",": the same submission may be delivered more than\nonce. Use ",[193,1183,1184],{},"meta.deliveryId"," (or the submission id) to deduplicate on your side.",[131,1187,1189],{"id":1188},"testing","Testing",[127,1191,1192,1193,1196,1197,1200,1201,1204,1205,1207],{},"You can send a ",[143,1194,1195],{},"test event"," to your endpoint from the integration. Test events\nhave ",[193,1198,1199],{},"meta.test: true"," and a ",[193,1202,1203],{},"null"," ",[193,1206,347],{},", so your handler can recognize\nand ignore them if needed.",[131,1209,1211],{"id":1210},"delivery-log","Delivery log",[127,1213,1214],{},"Each integration keeps a log of delivery attempts with their status (pending, in\nflight, success, failed, or dead-lettered) and the response received. Use it to\ndebug failures and to trigger manual retries.",[1216,1217,1218],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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);}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 .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 .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}",{"title":222,"searchDepth":236,"depth":236,"links":1220},[1221,1222,1223,1224,1225,1226,1227],{"id":133,"depth":236,"text":134},{"id":182,"depth":236,"text":183},{"id":214,"depth":236,"text":215},{"id":482,"depth":236,"text":483},{"id":1156,"depth":236,"text":1157},{"id":1188,"depth":236,"text":1189},{"id":1210,"depth":236,"text":1211},"2026-07-02","Receive, verify, and respond to Formiary webhook deliveries.","md",{},{"title":63,"description":1229},{"loc":64},"j4MPxSsxb5lGLaL0JYcGVRG1CCdn3cutWH6eo8bP0wY",[1236,1238],{"title":59,"path":60,"stem":61,"description":1237,"children":-1},"Create or update an Attio record for each form submission.",{"title":67,"path":68,"stem":69,"description":1239,"children":-1},"Post each form submission as a message in a Slack channel.",1785813501896]