[{"data":1,"prerenderedAt":900},["ShallowReactive",2],{"header:help":3,"footer:default":67,"story:navigation\u002Fsearch:help":250,"story:help\u002Fcategories":288,"story:help\u002Farticles\u002Fverify-a-webhook-payload":314,"no-guide:verify-a-webhook-payload":59,"article:\u002Fhelp\u002Farticles\u002Fverify-a-webhook-payload":635,"story:contact":658,"help:tree:a98d0a09-b3dc-41f2-a242-f6baccce7733":848,"_apollo:default":899},{"name":4,"created_at":5,"published_at":6,"updated_at":7,"id":8,"uuid":9,"content":10,"slug":57,"full_slug":58,"sort_by_date":59,"position":60,"tag_list":61,"is_startpage":24,"parent_id":62,"meta_data":59,"group_id":63,"first_published_at":64,"release_id":59,"lang":65,"path":59,"alternates":66,"default_full_slug":59,"translated_slugs":59},"Help Center Header","2024-08-09T18:06:34.939Z","2024-10-21T21:58:39.217Z","2024-10-21T21:58:39.232Z",10082752,"3e9b88f7-c163-4657-a2f2-62532d600fad",{"_uid":11,"link":12,"badge":16,"items":17,"title":13,"buttons":50,"new_tab":24,"submenu":51,"alignment":13,"component":52,"badge_link":53,"top_menu_items":56},"e5645a1a-f991-40e8-8d67-e40ebc082b5a",{"id":13,"url":13,"linktype":14,"fieldtype":15,"cached_url":13},"","story","multilink","Help Center",[18,27,34,39,44],{"_uid":19,"link":20,"title":23,"new_tab":24,"submenu":25,"component":26},"5cbe2861-1f49-4166-97da-a4dddd8105e3",{"id":21,"url":13,"linktype":14,"fieldtype":15,"cached_url":22},"4c0a2d99-ec30-4579-8ef1-6bf5564d4839","help\u002Fcategories\u002F","Articles",false,[],"header___item",{"_uid":28,"link":29,"title":32,"new_tab":33,"component":26},"1c8edeb5-b9e9-4cb8-b1c6-c1f292f7d7cd",{"id":13,"url":30,"linktype":31,"fieldtype":15,"cached_url":30},"https:\u002F\u002Fwiki.foxycart.com\u002F","url","Documentation",true,{"_uid":35,"link":36,"title":38,"new_tab":33,"component":26},"8d7df70e-f087-4da0-b616-6f0e9a5af35c",{"id":13,"url":37,"linktype":31,"fieldtype":15,"cached_url":37},"https:\u002F\u002Fapi.foxycart.com\u002F","API Documentation",{"_uid":40,"link":41,"title":43,"new_tab":33,"component":26},"f76e7944-23d5-4652-87e4-cdae79272762",{"id":13,"url":42,"linktype":31,"fieldtype":15,"cached_url":42},"https:\u002F\u002Fstatus.foxy.io\u002F","System Status",{"_uid":45,"link":46,"title":49,"new_tab":24,"component":26},"0de16771-4c84-466c-a1da-d8568113c71f",{"id":47,"url":13,"linktype":14,"fieldtype":15,"cached_url":48},"01e4e370-f9b9-45af-8fa9-f15540699b0d","contact","Contact Us",[],[],"header",{"id":54,"url":13,"linktype":14,"fieldtype":15,"cached_url":55},"4a679eb7-662d-4ea4-a976-5a2acbf0b663","help\u002F",[],"help-header","navigation\u002Fhelp-header",null,20,[],10082747,"71b81c2e-5e09-48a1-a397-a3c72fcd344a","2022-09-21T14:50:25.655Z","default",[],{"name":68,"created_at":69,"published_at":70,"updated_at":71,"id":72,"uuid":73,"content":74,"slug":243,"full_slug":244,"sort_by_date":59,"position":245,"tag_list":246,"is_startpage":24,"parent_id":62,"meta_data":59,"group_id":247,"first_published_at":248,"release_id":59,"lang":65,"path":59,"alternates":249,"default_full_slug":59,"translated_slugs":59},"Default Footer","2024-08-09T18:06:59.024Z","2025-09-04T06:24:46.223Z","2025-09-04T06:24:46.241Z",10082753,"e59e67ac-248a-482f-84a1-53d4f318186a",{"_uid":75,"about":76,"logos":77,"socials":82,"sections":108,"component":225,"cta_title":226,"bottom_links":227,"cta_subtitle":241,"cta_button_link":242,"cta_button_text":183},"830983f5-c4c4-43c8-b150-86a5e3fa6dc8","Foxy’s hosted cart & payment page allow you to sell anything, using your existing website or platform.",[78],{"id":79,"alt":13,"name":13,"focus":13,"title":13,"filename":80,"copyright":13,"fieldtype":81},14760,"https:\u002F\u002Fa-us.storyblok.com\u002Ff\u002F1001040\u002Fx\u002F3b030847ec\u002Fb-corp.svg","asset",[83,90,96,102],{"_uid":84,"icon":85,"link":86,"name":88,"component":89},"faf0a618-ea94-42ea-9182-03be18c43216","fa-facebook",{"id":13,"url":87,"linktype":31,"fieldtype":15,"cached_url":87},"https:\u002F\u002Fwww.facebook.com\u002Ffoxycart","Facebook","footer___social",{"_uid":91,"icon":92,"link":93,"name":95,"component":89},"14309c18-7e79-423e-b375-34555bac0811","fa-instagram",{"id":13,"url":94,"linktype":31,"fieldtype":15,"cached_url":94},"https:\u002F\u002Fwww.instagram.com\u002Ffoxy_io","Instagram",{"_uid":97,"icon":98,"link":99,"name":101,"component":89},"8f7fe7cf-0dd3-4596-8334-226ea466716a","fa-linkedin",{"id":13,"url":100,"linktype":31,"fieldtype":15,"cached_url":100},"https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Ffoxycart.com","LinkedIn",{"_uid":103,"icon":104,"link":105,"name":107,"component":89},"90a675b4-dd97-40b5-be09-00a87223d4c5","fa-youtube",{"id":13,"url":106,"linktype":31,"fieldtype":15,"cached_url":106},"https:\u002F\u002Fwww.youtube.com\u002Fuser\u002Ffoxycart","Youtube",[109,139,184,206],{"_uid":110,"name":111,"items":112,"component":138},"82849945-282f-488c-b18d-a8d2252f514a","Company",[113,120,126,132],{"_uid":114,"link":115,"title":118,"new_tab":24,"component":119},"1f699ab1-938b-4d9d-9825-aabcbe6f57fe",{"id":116,"url":13,"linktype":14,"fieldtype":15,"cached_url":117},"63634293-a749-4226-9439-9f38ee6dcda0","about-us","About Us","footer___menu_items",{"_uid":121,"link":122,"title":125,"new_tab":24,"component":119},"b26b00f1-a0e7-4be2-8ab3-428b8cc841f8",{"id":123,"url":13,"linktype":14,"fieldtype":15,"cached_url":124},"26cb7c55-faed-4a77-a291-1552d4111b3e","how-foxy-works","How Foxy Works",{"_uid":127,"link":128,"title":131,"new_tab":24,"component":119},"b40c68a0-1ceb-4226-9515-6176534f61fe",{"id":129,"url":13,"linktype":14,"fieldtype":15,"cached_url":130},"dc6657d7-7f4f-4c0d-b781-e971b038ee26","for-good","Foxy For Good",{"_uid":133,"link":134,"title":137,"new_tab":24,"component":119},"3ad0c134-bef9-4fff-b891-e09f16109036",{"id":135,"url":13,"linktype":14,"fieldtype":15,"cached_url":136},"23cae210-baf4-4588-9862-d09f4f52ccd2","brand-assets","Brand Assets","footer___section",{"_uid":140,"name":141,"items":142,"component":138},"a6805fa8-ac60-47f1-b8f0-f27aded0afbe","Product",[143,149,155,161,167,173,179],{"_uid":144,"link":145,"title":148,"new_tab":24,"component":119},"b39c8a4e-2383-486f-b76a-11fbb15d8134",{"id":146,"url":13,"linktype":14,"fieldtype":15,"cached_url":147},"bb04690f-fe98-4ce6-80be-05b950f2364f","features\u002F","Features",{"_uid":150,"link":151,"title":154,"new_tab":24,"component":119},"64f8a41f-c181-433d-bc0a-fc94e71ecbf6",{"id":152,"url":13,"linktype":14,"fieldtype":15,"cached_url":153},"c450c58d-761d-48c0-a9af-0b064611689b","pricing","Pricing",{"_uid":156,"link":157,"title":160,"new_tab":24,"component":119},"6e0b287f-fd8c-4146-9e0e-0ab0b5c9ce3c",{"id":158,"url":13,"linktype":14,"fieldtype":15,"cached_url":159},"fab20ad9-e76a-4947-b709-3a6fdfa88028","blog\u002Fcategories\u002Fproduct-updates","Product Updates",{"_uid":162,"link":163,"title":166,"new_tab":24,"component":119},"47e5a074-a6b5-4f1c-8c2f-89a2ae9f83eb",{"id":164,"url":13,"linktype":14,"fieldtype":15,"cached_url":165},"d2c83612-d611-47f3-a3b4-ca7fe08540b8","changelogs\u002F","Changelogs",{"_uid":168,"link":169,"title":172,"new_tab":24,"component":119},"b5c08774-542f-4ffd-b357-c94d674488b9",{"id":170,"url":13,"linktype":14,"fieldtype":15,"cached_url":171},"08876121-0df3-4ed9-aa11-902b3e41cd02","whats-next","What's Next",{"_uid":174,"link":175,"title":178,"new_tab":24,"component":119},"9c2704ed-6d9f-43e1-9e67-c8d91c083288",{"id":176,"url":13,"linktype":14,"fieldtype":15,"cached_url":177},"056a7857-b18f-4025-8f97-91a38fc19bc8","compare\u002F","Compare",{"_uid":180,"link":181,"title":183,"new_tab":24,"component":119},"5f2db35b-674b-406a-8fa7-d246633af9fe",{"id":13,"url":182,"linktype":31,"fieldtype":15,"cached_url":182},"https:\u002F\u002Fadmin.foxy.io\u002Fsign-up","Try Foxy Free",{"_uid":185,"name":186,"items":187,"component":138},"63fa1f29-4252-4640-9922-fe310e69e54a","Security",[188,194,200],{"_uid":189,"link":190,"title":193,"new_tab":24,"component":119},"1158ddb6-9eb0-466f-8eb6-7ca2ae66c8b8",{"id":191,"url":13,"linktype":14,"fieldtype":15,"cached_url":192},"1f58fb2c-8681-4742-b6e8-09999beae9f6","security-contact","Security Contact",{"_uid":195,"link":196,"title":199,"new_tab":24,"component":119},"9a79c54a-6022-4dfd-854b-766f5e4703ba",{"id":197,"url":13,"linktype":14,"fieldtype":15,"cached_url":198},"55cbfcc3-425a-4261-8037-54e919851d2d","pci","PCI Compliance",{"_uid":201,"link":202,"title":205,"new_tab":24,"component":119},"0b85f5b6-9534-4071-b323-b39d053dd4d7",{"id":203,"url":13,"linktype":14,"fieldtype":15,"cached_url":204},"c3ac0fe3-83e2-4879-afbd-d4c83e1590df","help\u002Farticles\u002Four-official-domains-public-code","Domains & Codebases",{"_uid":207,"name":208,"items":209,"component":138},"998ded67-d107-49f4-8154-ca6be51671ec","Support",[210,213,216,219,222],{"_uid":211,"link":212,"title":16,"new_tab":24,"component":119},"594ffd35-3049-4004-bb08-0db568ebd819",{"id":54,"url":13,"linktype":14,"fieldtype":15,"cached_url":55},{"_uid":214,"link":215,"title":32,"new_tab":33,"component":119},"0a1a55ab-a985-4f9d-8b42-26da714d0c1c",{"id":13,"url":30,"linktype":31,"fieldtype":15,"cached_url":30},{"_uid":217,"link":218,"title":38,"new_tab":33,"component":119},"61e0b7c8-aadf-419b-a339-b3ccabc65bf4",{"id":13,"url":37,"linktype":31,"fieldtype":15,"cached_url":37},{"_uid":220,"link":221,"title":43,"new_tab":33,"component":119},"fd67a89e-1c54-4d31-94b5-64be999062d6",{"id":13,"url":42,"linktype":31,"fieldtype":15,"cached_url":42},{"_uid":223,"link":224,"title":49,"new_tab":24,"component":119},"231a6f71-e996-4ad4-b033-d4d5542f34f0",{"id":47,"url":13,"linktype":14,"fieldtype":15,"cached_url":48},"footer","Get started with our *unlimited free trial*.",[228,235],{"_uid":229,"link":230,"text":233,"component":234},"f0b77210-2632-45a2-8436-e57cad84d01a",{"id":231,"url":13,"linktype":14,"fieldtype":15,"cached_url":232},"60ba16a2-c1f4-485f-b978-8d2eeeafbf5a","terms-of-service","Terms of Service","footer___bottom_links",{"_uid":236,"link":237,"text":240,"component":234},"4bd497b0-993f-4b4d-a5b7-8a49c7c8fec9",{"id":238,"url":13,"linktype":14,"fieldtype":15,"cached_url":239},"332302b9-1d18-4016-b9c8-9b33c72d782b","privacy-policy","Privacy Policy","No credit card required.",{"id":13,"url":182,"linktype":31,"fieldtype":15,"cached_url":182},"default-footer","navigation\u002Fdefault-footer",50,[],"11006268-07f9-41e9-96f3-c51fb723399d","2022-09-21T20:39:02.357Z",[],{"name":251,"created_at":252,"published_at":253,"updated_at":254,"id":255,"uuid":256,"content":257,"slug":279,"full_slug":282,"sort_by_date":59,"position":283,"tag_list":284,"is_startpage":24,"parent_id":62,"meta_data":59,"group_id":285,"first_published_at":286,"release_id":59,"lang":65,"path":59,"alternates":287,"default_full_slug":59,"translated_slugs":59},"Search","2024-10-21T22:08:54.973Z","2025-05-26T09:17:25.790Z","2025-05-26T09:17:25.804Z",13592003,"14cbc359-9ac1-4a7a-a8de-ad4ac8ef26d4",{"_uid":258,"name":251,"indices":259,"summary":13,"component":279,"primary_image":280},"5e4a56e8-76f1-4790-b3a7-70f1be97d042",[260,265,269,274],{"key":261,"_uid":262,"icon":13,"name":263,"component":264},"all","c12a3210-7323-4273-8217-5215e52efe84","All","index",{"key":266,"_uid":267,"icon":268,"name":23,"component":264},"help_center_article","5acff080-95e4-44d3-8dcf-1b19720af382","fa-file-alt",{"key":270,"_uid":271,"icon":272,"name":273,"component":264},"help_center_guide","b8fbc206-c083-471e-a1f0-0ebeb90a669d","fa-book","Guides",{"key":275,"_uid":276,"icon":277,"name":278,"component":264},"blog_post","23419e83-2e56-4c4c-8a05-9fd1b3c9a9bd","fa-file-image","Blog Posts","search",{"id":59,"alt":59,"name":13,"focus":59,"title":59,"source":59,"filename":13,"copyright":59,"fieldtype":81,"meta_data":281},{},"navigation\u002Fsearch",60,[],"11e1fd31-95cd-4fc9-b736-8b8910663e6c","2024-10-21T23:17:05.904Z",[],{"name":23,"created_at":289,"published_at":290,"updated_at":291,"id":292,"uuid":21,"content":293,"slug":307,"full_slug":22,"sort_by_date":59,"position":308,"tag_list":309,"is_startpage":33,"parent_id":310,"meta_data":59,"group_id":311,"first_published_at":312,"release_id":59,"lang":65,"path":59,"alternates":313,"default_full_slug":59,"translated_slugs":59},"2022-09-19T14:42:29.685Z","2024-07-30T18:17:22.506Z","2024-07-30T18:17:22.525Z",2660,{"_uid":294,"icon":13,"name":23,"guides":295,"pinned":24,"summary":296,"category":13,"component":297,"blog_posts":298,"content_hub":24,"icon_custom":299,"case_studies":300,"faq_sections":301,"help_articles":302,"featured_guides":303,"mailbox_category":13,"featured_articles":304,"featured_blog_posts":305,"featured_case_studies":306},"d6dae89a-907a-4bf7-82de-fe2ba875ee6e",[],"Get your questions answered with our browsable knowledge base.","help_center_category",[],{"id":59,"alt":59,"name":13,"focus":59,"title":59,"filename":13,"copyright":59,"fieldtype":81},[],[],[],[],[],[],[],"categories",530,[],2658,"19ebcdd2-027f-47f5-9a5b-a8992c959578","2022-09-19T16:24:39.219Z",[],{"name":315,"created_at":316,"published_at":317,"updated_at":318,"id":319,"uuid":320,"content":321,"slug":628,"full_slug":629,"sort_by_date":59,"position":630,"tag_list":631,"is_startpage":24,"parent_id":632,"meta_data":59,"group_id":633,"first_published_at":317,"release_id":59,"lang":65,"path":59,"alternates":634,"default_full_slug":59,"translated_slugs":59},"Verify a webhook payload","2026-07-20T20:06:10.920Z","2026-07-20T20:30:31.791Z","2026-07-20T20:30:31.819Z",200246767343464,"a98d0a09-b3dc-41f2-a242-f6baccce7733",{"_uid":322,"body":323,"name":315,"image":623,"pinned":24,"summary":625,"category":626,"component":266,"related_articles":627},"5c2f240a-4849-48df-ac66-4fbb3e3b2507",{"type":324,"content":325},"doc",[326,342,349,354,480,485,495,526,549,554,559,565,571,576,581,586,591,596,601,606],{"type":327,"attrs":328,"content":329},"paragraph",{"textAlign":59},[330,333,340],{"text":331,"type":332},"Once a webhook is configured, a JSON payload is sent to your endpoint whenever a subscribed event occurs. If your endpoint is secured with HTTPS, the payload is sent unencrypted, ready to use. If your endpoint isn’t secured, the payload is encrypted with AES-256-CBC before being sent, and will need to be decrypted before use — see ","text",{"text":334,"type":332,"marks":335},"Verify and decrypt a legacy webhook payload",[336],{"type":337,"attrs":338},"link",{"href":339,"uuid":59,"anchor":59,"target":59,"linktype":31},"https:\u002F\u002Ffoxy.io\u002Fhelp\u002Farticles\u002Fverify-and-decrypt-a-legacy-webhook-payload",{"text":341,"type":332}," for the decryption steps, which use the same method.",{"type":343,"attrs":344,"content":346},"heading",{"level":345,"textAlign":59},2,[347],{"text":348,"type":332},"Headers",{"type":327,"attrs":350,"content":351},{"textAlign":59},[352],{"text":353,"type":332},"Every webhook request includes these headers:",{"type":355,"content":356},"table",[357,378,400,420,440,460],{"type":358,"content":359},"tableRow",[360,370],{"type":361,"attrs":362,"content":364},"tableHeader",{"colspan":363,"rowspan":363,"colwidth":59},1,[365],{"type":327,"attrs":366,"content":367},{"textAlign":59},[368],{"text":369,"type":332},"Header",{"type":361,"attrs":371,"content":372},{"colspan":363,"rowspan":363,"colwidth":59},[373],{"type":327,"attrs":374,"content":375},{"textAlign":59},[376],{"text":377,"type":332},"Description",{"type":358,"content":379},[380,392],{"type":381,"attrs":382,"content":383},"tableCell",{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[384],{"type":327,"attrs":385,"content":386},{"textAlign":59},[387],{"text":388,"type":332,"marks":389},"Foxy-Webhook-Event",[390],{"type":391},"code",{"type":381,"attrs":393,"content":394},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[395],{"type":327,"attrs":396,"content":397},{"textAlign":59},[398],{"text":399,"type":332},"Name of the event that triggered this payload",{"type":358,"content":401},[402,412],{"type":381,"attrs":403,"content":404},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[405],{"type":327,"attrs":406,"content":407},{"textAlign":59},[408],{"text":409,"type":332,"marks":410},"Foxy-Webhook-Signature",[411],{"type":391},{"type":381,"attrs":413,"content":414},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[415],{"type":327,"attrs":416,"content":417},{"textAlign":59},[418],{"text":419,"type":332},"An HMAC SHA256 signature of the payload, using the webhook’s encryption key. Used to verify the contents of the payload",{"type":358,"content":421},[422,432],{"type":381,"attrs":423,"content":424},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[425],{"type":327,"attrs":426,"content":427},{"textAlign":59},[428],{"text":429,"type":332,"marks":430},"Foxy-Webhook-Refeed",[431],{"type":391},{"type":381,"attrs":433,"content":434},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[435],{"type":327,"attrs":436,"content":437},{"textAlign":59},[438],{"text":439,"type":332},"A boolean signifying whether this payload has been refed. If false, this is the first time this instance of the event has been triggered",{"type":358,"content":441},[442,452],{"type":381,"attrs":443,"content":444},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[445],{"type":327,"attrs":446,"content":447},{"textAlign":59},[448],{"text":449,"type":332,"marks":450},"Foxy-Store-ID",[451],{"type":391},{"type":381,"attrs":453,"content":454},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[455],{"type":327,"attrs":456,"content":457},{"textAlign":59},[458],{"text":459,"type":332},"The ID of the store this webhook was triggered for",{"type":358,"content":461},[462,472],{"type":381,"attrs":463,"content":464},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[465],{"type":327,"attrs":466,"content":467},{"textAlign":59},[468],{"text":469,"type":332,"marks":470},"Foxy-Store-Domain",[471],{"type":391},{"type":381,"attrs":473,"content":474},{"colspan":363,"rowspan":363,"colwidth":59,"backgroundColor":59},[475],{"type":327,"attrs":476,"content":477},{"textAlign":59},[478],{"text":479,"type":332},"The store domain this webhook was triggered for",{"type":343,"attrs":481,"content":482},{"level":345,"textAlign":59},[483],{"text":484,"type":332},"Validating the signature",{"type":327,"attrs":486,"content":487},{"textAlign":59},[488,490,493],{"text":489,"type":332},"Using the encryption key associated with the webhook, a signature of the payload is generated and passed as the ",{"text":409,"type":332,"marks":491},[492],{"type":391},{"text":494,"type":332}," header. To validate a request on your endpoint:",{"type":496,"attrs":497,"content":498},"ordered_list",{"order":363},[499,507,514],{"type":500,"content":501},"list_item",[502],{"type":327,"attrs":503,"content":504},{"textAlign":59},[505],{"text":506,"type":332},"Generate an HMAC SHA256 hash of the raw request body, using the webhook’s encryption key.",{"type":500,"content":508},[509],{"type":327,"attrs":510,"content":511},{"textAlign":59},[512],{"text":513,"type":332},"Format the result as a hexadecimal string.",{"type":500,"content":515},[516],{"type":327,"attrs":517,"content":518},{"textAlign":59},[519,521,524],{"text":520,"type":332},"Perform a secure comparison of your generated signature against the ",{"text":409,"type":332,"marks":522},[523],{"type":391},{"text":525,"type":332}," header value.",{"type":327,"attrs":527,"content":528},{"textAlign":59},[529,531,535,537,541,543,547],{"text":530,"type":332},"Always use a secure\u002Fconstant-time comparison function for this step — ",{"text":532,"type":332,"marks":533},"hash_equals()",[534],{"type":391},{"text":536,"type":332}," in PHP 5.6+, ",{"text":538,"type":332,"marks":539},"secure_compare()",[540],{"type":391},{"text":542,"type":332}," in Ruby — rather than a direct ",{"text":544,"type":332,"marks":545},"==",[546],{"type":391},{"text":548,"type":332}," comparison.",{"type":343,"attrs":550,"content":551},{"level":345,"textAlign":59},[552],{"text":553,"type":332},"Example endpoints",{"type":327,"attrs":555,"content":556},{"textAlign":59},[557],{"text":558,"type":332},"The following examples validate the payload signature and handle the parsed JSON.",{"type":343,"attrs":560,"content":562},{"level":561,"textAlign":59},3,[563],{"text":564,"type":332},"PHP",{"type":566,"attrs":567,"content":568},"code_block",{"class":59},[569],{"text":570,"type":332},"\u003C?php\n\ndefine('FOXY_WEBHOOK_ENCRYPTION_KEY', 'ABC123');\n\n$data = file_get_contents('php:\u002F\u002Finput');\n$parsedData = json_decode($data, true);\n$event = $_SERVER['HTTP_FOXY_WEBHOOK_EVENT'];\n\n\u002F\u002F Verify the webhook payload\n$signature = hash_hmac('sha256', $data, FOXY_WEBHOOK_ENCRYPTION_KEY);\nif (!hash_equals($signature, $_SERVER['HTTP_FOXY_WEBHOOK_SIGNATURE'])) {\n    echo \"Signature verification failed - data corrupted\";\n    http_response_code(500);\n    return;\n}\n\nif (is_array($parsedData)) {\n    \u002F\u002F Handle the payload\n\n    if ($event == \"transaction\u002Fcreated\") {\n        \u002F\u002F Example of working with the transaction\u002Fcreated payload\n        $email_address = $parsedData['customer_email'];\n        $billing_country = $parsedData['_embedded']['fx:billing_addresses']['country'];\n        $shipping_country = $parsedData['_embedded']['fx:shipments'][0]['country']; \u002F\u002F Assuming single-ship\n\n        $has_small_product_a = false;\n        $has_large_product_a = false;\n\n        foreach ($parsedData['_embedded']['fx:items'] as $item) {\n            $name = $item['name'];\n            $quantity = $item['quantity'];\n            $category = $item['_embedded']['fx:item_category']['code'];\n\n            if ($item['name'] == \"Product A\") {\n                foreach($item['_embedded']['fx:item_options'] as $item_option) {\n                    if ($item_option['name'] == \"size\") {\n                        if ($item_option['value'] == \"small\") {\n                            $has_small_product_a = true;\n                        } else if ($item_option['value'] == \"large\") {\n                            $has_large_product_a = true;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n} else {\n    \u002F\u002F JSON data not found\n    echo(\"No data\");\n    http_response_code(500);\n    return;\n}\n",{"type":343,"attrs":572,"content":573},{"level":561,"textAlign":59},[574],{"text":575,"type":332},"Node",{"type":327,"attrs":577,"content":578},{"textAlign":59},[579],{"text":580,"type":332},"You can also use the official SDK to make pieces of this easier, but this example uses minimal dependencies:",{"type":566,"attrs":582,"content":583},{"class":59},[584],{"text":585,"type":332},"const crypto = require('crypto');\nconst foxyEncryptionKey = 'YOUR_ENCRYPTION_KEY_HERE';\nconst foxyStoreId = 'YOUR_STORE_ID_HERE';\nconst foxyStoreDomain = 'YOUR_STORE_DOMAIN_HERE';\n\nconst http = require('http');\nconst server = http.createServer(handleRequest);\n\nconst routes = {\n  'transaction\u002Fcreated': handleTransactionCreated,\n}\n\nfunction handleRequest(request, response) {\n  if (!validFoxyRequest(request)) {\n    response.statusCode = 403; \u002F\u002F Forbidden\n    response.write('Forbidden');\n    return response.end();\n  }\n  const bodyChunks = [];\n\n  request.on('data', (chunk) => bodyChunks.push(chunk));\n  request.on('end', () => {\n    let body = Buffer.concat(bodyChunks).toString()\n    if (!validFoxySignature(request.headers['foxy-webhook-signature'], body)){\n      response.statusCode = 403; \u002F\u002F Forbidden\n      response.write('Forbidden');\n      return response.end();\n    }\n    try {\n      body = JSON.parse(body);\n    } catch(e) {\n      response.statusCode = 400; \u002F\u002F Bad Request\n      response.write('Bad Request');\n      return response.end();\n    }\n    const foxyEvent = request.headers['foxy-webhook-event'];\n    const responseData = routes[foxyEvent](request.headers, body);\n    console.log(responseData);\n    if (responseData) {\n      response.statusCode = 200;\n      response.write(JSON.stringify(responseData));\n      return response.end();\n    }\n    response.statusCode = 500;\n    response.end();\n  });\n}\n\nfunction validFoxyRequest(request) {\n  const postMethod = request.method === 'POST';\n  const headers = request.headers;\n  const routeForEventExists = Object.keys(routes).includes(headers['foxy-webhook-event']);\n  const foxySignatureExists = !!headers['foxy-webhook-signature'];\n  const foxyStoreIdIsCorrect = headers['foxy-store-id'] === foxyStoreId;\n  const foxyStoreDomainIsCorrect = headers['foxy-store-domain'] === foxyStoreDomain;\n  return postMethod && routeForEventExists && foxySignatureExists && foxyStoreIdIsCorrect && foxyStoreDomainIsCorrect;\n}\n\nfunction validFoxySignature(signature, payload) {\n  const referenceSignature = crypto.createHmac('sha256', foxyEncryptionKey).update(payload).digest('hex');\n  console.log(referenceSignature);\n  return signature === referenceSignature;\n}\n\nfunction handleTransactionCreated(headers, body) {\n  const emailAddress = body['customer_email'];\n  const billingCountry = body['_embedded']['fx:billing_addresses']['country'];\n  const shippingCountry = body['_embedded']['fx:shipments'][0]['country'];\n  \u002F\u002F Check if there is a Product A and its size\n  let hasSmallA = false;\n  let hasLargeA = false;\n  for (let item of body['_embedded']['fx:items']) {\n    const name = item['name'];\n    const quantity = item['quantity'];\n    const category = item['_embedded']['fx:item_category']['code'];\n    if(item['name'] === \"Product A\") {\n      for (let itemOption of item['_embedded']['fx:item_options']) {\n        if (itemOption['name'] == 'size') {\n          if (itemOption['value'] === 'small') {\n            hasSmallA = true;\n            return {\n              ok: true,\n              details: \"has small A\"\n            }\n          } else if (itemOption['value'] === 'large') {\n            hasLargeA = true;\n            return {\n              ok: true,\n              details: \"has large A\"\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\nserver.listen(80);\n",{"type":343,"attrs":587,"content":588},{"level":561,"textAlign":59},[589],{"text":590,"type":332},"Ruby",{"type":327,"attrs":592,"content":593},{"textAlign":59},[594],{"text":595,"type":332},"This example uses a small Sinatra app — some logic may need adjusting for a different framework.",{"type":566,"attrs":597,"content":598},{"class":59},[599],{"text":600,"type":332},"require 'sinatra'\nrequire 'json'\n\ndef verify_webhook(data, encryption_key)\n    signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), encryption_key, data)\n    return halt 500, \"Signature verification failed - data corrupted\" unless Rack::Utils.secure_compare(signature, request.env['HTTP_FOXY_WEBHOOK_SIGNATURE'])\nend\n\npost '\u002Fwebhook' do\n    request.body.rewind\n    data = request.body.read\n    event = request.env['HTTP_FOXY_WEBHOOK_EVENT']\n    verify_webhook(data, ENV['FOXY_WEBHOOK_ENCRYPTION_KEY'])\n\n    parsedData = JSON.parse(data)\n\n    # Handle the payload\n    puts parsedData['id']\nend\n",{"type":343,"attrs":602,"content":603},{"level":345,"textAlign":59},[604],{"text":605,"type":332},"Notes",{"type":607,"content":608},"bullet_list",[609,616],{"type":500,"content":610},[611],{"type":327,"attrs":612,"content":613},{"textAlign":59},[614],{"text":615,"type":332},"Avoid storing your webhook encryption key directly in your codebase — store it as an environment variable instead.",{"type":500,"content":617},[618],{"type":327,"attrs":619,"content":620},{"textAlign":59},[621],{"text":622,"type":332},"When comparing signatures, always use a secure\u002Fconstant-time comparison method rather than a direct equality check.",{"id":59,"alt":59,"name":13,"focus":59,"title":59,"source":59,"filename":13,"copyright":59,"fieldtype":81,"meta_data":624},{},"How to confirm a webhook request came from Foxy using the payload signature, with example endpoint code in PHP, Node, and Ruby.","7234dbeb-44d4-4b3c-b847-8791cf974ff7",[],"verify-a-webhook-payload","help\u002Farticles\u002Fverify-a-webhook-payload",-3880,[],2659,"192a6877-2dc3-471f-9ca7-b1331f0bf59b",[],{"html":636,"sections":637,"segments":654},"\u003Cp>Once a webhook is configured, a JSON payload is sent to your endpoint whenever a subscribed event occurs. If your endpoint is secured with HTTPS, the payload is sent unencrypted, ready to use. If your endpoint isn’t secured, the payload is encrypted with AES-256-CBC before being sent, and will need to be decrypted before use — see \u003Ca href=\"https:\u002F\u002Ffoxy.io\u002Fhelp\u002Farticles\u002Fverify-and-decrypt-a-legacy-webhook-payload\" class=\"\">Verify and decrypt a legacy webhook payload\u003C\u002Fa> for the decryption steps, which use the same method.\u003C\u002Fp>\u003Csection id=\"headers\" data-title=\"Headers\" data-title-node=\"H2\">\u003Chr class=\"my-8\" style=\"margin-left: -48px; margin-right: -40vw\">\u003Ch2 data-anchor-id=\"headers\">Headers\u003C\u002Fh2>\u003Cp>Every webhook request includes these headers:\u003C\u002Fp>\u003Cdiv class=\"table-responsive w-100\">\u003Ctable class=\"table table-lg table-bordered my-5\">\u003Cthead class=\"thead-light\">\u003Ctr>\u003Cth>\u003Cp>Header\u003C\u002Fp>\u003C\u002Fth>\u003Cth>\u003Cp>Description\u003C\u002Fp>\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Event\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>Name of the event that triggered this payload\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Signature\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>An HMAC SHA256 signature of the payload, using the webhook’s encryption key. Used to verify the contents of the payload\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Refeed\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>A boolean signifying whether this payload has been refed. If false, this is the first time this instance of the event has been triggered\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Store-ID\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>The ID of the store this webhook was triggered for\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Store-Domain\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>The store domain this webhook was triggered for\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\u003C\u002Fsection>\u003Csection id=\"validating-the-signature\" data-title=\"Validating the signature\" data-title-node=\"H2\">\u003Chr class=\"my-8\" style=\"margin-left: -48px; margin-right: -40vw\">\u003Ch2 data-anchor-id=\"validating-the-signature\">Validating the signature\u003C\u002Fh2>\u003Cp>Using the encryption key associated with the webhook, a signature of the payload is generated and passed as the \u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Signature\u003C\u002Fcode> header. To validate a request on your endpoint:\u003C\u002Fp>\u003Col class=\"step step-icon-sm step-dashed step-border-last-0 mt-3\">\u003Cli class=\"step-item\">\u003Cdiv class=\"step-content-wrapper\">\u003Cspan class=\"step-icon step-icon-soft-primary\">1\u003C\u002Fspan>\u003Cdiv class=\"w-100 overflow-hidden\">\u003Cdiv class=\"step-content mt-2\">\u003Cp>Generate an HMAC SHA256 hash of the raw request body, using the webhook’s encryption key.\u003C\u002Fp>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fli>\u003Cli class=\"step-item\">\u003Cdiv class=\"step-content-wrapper\">\u003Cspan class=\"step-icon step-icon-soft-primary\">2\u003C\u002Fspan>\u003Cdiv class=\"w-100 overflow-hidden\">\u003Cdiv class=\"step-content mt-2\">\u003Cp>Format the result as a hexadecimal string.\u003C\u002Fp>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fli>\u003Cli class=\"step-item\">\u003Cdiv class=\"step-content-wrapper\">\u003Cspan class=\"step-icon step-icon-soft-primary\">3\u003C\u002Fspan>\u003Cdiv class=\"w-100 overflow-hidden\">\u003Cdiv class=\"step-content mt-2\">\u003Cp>Perform a secure comparison of your generated signature against the \u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Signature\u003C\u002Fcode> header value.\u003C\u002Fp>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fli>\u003C\u002Fol>\u003Cp>Always use a secure\u002Fconstant-time comparison function for this step — \u003Ccode class=\"badge bg-soft-danger text-danger\">hash_equals()\u003C\u002Fcode> in PHP 5.6+, \u003Ccode class=\"badge bg-soft-danger text-danger\">secure_compare()\u003C\u002Fcode> in Ruby — rather than a direct \u003Ccode class=\"badge bg-soft-danger text-danger\">==\u003C\u002Fcode> comparison.\u003C\u002Fp>\u003C\u002Fsection>\u003Csection id=\"example-endpoints\" data-title=\"Example endpoints\" data-title-node=\"H2\">\u003Chr class=\"my-8\" style=\"margin-left: -48px; margin-right: -40vw\">\u003Ch2 data-anchor-id=\"example-endpoints\">Example endpoints\u003C\u002Fh2>\u003Cp>The following examples validate the payload signature and handle the parsed JSON.\u003C\u002Fp>\u003C\u002Fsection>\u003Csection id=\"php\" data-title=\"PHP\" data-title-node=\"H3\">\u003Ch3 data-anchor-id=\"php\">PHP\u003C\u002Fh3>\u003Cdiv class=\"position-relative w-100 overflow-hidden rounded-2\" data-code-block>\u003Cdiv class=\"d-flex justify-content-end border-bottom\" style=\"background:#2b2c3b;\">\u003Cbutton type=\"button\" class=\"btn btn-link btn-sm text-light\" title=\"Copy\" data-code-button>\u003Cspan data-code-default style=\"\">\u003Ci class=\"fal fa-copy me-2\">\u003C\u002Fi> Copy \u003C\u002Fspan>\u003Cspan class=\"text-success\" data-code-success style=\"display:none;\">\u003Ci class=\"fal fa-check ms-2\">\u003C\u002Fi> Copied \u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cdiv class=\"small\">\u003Cpre class=\"hljs p-2\" data-code-content>\u003Cspan class=\"hljs-meta\">&lt;?php\n\ndefine(&#x27;FOXY_WEBHOOK_ENCRYPTION_KEY&#x27;, &#x27;ABC123&#x27;);\n\n$data = file_get_contents(&#x27;php:\u002F\u002Finput&#x27;);\n$parsedData = json_decode($data, true);\n$event = $_SERVER[&#x27;HTTP_FOXY_WEBHOOK_EVENT&#x27;];\n\n\u002F\u002F Verify the webhook payload\n$signature = hash_hmac(&#x27;sha256&#x27;, $data, FOXY_WEBHOOK_ENCRYPTION_KEY);\nif (!hash_equals($signature, $_SERVER[&#x27;HTTP_FOXY_WEBHOOK_SIGNATURE&#x27;])) {\n    echo &quot;Signature verification failed - data corrupted&quot;;\n    http_response_code(500);\n    return;\n}\n\nif (is_array($parsedData)) {\n    \u002F\u002F Handle the payload\n\n    if ($event == &quot;transaction\u002Fcreated&quot;) {\n        \u002F\u002F Example of working with the transaction\u002Fcreated payload\n        $email_address = $parsedData[&#x27;customer_email&#x27;];\n        $billing_country = $parsedData[&#x27;_embedded&#x27;][&#x27;fx:billing_addresses&#x27;][&#x27;country&#x27;];\n        $shipping_country = $parsedData[&#x27;_embedded&#x27;][&#x27;fx:shipments&#x27;][0][&#x27;country&#x27;]; \u002F\u002F Assuming single-ship\n\n        $has_small_product_a = false;\n        $has_large_product_a = false;\n\n        foreach ($parsedData[&#x27;_embedded&#x27;][&#x27;fx:items&#x27;] as $item) {\n            $name = $item[&#x27;name&#x27;];\n            $quantity = $item[&#x27;quantity&#x27;];\n            $category = $item[&#x27;_embedded&#x27;][&#x27;fx:item_category&#x27;][&#x27;code&#x27;];\n\n            if ($item[&#x27;name&#x27;] == &quot;Product A&quot;) {\n                foreach($item[&#x27;_embedded&#x27;][&#x27;fx:item_options&#x27;] as $item_option) {\n                    if ($item_option[&#x27;name&#x27;] == &quot;size&quot;) {\n                        if ($item_option[&#x27;value&#x27;] == &quot;small&quot;) {\n                            $has_small_product_a = true;\n                        } else if ($item_option[&#x27;value&#x27;] == &quot;large&quot;) {\n                            $has_large_product_a = true;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n} else {\n    \u002F\u002F JSON data not found\n    echo(&quot;No data&quot;);\n    http_response_code(500);\n    return;\n}\n\u003C\u002Fspan>\u003C\u002Fpre>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fsection>\u003Csection id=\"node\" data-title=\"Node\" data-title-node=\"H3\">\u003Ch3 data-anchor-id=\"node\">Node\u003C\u002Fh3>\u003Cp>You can also use the official SDK to make pieces of this easier, but this example uses minimal dependencies:\u003C\u002Fp>\u003Cdiv class=\"position-relative w-100 overflow-hidden rounded-2\" data-code-block>\u003Cdiv class=\"d-flex justify-content-end border-bottom\" style=\"background:#2b2c3b;\">\u003Cbutton type=\"button\" class=\"btn btn-link btn-sm text-light\" title=\"Copy\" data-code-button>\u003Cspan data-code-default style=\"\">\u003Ci class=\"fal fa-copy me-2\">\u003C\u002Fi> Copy \u003C\u002Fspan>\u003Cspan class=\"text-success\" data-code-success style=\"display:none;\">\u003Ci class=\"fal fa-check ms-2\">\u003C\u002Fi> Copied \u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cdiv class=\"small\">\u003Cpre class=\"hljs p-2\" data-code-content>const crypto = require(&#x27;crypto&#x27;);\nconst foxyEncryptionKey = &#x27;YOUR_ENCRYPTION_KEY_HERE&#x27;;\nconst foxyStoreId = &#x27;YOUR_STORE_ID_HERE&#x27;;\nconst foxyStoreDomain = &#x27;YOUR_STORE_DOMAIN_HERE&#x27;;\n\nconst http = require(&#x27;http&#x27;);\nconst server = http.createServer(handleRequest);\n\nconst routes = {\n  &#x27;transaction\u002Fcreated&#x27;: handleTransactionCreated,\n}\n\nfunction handleRequest(request, response) {\n  if (!validFoxyRequest(request)) {\n    response.statusCode = 403; \u002F\u002F Forbidden\n    response.write(&#x27;Forbidden&#x27;);\n    return response.end();\n  }\n  const bodyChunks = [];\n\n  request.on(&#x27;data&#x27;, (chunk) =&gt; bodyChunks.push(chunk));\n  request.on(&#x27;end&#x27;, () =&gt; {\n    let body = Buffer.concat(bodyChunks).toString()\n    if (!validFoxySignature(request.headers[&#x27;foxy-webhook-signature&#x27;], body)){\n      response.statusCode = 403; \u002F\u002F Forbidden\n      response.write(&#x27;Forbidden&#x27;);\n      return response.end();\n    }\n    try {\n      body = JSON.parse(body);\n    } catch(e) {\n      response.statusCode = 400; \u002F\u002F Bad Request\n      response.write(&#x27;Bad Request&#x27;);\n      return response.end();\n    }\n    const foxyEvent = request.headers[&#x27;foxy-webhook-event&#x27;];\n    const responseData = routes[foxyEvent](request.headers, body);\n    console.log(responseData);\n    if (responseData) {\n      response.statusCode = 200;\n      response.write(JSON.stringify(responseData));\n      return response.end();\n    }\n    response.statusCode = 500;\n    response.end();\n  });\n}\n\nfunction validFoxyRequest(request) {\n  const postMethod = request.method === &#x27;POST&#x27;;\n  const headers = request.headers;\n  const routeForEventExists = Object.keys(routes).includes(headers[&#x27;foxy-webhook-event&#x27;]);\n  const foxySignatureExists = !!headers[&#x27;foxy-webhook-signature&#x27;];\n  const foxyStoreIdIsCorrect = headers[&#x27;foxy-store-id&#x27;] === foxyStoreId;\n  const foxyStoreDomainIsCorrect = headers[&#x27;foxy-store-domain&#x27;] === foxyStoreDomain;\n  return postMethod &amp;&amp; routeForEventExists &amp;&amp; foxySignatureExists &amp;&amp; foxyStoreIdIsCorrect &amp;&amp; foxyStoreDomainIsCorrect;\n}\n\nfunction validFoxySignature(signature, payload) {\n  const referenceSignature = crypto.createHmac(&#x27;sha256&#x27;, foxyEncryptionKey).update(payload).digest(&#x27;hex&#x27;);\n  console.log(referenceSignature);\n  return signature === referenceSignature;\n}\n\nfunction handleTransactionCreated(headers, body) {\n  const emailAddress = body[&#x27;customer_email&#x27;];\n  const billingCountry = body[&#x27;_embedded&#x27;][&#x27;fx:billing_addresses&#x27;][&#x27;country&#x27;];\n  const shippingCountry = body[&#x27;_embedded&#x27;][&#x27;fx:shipments&#x27;][0][&#x27;country&#x27;];\n  \u002F\u002F Check if there is a Product A and its size\n  let hasSmallA = false;\n  let hasLargeA = false;\n  for (let item of body[&#x27;_embedded&#x27;][&#x27;fx:items&#x27;]) {\n    const name = item[&#x27;name&#x27;];\n    const quantity = item[&#x27;quantity&#x27;];\n    const category = item[&#x27;_embedded&#x27;][&#x27;fx:item_category&#x27;][&#x27;code&#x27;];\n    if(item[&#x27;name&#x27;] === &quot;Product A&quot;) {\n      for (let itemOption of item[&#x27;_embedded&#x27;][&#x27;fx:item_options&#x27;]) {\n        if (itemOption[&#x27;name&#x27;] == &#x27;size&#x27;) {\n          if (itemOption[&#x27;value&#x27;] === &#x27;small&#x27;) {\n            hasSmallA = true;\n            return {\n              ok: true,\n              details: &quot;has small A&quot;\n            }\n          } else if (itemOption[&#x27;value&#x27;] === &#x27;large&#x27;) {\n            hasLargeA = true;\n            return {\n              ok: true,\n              details: &quot;has large A&quot;\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\nserver.listen(80);\n\u003C\u002Fpre>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fsection>\u003Csection id=\"ruby\" data-title=\"Ruby\" data-title-node=\"H3\">\u003Ch3 data-anchor-id=\"ruby\">Ruby\u003C\u002Fh3>\u003Cp>This example uses a small Sinatra app — some logic may need adjusting for a different framework.\u003C\u002Fp>\u003Cdiv class=\"position-relative w-100 overflow-hidden rounded-2\" data-code-block>\u003Cdiv class=\"d-flex justify-content-end border-bottom\" style=\"background:#2b2c3b;\">\u003Cbutton type=\"button\" class=\"btn btn-link btn-sm text-light\" title=\"Copy\" data-code-button>\u003Cspan data-code-default style=\"\">\u003Ci class=\"fal fa-copy me-2\">\u003C\u002Fi> Copy \u003C\u002Fspan>\u003Cspan class=\"text-success\" data-code-success style=\"display:none;\">\u003Ci class=\"fal fa-check ms-2\">\u003C\u002Fi> Copied \u003C\u002Fspan>\u003C\u002Fbutton>\u003C\u002Fdiv>\u003Cdiv class=\"small\">\u003Cpre class=\"hljs p-2\" data-code-content>require &#x27;sinatra&#x27;\nrequire &#x27;json&#x27;\n\ndef verify_webhook(data, encryption_key)\n    signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new(&#x27;sha256&#x27;), encryption_key, data)\n    return halt 500, &quot;Signature verification failed - data corrupted&quot; unless Rack::Utils.secure_compare(signature, request.env[&#x27;HTTP_FOXY_WEBHOOK_SIGNATURE&#x27;])\nend\n\npost &#x27;\u002Fwebhook&#x27; do\n    request.body.rewind\n    data = request.body.read\n    event = request.env[&#x27;HTTP_FOXY_WEBHOOK_EVENT&#x27;]\n    verify_webhook(data, ENV[&#x27;FOXY_WEBHOOK_ENCRYPTION_KEY&#x27;])\n\n    parsedData = JSON.parse(data)\n\n    # Handle the payload\n    puts parsedData[&#x27;id&#x27;]\nend\n\u003C\u002Fpre>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fsection>\u003Csection id=\"notes\" data-title=\"Notes\" data-title-node=\"H2\">\u003Chr class=\"my-8\" style=\"margin-left: -48px; margin-right: -40vw\">\u003Ch2 data-anchor-id=\"notes\">Notes\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Cp>Avoid storing your webhook encryption key directly in your codebase — store it as an environment variable instead.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>When comparing signatures, always use a secure\u002Fconstant-time comparison method rather than a direct equality check.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003C\u002Fsection>",[638,641,643,645,648,650,652],{"id":639,"title":348,"level":640},"headers","H2",{"id":642,"title":484,"level":640},"validating-the-signature",{"id":644,"title":553,"level":640},"example-endpoints",{"id":646,"title":564,"level":647},"php","H3",{"id":649,"title":575,"level":647},"node",{"id":651,"title":590,"level":647},"ruby",{"id":653,"title":605,"level":640},"notes",[655],{"type":656,"content":657},"html","\u003Cp>Once a webhook is configured, a JSON payload is sent to your endpoint whenever a subscribed event occurs. If your endpoint is secured with HTTPS, the payload is sent unencrypted, ready to use. If your endpoint isn’t secured, the payload is encrypted with AES-256-CBC before being sent, and will need to be decrypted before use — see \u003Ca href=\"https:\u002F\u002Ffoxy.io\u002Fhelp\u002Farticles\u002Fverify-and-decrypt-a-legacy-webhook-payload\" class=\"\">Verify and decrypt a legacy webhook payload\u003C\u002Fa> for the decryption steps, which use the same method.\u003C\u002Fp>\u003Ch2>Headers\u003C\u002Fh2>\u003Cp>Every webhook request includes these headers:\u003C\u002Fp>\u003Cdiv class=\"table-responsive w-100\">\u003Ctable class=\"table table-lg table-bordered my-5\">\u003Cthead>\u003Ctr>\u003Cth>\u003Cp>Header\u003C\u002Fp>\u003C\u002Fth>\u003Cth>\u003Cp>Description\u003C\u002Fp>\u003C\u002Fth>\u003C\u002Ftr>\u003C\u002Fthead>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Event\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>Name of the event that triggered this payload\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Signature\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>An HMAC SHA256 signature of the payload, using the webhook’s encryption key. Used to verify the contents of the payload\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Refeed\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>A boolean signifying whether this payload has been refed. If false, this is the first time this instance of the event has been triggered\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Store-ID\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>The ID of the store this webhook was triggered for\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003Ctr>\u003Ctd>\u003Cp>\u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Store-Domain\u003C\u002Fcode>\u003C\u002Fp>\u003C\u002Ftd>\u003Ctd>\u003Cp>The store domain this webhook was triggered for\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003C\u002Fdiv>\u003Ch2>Validating the signature\u003C\u002Fh2>\u003Cp>Using the encryption key associated with the webhook, a signature of the payload is generated and passed as the \u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Signature\u003C\u002Fcode> header. To validate a request on your endpoint:\u003C\u002Fp>\u003Col order=\"1\">\u003Cli>\u003Cp>Generate an HMAC SHA256 hash of the raw request body, using the webhook’s encryption key.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>Format the result as a hexadecimal string.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>Perform a secure comparison of your generated signature against the \u003Ccode class=\"badge bg-soft-danger text-danger\">Foxy-Webhook-Signature\u003C\u002Fcode> header value.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Fol>\u003Cp>Always use a secure\u002Fconstant-time comparison function for this step — \u003Ccode class=\"badge bg-soft-danger text-danger\">hash_equals()\u003C\u002Fcode> in PHP 5.6+, \u003Ccode class=\"badge bg-soft-danger text-danger\">secure_compare()\u003C\u002Fcode> in Ruby — rather than a direct \u003Ccode class=\"badge bg-soft-danger text-danger\">==\u003C\u002Fcode> comparison.\u003C\u002Fp>\u003Ch2>Example endpoints\u003C\u002Fh2>\u003Cp>The following examples validate the payload signature and handle the parsed JSON.\u003C\u002Fp>\u003Ch3>PHP\u003C\u002Fh3>\u003Cpre>\u003Ccode>&lt;?php\n\ndefine(&#039;FOXY_WEBHOOK_ENCRYPTION_KEY&#039;, &#039;ABC123&#039;);\n\n$data = file_get_contents(&#039;php:\u002F\u002Finput&#039;);\n$parsedData = json_decode($data, true);\n$event = $_SERVER[&#039;HTTP_FOXY_WEBHOOK_EVENT&#039;];\n\n\u002F\u002F Verify the webhook payload\n$signature = hash_hmac(&#039;sha256&#039;, $data, FOXY_WEBHOOK_ENCRYPTION_KEY);\nif (!hash_equals($signature, $_SERVER[&#039;HTTP_FOXY_WEBHOOK_SIGNATURE&#039;])) {\n    echo &quot;Signature verification failed - data corrupted&quot;;\n    http_response_code(500);\n    return;\n}\n\nif (is_array($parsedData)) {\n    \u002F\u002F Handle the payload\n\n    if ($event == &quot;transaction\u002Fcreated&quot;) {\n        \u002F\u002F Example of working with the transaction\u002Fcreated payload\n        $email_address = $parsedData[&#039;customer_email&#039;];\n        $billing_country = $parsedData[&#039;_embedded&#039;][&#039;fx:billing_addresses&#039;][&#039;country&#039;];\n        $shipping_country = $parsedData[&#039;_embedded&#039;][&#039;fx:shipments&#039;][0][&#039;country&#039;]; \u002F\u002F Assuming single-ship\n\n        $has_small_product_a = false;\n        $has_large_product_a = false;\n\n        foreach ($parsedData[&#039;_embedded&#039;][&#039;fx:items&#039;] as $item) {\n            $name = $item[&#039;name&#039;];\n            $quantity = $item[&#039;quantity&#039;];\n            $category = $item[&#039;_embedded&#039;][&#039;fx:item_category&#039;][&#039;code&#039;];\n\n            if ($item[&#039;name&#039;] == &quot;Product A&quot;) {\n                foreach($item[&#039;_embedded&#039;][&#039;fx:item_options&#039;] as $item_option) {\n                    if ($item_option[&#039;name&#039;] == &quot;size&quot;) {\n                        if ($item_option[&#039;value&#039;] == &quot;small&quot;) {\n                            $has_small_product_a = true;\n                        } else if ($item_option[&#039;value&#039;] == &quot;large&quot;) {\n                            $has_large_product_a = true;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n} else {\n    \u002F\u002F JSON data not found\n    echo(&quot;No data&quot;);\n    http_response_code(500);\n    return;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Node\u003C\u002Fh3>\u003Cp>You can also use the official SDK to make pieces of this easier, but this example uses minimal dependencies:\u003C\u002Fp>\u003Cpre>\u003Ccode>const crypto = require(&#039;crypto&#039;);\nconst foxyEncryptionKey = &#039;YOUR_ENCRYPTION_KEY_HERE&#039;;\nconst foxyStoreId = &#039;YOUR_STORE_ID_HERE&#039;;\nconst foxyStoreDomain = &#039;YOUR_STORE_DOMAIN_HERE&#039;;\n\nconst http = require(&#039;http&#039;);\nconst server = http.createServer(handleRequest);\n\nconst routes = {\n  &#039;transaction\u002Fcreated&#039;: handleTransactionCreated,\n}\n\nfunction handleRequest(request, response) {\n  if (!validFoxyRequest(request)) {\n    response.statusCode = 403; \u002F\u002F Forbidden\n    response.write(&#039;Forbidden&#039;);\n    return response.end();\n  }\n  const bodyChunks = [];\n\n  request.on(&#039;data&#039;, (chunk) =&gt; bodyChunks.push(chunk));\n  request.on(&#039;end&#039;, () =&gt; {\n    let body = Buffer.concat(bodyChunks).toString()\n    if (!validFoxySignature(request.headers[&#039;foxy-webhook-signature&#039;], body)){\n      response.statusCode = 403; \u002F\u002F Forbidden\n      response.write(&#039;Forbidden&#039;);\n      return response.end();\n    }\n    try {\n      body = JSON.parse(body);\n    } catch(e) {\n      response.statusCode = 400; \u002F\u002F Bad Request\n      response.write(&#039;Bad Request&#039;);\n      return response.end();\n    }\n    const foxyEvent = request.headers[&#039;foxy-webhook-event&#039;];\n    const responseData = routes[foxyEvent](request.headers, body);\n    console.log(responseData);\n    if (responseData) {\n      response.statusCode = 200;\n      response.write(JSON.stringify(responseData));\n      return response.end();\n    }\n    response.statusCode = 500;\n    response.end();\n  });\n}\n\nfunction validFoxyRequest(request) {\n  const postMethod = request.method === &#039;POST&#039;;\n  const headers = request.headers;\n  const routeForEventExists = Object.keys(routes).includes(headers[&#039;foxy-webhook-event&#039;]);\n  const foxySignatureExists = !!headers[&#039;foxy-webhook-signature&#039;];\n  const foxyStoreIdIsCorrect = headers[&#039;foxy-store-id&#039;] === foxyStoreId;\n  const foxyStoreDomainIsCorrect = headers[&#039;foxy-store-domain&#039;] === foxyStoreDomain;\n  return postMethod &amp;&amp; routeForEventExists &amp;&amp; foxySignatureExists &amp;&amp; foxyStoreIdIsCorrect &amp;&amp; foxyStoreDomainIsCorrect;\n}\n\nfunction validFoxySignature(signature, payload) {\n  const referenceSignature = crypto.createHmac(&#039;sha256&#039;, foxyEncryptionKey).update(payload).digest(&#039;hex&#039;);\n  console.log(referenceSignature);\n  return signature === referenceSignature;\n}\n\nfunction handleTransactionCreated(headers, body) {\n  const emailAddress = body[&#039;customer_email&#039;];\n  const billingCountry = body[&#039;_embedded&#039;][&#039;fx:billing_addresses&#039;][&#039;country&#039;];\n  const shippingCountry = body[&#039;_embedded&#039;][&#039;fx:shipments&#039;][0][&#039;country&#039;];\n  \u002F\u002F Check if there is a Product A and its size\n  let hasSmallA = false;\n  let hasLargeA = false;\n  for (let item of body[&#039;_embedded&#039;][&#039;fx:items&#039;]) {\n    const name = item[&#039;name&#039;];\n    const quantity = item[&#039;quantity&#039;];\n    const category = item[&#039;_embedded&#039;][&#039;fx:item_category&#039;][&#039;code&#039;];\n    if(item[&#039;name&#039;] === &quot;Product A&quot;) {\n      for (let itemOption of item[&#039;_embedded&#039;][&#039;fx:item_options&#039;]) {\n        if (itemOption[&#039;name&#039;] == &#039;size&#039;) {\n          if (itemOption[&#039;value&#039;] === &#039;small&#039;) {\n            hasSmallA = true;\n            return {\n              ok: true,\n              details: &quot;has small A&quot;\n            }\n          } else if (itemOption[&#039;value&#039;] === &#039;large&#039;) {\n            hasLargeA = true;\n            return {\n              ok: true,\n              details: &quot;has large A&quot;\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\nserver.listen(80);\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Ruby\u003C\u002Fh3>\u003Cp>This example uses a small Sinatra app — some logic may need adjusting for a different framework.\u003C\u002Fp>\u003Cpre>\u003Ccode>require &#039;sinatra&#039;\nrequire &#039;json&#039;\n\ndef verify_webhook(data, encryption_key)\n    signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new(&#039;sha256&#039;), encryption_key, data)\n    return halt 500, &quot;Signature verification failed - data corrupted&quot; unless Rack::Utils.secure_compare(signature, request.env[&#039;HTTP_FOXY_WEBHOOK_SIGNATURE&#039;])\nend\n\npost &#039;\u002Fwebhook&#039; do\n    request.body.rewind\n    data = request.body.read\n    event = request.env[&#039;HTTP_FOXY_WEBHOOK_EVENT&#039;]\n    verify_webhook(data, ENV[&#039;FOXY_WEBHOOK_ENCRYPTION_KEY&#039;])\n\n    parsedData = JSON.parse(data)\n\n    # Handle the payload\n    puts parsedData[&#039;id&#039;]\nend\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>Notes\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Cp>Avoid storing your webhook encryption key directly in your codebase — store it as an environment variable instead.\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>When comparing signatures, always use a secure\u002Fconstant-time comparison method rather than a direct equality check.\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>",{"name":659,"created_at":660,"published_at":661,"updated_at":662,"id":663,"uuid":47,"content":664,"slug":48,"full_slug":48,"sort_by_date":59,"position":843,"tag_list":844,"is_startpage":24,"parent_id":59,"meta_data":59,"group_id":845,"first_published_at":846,"release_id":59,"lang":65,"path":59,"alternates":847,"default_full_slug":59,"translated_slugs":59},"Contact","2022-09-23T19:56:58.957Z","2025-05-08T18:24:40.382Z","2025-05-08T18:24:40.392Z",3138,{"seo":665,"_uid":668,"title":669,"action":670,"fields":671,"method":819,"columns":820,"subtitle":834,"component":48,"button_text":840,"submit_title":841,"submit_subtitle":842},{"_uid":666,"title":659,"plugin":667,"description":13},"24ff7574-3bcc-48d2-85b5-e529dfea1cc4","meta-fields","8f54f1da-9d8f-49b2-89e7-840e886491cb","We're here to help.","https:\u002F\u002Fusebasin.com\u002Ff\u002F029f48d65402",[672,677,681,790,793,798,813],{"_uid":673,"name":674,"type":332,"label":675,"options":13,"required":33,"component":676,"placeholder":13},"9a70b226-2036-4f90-a052-b3efa61c5896","name","Name","form___field",{"_uid":678,"name":679,"type":679,"label":680,"options":13,"required":33,"component":676,"placeholder":13},"86ba35be-ff43-4a28-8633-14052a8f6622","email","Email Address",{"_uid":682,"name":683,"type":684,"label":685,"options":686,"required":33,"component":676,"conditions":687,"placeholder":13},"3f827475-492c-4f97-aa1e-2386ac263b6c","topic","select","Topic","Presales, Support, Billing, Partnerships, Order Enquiry, Other",[688,744,754,761,769,777,783],{"_uid":689,"equals":690,"fields":691,"component":743},"e21d97dd-e68e-4fa6-ba97-bc40f3041dde","Order Enquiry",[692],{"_uid":693,"body":694,"type":741,"title":13,"component":742},"b64992bc-6d53-48b8-b7a0-d81e5a062e50",{"type":324,"content":695},[696],{"type":327,"content":697},[698,700,707,709,711,712,717,719,724,732,734,739],{"text":699,"type":332},"We are ",{"text":701,"type":332,"marks":702},"Foxy.io",[703],{"type":337,"attrs":704},{"href":705,"uuid":59,"anchor":59,"custom":706,"target":59,"linktype":31},"http:\u002F\u002FFoxy.io",{},{"text":708,"type":332},", an ecommerce platform powering ecommerce for other merchants. We do not sell products, and are unable to assist with questions about order statuses or refunds for any merchants using our platform. Please contact the merchant you ordered from for assistance. If you’d like to report a store using Foxy for fraudulent practices, please select ‘other’ in the subject.",{"type":710},"hard_break",{"type":710},{"text":713,"type":332,"marks":714},"NOTE:",[715],{"type":716},"bold",{"text":718,"type":332}," We are ",{"text":720,"type":332,"marks":721},"not ",[722],{"type":723},"italic",{"text":725,"type":332,"marks":726},"Foxy.in",[727,731],{"type":337,"attrs":728},{"href":729,"uuid":59,"anchor":59,"custom":730,"target":59,"linktype":31},"http:\u002F\u002FFoxy.in",{},{"type":723},{"text":733,"type":332},". We are not in any way affiliated with ",{"text":725,"type":332,"marks":735},[736],{"type":337,"attrs":737},{"href":729,"uuid":59,"anchor":59,"custom":738,"target":59,"linktype":31},{},{"text":740,"type":332},", and cannot help in any way with your order from that website.","danger","global___alert","form___condition",{"_uid":745,"equals":746,"fields":747,"component":743},"8765c3e1-25cf-44aa-b8ea-fc6094acf9c3","Presales",[748],{"_uid":749,"name":750,"type":751,"label":13,"options":13,"required":24,"component":676,"conditions":752,"placeholder":13,"default_value":753},"cf464f8e-d643-4f6e-af29-d3abffaf7380","department_email_address","hidden",[],"hello@foxy.io",{"_uid":755,"equals":208,"fields":756,"component":743},"4007b6d8-77e5-421d-bd1e-6f336dd853fb",[757],{"_uid":758,"name":750,"type":751,"label":13,"options":13,"required":24,"component":676,"conditions":759,"placeholder":13,"default_value":760},"7b4c6aa5-a68c-45e0-9ce1-0a36af10c0c2",[],"help@foxy.io",{"_uid":762,"equals":763,"fields":764,"component":743},"1dbb8f11-613d-43cd-9e09-1b94f6e19219","Billing",[765],{"_uid":766,"name":750,"type":751,"label":13,"options":13,"required":24,"component":676,"conditions":767,"placeholder":13,"default_value":768},"a0ac0d1b-bc4f-4a6c-a682-581d450b0b73",[],"help+billing@foxy.io",{"_uid":770,"equals":771,"fields":772,"component":743},"a0a53a50-7172-4a29-ba58-181e38874e12","Partnerships",[773],{"_uid":774,"name":750,"type":751,"label":13,"options":13,"required":24,"component":676,"conditions":775,"placeholder":13,"default_value":776},"7aa011d9-f374-4aed-b5a5-929b54aaf152",[],"partners@foxy.io",{"_uid":778,"equals":690,"fields":779,"component":743},"a4cd431f-25d5-41c7-bfdc-02c908c8fb47",[780],{"_uid":781,"name":750,"type":751,"label":13,"options":13,"required":24,"component":676,"conditions":782,"placeholder":13,"default_value":753},"f5d52168-d6ae-451b-94ee-2ced1cbd28ad",[],{"_uid":784,"equals":785,"fields":786,"component":743},"25aba1ed-eb41-4bbc-aa89-f7a7167ea86e","Other",[787],{"_uid":788,"name":750,"type":751,"label":13,"options":13,"required":24,"component":676,"conditions":789,"placeholder":13,"default_value":753},"f40dfaef-c203-4b71-bf4e-e1b43cef192b",[],{"_uid":791,"component":792},"e9c53a05-f40a-4510-aaf8-bc072a235a0c","form___subject",{"_uid":794,"name":795,"type":796,"label":797,"options":13,"required":33,"component":676,"placeholder":13},"a4c4d385-fff4-4978-99fb-b68cfea623d6","message","textarea","Message",{"_uid":799,"name":800,"type":684,"label":801,"options":802,"required":33,"component":676,"conditions":803,"placeholder":13},"8a3c9f85-f438-427d-9c7a-d7b295a14b5b","existing_user","Are you an existing user?","No, Yes",[804],{"_uid":805,"equals":806,"fields":807,"component":743},"115933d6-262a-4b59-8fa8-579c5ad73de1","Yes",[808],{"_uid":809,"name":810,"type":332,"label":811,"options":13,"required":33,"component":676,"conditions":812,"placeholder":13},"44b6ff23-98f0-4e95-b7f5-c23e06415c2d","subdomain","Store Subdomain",[],{"_uid":814,"name":815,"type":684,"label":816,"options":817,"required":33,"component":676,"conditions":818,"placeholder":13},"922a5cef-3af2-4113-8855-36c7910e3ee3","user_type","What type of user are you?","Developer, Designer, Merchant",[],"POST",[821],{"_uid":822,"text":823,"title":832,"component":833},"7323b90d-a93a-4bf1-baa9-20d0b7ead61b",{"type":324,"content":824},[825],{"type":327,"content":826},[827,829,830],{"text":828,"type":332},"855.369.9227",{"type":710},{"text":831,"type":332},"9:30am-6pm Central M-F","Pre-sales, Sales, & Partnerships","contact___footer_column",{"type":324,"content":835},[836],{"type":327,"content":837},[838],{"text":839,"type":332},"Get in touch to get help from our friendly support team.","Submit","Success!","Your email has been received. We'll get back to you as soon as we can, but it might take a business day. If you don't hear back from us in a timely manner, please check your spam folder to ensure our reply didn't go there.",-80,[],"2fd9fb7d-a48a-4184-acfd-30022d8d6f08","2022-09-23T20:10:45.360Z",[],[288,849,875],{"name":850,"created_at":851,"published_at":852,"updated_at":853,"id":854,"uuid":855,"content":856,"slug":869,"full_slug":870,"sort_by_date":59,"position":871,"tag_list":872,"is_startpage":24,"parent_id":310,"meta_data":59,"group_id":873,"first_published_at":852,"release_id":59,"lang":65,"path":59,"alternates":874,"default_full_slug":59,"translated_slugs":59},"Webhooks","2026-07-20T19:37:26.231Z","2026-07-20T19:41:27.137Z","2026-07-20T19:41:27.157Z",200239703052833,"5f8f8006-b68e-4a03-8638-2d28a556726e",{"_uid":857,"icon":13,"name":850,"type":858,"pinned":24,"summary":859,"category":13,"component":297,"blog_posts":860,"icon_custom":861,"case_studies":863,"faq_sections":864,"featured_guides":865,"mailbox_category":13,"featured_articles":866,"featured_blog_posts":867,"featured_case_studies":868},"c8a9b798-94ba-4a83-9ba5-c851b17946df","simple","Send real-time event notifications to your own endpoint when transactions, subscriptions, and customers change.",[],{"id":59,"alt":59,"name":13,"focus":59,"title":59,"source":59,"filename":13,"copyright":59,"fieldtype":81,"meta_data":862},{},[],[],[],[],[],[],"webhooks","help\u002Fcategories\u002Fwebhooks",-750,[],"c59e6243-064a-4f06-a367-c14a15c02ff3",[],{"name":876,"created_at":877,"published_at":878,"updated_at":879,"id":880,"uuid":626,"content":881,"slug":893,"full_slug":894,"sort_by_date":59,"position":895,"tag_list":896,"is_startpage":24,"parent_id":310,"meta_data":59,"group_id":897,"first_published_at":878,"release_id":59,"lang":65,"path":59,"alternates":898,"default_full_slug":59,"translated_slugs":59},"Transaction Webhook","2026-07-20T19:38:03.911Z","2026-07-20T19:41:26.859Z","2026-07-20T19:41:26.871Z",200239857342105,{"_uid":882,"icon":13,"name":876,"type":858,"pinned":24,"summary":883,"category":855,"component":297,"blog_posts":884,"icon_custom":885,"case_studies":887,"faq_sections":888,"featured_guides":889,"mailbox_category":13,"featured_articles":890,"featured_blog_posts":891,"featured_case_studies":892},"26ff9dcf-0966-4b3b-a73b-933b8f8394cc","Subscribe to a JSON webhook for transaction, subscription, customer, transaction log, and changelog events.",[],{"id":59,"alt":59,"name":13,"focus":59,"title":59,"source":59,"filename":13,"copyright":59,"fieldtype":81,"meta_data":886},{},[],[],[],[],[],[],"transaction-webhook","help\u002Fcategories\u002Ftransaction-webhook",-770,[],"098fe45b-d310-4699-8759-3963ef9fe541",[],{},1784651810252]