[{"data":1,"prerenderedAt":1880},["ShallowReactive",2],{"navigation_docs":3,"-modules-stripe":153,"-modules-stripe-surround":1875},[4,35,50,59,144],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting started",false,"\u002Fgetting-started","1.getting-started",[10,15,20,25,30],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F2.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Local Development","\u002Fgetting-started\u002Flocal-development","1.getting-started\u002F3.local-development","i-lucide-terminal",{"title":21,"path":22,"stem":23,"icon":24},"Publishing Packages","\u002Fgetting-started\u002Fpublishing","1.getting-started\u002F4.publishing","i-lucide-package-check",{"title":26,"path":27,"stem":28,"icon":29},"Writing a Module","\u002Fgetting-started\u002Fwriting-a-module","1.getting-started\u002F5.writing-a-module","i-lucide-puzzle",{"title":31,"path":32,"stem":33,"icon":34},"UX Patterns","\u002Fgetting-started\u002Fux-patterns","1.getting-started\u002F6.ux-patterns","i-lucide-layout-template",{"title":36,"path":37,"stem":38,"children":39},"Applications","\u002Fapplications","2.applications",[40,45],{"title":41,"path":42,"stem":43,"icon":44},"Website","\u002Fapplications\u002Fwebsite","2.applications\u002F1.website","i-lucide-layout-dashboard",{"title":46,"path":47,"stem":48,"icon":49},"Docs","\u002Fapplications\u002Fdocs","2.applications\u002F2.docs","i-lucide-book-open",{"title":51,"path":52,"stem":53,"children":54},"Layers","\u002Flayers","3.layers",[55],{"title":56,"path":57,"stem":58},"Base Layer","\u002Flayers\u002Fbase","3.layers\u002F1.base",{"title":60,"path":61,"stem":62,"children":63},"Modules","\u002Fmodules","4.modules",[64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140],{"title":65,"path":66,"stem":67},"Account","\u002Fmodules\u002Faccount","4.modules\u002F01.account",{"title":69,"path":70,"stem":71},"Admin","\u002Fmodules\u002Fadmin","4.modules\u002F02.admin",{"title":73,"path":74,"stem":75},"Auth","\u002Fmodules\u002Fauth","4.modules\u002F03.auth",{"title":77,"path":78,"stem":79},"Authorization","\u002Fmodules\u002Fauthorization","4.modules\u002F04.authorization",{"title":81,"path":82,"stem":83},"Cookie Consent","\u002Fmodules\u002Fcookie-consent","4.modules\u002F05.cookie-consent",{"title":85,"path":86,"stem":87},"Events","\u002Fmodules\u002Fevents","4.modules\u002F06.events",{"title":89,"path":90,"stem":91},"Forms","\u002Fmodules\u002Fforms","4.modules\u002F07.forms",{"title":93,"path":94,"stem":95},"MCP","\u002Fmodules\u002Fmcp","4.modules\u002F08.mcp",{"title":97,"path":98,"stem":99},"Menu","\u002Fmodules\u002Fmenu","4.modules\u002F09.menu",{"title":101,"path":102,"stem":103},"Module Kit","\u002Fmodules\u002Fmodule-kit","4.modules\u002F10.module-kit",{"title":105,"path":106,"stem":107},"Notify","\u002Fmodules\u002Fnotify","4.modules\u002F11.notify",{"title":109,"path":110,"stem":111},"OAuth Server","\u002Fmodules\u002Foauth-server","4.modules\u002F12.oauth-server",{"title":113,"path":114,"stem":115},"Payments","\u002Fmodules\u002Fpayments","4.modules\u002F13.payments",{"title":117,"path":118,"stem":119},"Preferences","\u002Fmodules\u002Fpreferences","4.modules\u002F14.preferences",{"title":121,"path":122,"stem":123},"Stripe","\u002Fmodules\u002Fstripe","4.modules\u002F15.stripe",{"title":125,"path":126,"stem":127},"Subscriptions","\u002Fmodules\u002Fsubscriptions","4.modules\u002F16.subscriptions",{"title":129,"path":130,"stem":131},"UI","\u002Fmodules\u002Fui","4.modules\u002F17.ui",{"title":133,"path":134,"stem":135},"Users","\u002Fmodules\u002Fusers","4.modules\u002F18.users",{"title":137,"path":138,"stem":139},"Widget","\u002Fmodules\u002Fwidget","4.modules\u002F19.widget",{"title":141,"path":142,"stem":143},"Email Templates","\u002Fmodules\u002Femail-templates","4.modules\u002F20.email-templates",{"title":145,"path":146,"stem":147,"children":148},"Packages","\u002Fpackages","5.packages",[149],{"title":150,"path":151,"stem":152},"CLI","\u002Fpackages\u002Fcli","5.packages\u002F4.cli",{"id":154,"title":121,"body":155,"description":1869,"extension":1870,"links":1871,"meta":1872,"navigation":859,"path":122,"seo":1873,"stem":123,"__hash__":1874},"docs\u002F4.modules\u002F15.stripe.md",{"type":156,"value":157,"toc":1851},"minimark",[158,180,183,209,214,406,410,455,472,477,483,573,577,594,598,601,710,727,783,786,789,1121,1125,1362,1486,1497,1501,1581,1588,1592,1621,1625,1661,1665,1701,1708,1764,1768,1792,1795,1816,1820,1841,1847],[159,160,161,162,168,169,173,174,176,177,179],"p",{},"Provider plumbing for ",[163,164,121],"a",{"href":165,"rel":166},"https:\u002F\u002Fstripe.com",[167],"nofollow",". It owns the Stripe client, the link between a user and a Stripe\ncustomer, and ",[170,171,172],"strong",{},"one"," webhook endpoint. Feature modules such as ",[163,175,125],{"href":126}," and\n",[163,178,113],{"href":114}," register listeners for the Stripe events they care about; they never verify signatures or\ndeal with retries themselves.",[159,181,182],{},"Stripe stays the source of truth for catalog data: the module stores no products or prices, only the customer id per\nuser. Policy (seasons, discounts, ...) is injected through hooks in the feature modules, not encoded in Stripe.",[184,185,186,189,190,194,195,198,199,202,203,208],"note",{},[170,187,188],{},"Requires"," ",[191,192,193],"code",{},"@nuxthub\u002Fcore"," with KV enabled (",[191,196,197],{},"hub.kv",", set by default; the build throws if it is disabled),\n",[191,200,201],{},"@frigear-nu\u002Fmodule-kit"," and ",[163,204,205],{"href":134},[191,206,207],{},"@frigear-nu\u002Fusers",".",[210,211,213],"h2",{"id":212},"quick-setup","Quick setup",[215,216,221],"pre",{"className":217,"code":218,"language":219,"meta":220,"style":220},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  modules: ['@nuxthub\u002Fcore', '@frigear-nu\u002Fusers', '@frigear-nu\u002Fstripe'],\n  hub: { db: { dialect: 'sqlite', driver: 'libsql' }, kv: true },\n  stripe: {\n    settings: { webhookPath: '\u002Fapi\u002Fstripe\u002Fwebhook' }, \u002F\u002F default\n  },\n})\n","ts","",[191,222,223,247,293,352,363,391,397],{"__ignoreMap":220},[224,225,228,232,235,239,243],"span",{"class":226,"line":227},"line",1,[224,229,231],{"class":230},"s7zQu","export",[224,233,234],{"class":230}," default",[224,236,238],{"class":237},"s2Zo4"," defineNuxtConfig",[224,240,242],{"class":241},"sTEyZ","(",[224,244,246],{"class":245},"sMK4o","{\n",[224,248,250,254,257,260,263,266,268,271,274,276,278,280,282,285,287,290],{"class":226,"line":249},2,[224,251,253],{"class":252},"swJcz","  modules",[224,255,256],{"class":245},":",[224,258,259],{"class":241}," [",[224,261,262],{"class":245},"'",[224,264,193],{"class":265},"sfazB",[224,267,262],{"class":245},[224,269,270],{"class":245},",",[224,272,273],{"class":245}," '",[224,275,207],{"class":265},[224,277,262],{"class":245},[224,279,270],{"class":245},[224,281,273],{"class":245},[224,283,284],{"class":265},"@frigear-nu\u002Fstripe",[224,286,262],{"class":245},[224,288,289],{"class":241},"]",[224,291,292],{"class":245},",\n",[224,294,296,299,301,304,307,309,311,314,316,318,321,323,325,328,330,332,335,337,340,343,345,349],{"class":226,"line":295},3,[224,297,298],{"class":252},"  hub",[224,300,256],{"class":245},[224,302,303],{"class":245}," {",[224,305,306],{"class":252}," db",[224,308,256],{"class":245},[224,310,303],{"class":245},[224,312,313],{"class":252}," dialect",[224,315,256],{"class":245},[224,317,273],{"class":245},[224,319,320],{"class":265},"sqlite",[224,322,262],{"class":245},[224,324,270],{"class":245},[224,326,327],{"class":252}," driver",[224,329,256],{"class":245},[224,331,273],{"class":245},[224,333,334],{"class":265},"libsql",[224,336,262],{"class":245},[224,338,339],{"class":245}," },",[224,341,342],{"class":252}," kv",[224,344,256],{"class":245},[224,346,348],{"class":347},"sfNiH"," true",[224,350,351],{"class":245}," },\n",[224,353,355,358,360],{"class":226,"line":354},4,[224,356,357],{"class":252},"  stripe",[224,359,256],{"class":245},[224,361,362],{"class":245}," {\n",[224,364,366,369,371,373,376,378,380,383,385,387],{"class":226,"line":365},5,[224,367,368],{"class":252},"    settings",[224,370,256],{"class":245},[224,372,303],{"class":245},[224,374,375],{"class":252}," webhookPath",[224,377,256],{"class":245},[224,379,273],{"class":245},[224,381,382],{"class":265},"\u002Fapi\u002Fstripe\u002Fwebhook",[224,384,262],{"class":245},[224,386,339],{"class":245},[224,388,390],{"class":389},"sHwdD"," \u002F\u002F default\n",[224,392,394],{"class":226,"line":393},6,[224,395,396],{"class":245},"  },\n",[224,398,400,403],{"class":226,"line":399},7,[224,401,402],{"class":245},"}",[224,404,405],{"class":241},")\n",[210,407,409],{"id":408},"options","Options",[411,412,413,432],"table",{},[414,415,416],"thead",{},[417,418,419,423,426,429],"tr",{},[420,421,422],"th",{},"Option",[420,424,425],{},"Type",[420,427,428],{},"Default",[420,430,431],{},"Purpose",[433,434,435],"tbody",{},[417,436,437,443,448,452],{},[438,439,440],"td",{},[191,441,442],{},"settings.webhookPath",[438,444,445],{},[191,446,447],{},"string",[438,449,450],{},[191,451,382],{},[438,453,454],{},"Path the webhook is served on.",[159,456,457,458,461,462,465,466,469,470,208],{},"The default path is exported as ",[191,459,460],{},"DEFAULT_WEBHOOK_PATH",", and the pinned API version as ",[191,463,464],{},"STRIPE_API_VERSION"," (currently\n",[191,467,468],{},"2026-09-30.endive","), both from ",[191,471,284],{},[473,474,476],"h3",{"id":475},"environment-variables","Environment variables",[159,478,479,480,208],{},"Read them through runtime config, never ",[191,481,482],{},"process.env",[411,484,485,497],{},[414,486,487],{},[417,488,489,492,495],{},[420,490,491],{},"Variable",[420,493,494],{},"Runtime config",[420,496,431],{},[433,498,499,518,537,554],{},[417,500,501,506,511],{},[438,502,503],{},[191,504,505],{},"NUXT_STRIPE_SECRET_KEY",[438,507,508],{},[191,509,510],{},"stripe.secretKey",[438,512,513,514,517],{},"Server-side secret API key (",[191,515,516],{},"sk_..."," \u002F restricted key).",[417,519,520,525,530],{},[438,521,522],{},[191,523,524],{},"NUXT_STRIPE_WEBHOOK_SECRET",[438,526,527],{},[191,528,529],{},"stripe.webhookSecret",[438,531,532,533,536],{},"Signing secret of the webhook endpoint (",[191,534,535],{},"whsec_...",").",[417,538,539,544,549],{},[438,540,541],{},[191,542,543],{},"NUXT_STRIPE_API_VERSION",[438,545,546],{},[191,547,548],{},"stripe.apiVersion",[438,550,551,552,208],{},"Optional. Overrides ",[191,553,464],{},[417,555,556,561,566],{},[438,557,558],{},[191,559,560],{},"NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY",[438,562,563],{},[191,564,565],{},"public.stripe.publishableKey",[438,567,568,569,572],{},"Publishable key (",[191,570,571],{},"pk_...","), exposed to the client.",[473,574,576],{"id":575},"kv","KV",[159,578,579,580,585,586,589,590,593],{},"Webhook idempotency uses ",[163,581,584],{"href":582,"rel":583},"https:\u002F\u002Fhub.nuxt.com\u002Fdocs\u002Fkv",[167],"NuxtHub KV","; ",[191,587,588],{},"unstorage"," must be resolvable by the host app.\nProcessed event ids are stored under ",[191,591,592],{},"stripe:event:\u003Cevent id>",". No extra table is needed.",[210,595,597],{"id":596},"server","Server",[159,599,600],{},"All utilities are auto-imported in Nitro.",[411,602,603,616],{},[414,604,605],{},[417,606,607,610,613],{},[420,608,609],{},"Utility",[420,611,612],{},"Returns",[420,614,615],{},"Description",[433,617,618,640,659,678,697],{},[417,619,620,625,629],{},[438,621,622],{},[191,623,624],{},"useStripe()",[438,626,627],{},[191,628,121],{},[438,630,631,632,635,636,639],{},"Shared client built on ",[191,633,634],{},"fetch",", so it runs on Cloudflare Workers. Throws 500 when ",[191,637,638],{},"secretKey"," is missing.",[417,641,642,647,652],{},[438,643,644],{},[191,645,646],{},"ensureStripeCustomer(userId)",[438,648,649],{},[191,650,651],{},"Promise\u003Cstring>",[438,653,654,655,658],{},"The stored ",[191,656,657],{},"stripeCustomerId",", else a Stripe search by email, else a new customer, which is persisted. Concurrent calls converge on one id. Throws 404 for an unknown user.",[417,660,661,666,671],{},[438,662,663],{},[191,664,665],{},"getStripeCustomerUser(customerId)",[438,667,668],{},[191,669,670],{},"Promise\u003CUser | null>",[438,672,673,674,677],{},"The local ",[191,675,676],{},"users"," row for a Stripe customer id.",[417,679,680,685,690],{},[438,681,682],{},[191,683,684],{},"onStripeEvent(type, handler)",[438,686,687],{},[191,688,689],{},"void",[438,691,692,693,208],{},"Runtime listener, see ",[163,694,696],{"href":695},"#listening-to-events","Listening to events",[417,698,699,704,707],{},[438,700,701],{},[191,702,703],{},"defineStripeEventHandler(handler)",[438,705,706],{},"handler",[438,708,709],{},"Typed identity helper for handler files.",[159,711,712,715,716,719,720,292,723,726],{},[191,713,714],{},"@frigear-nu\u002Fstripe\u002Futils"," is framework-agnostic and also exports ",[191,717,718],{},"registerStripeEventHandler",", ",[191,721,722],{},"onStripeEvent",[191,724,725],{},"defineStripeEventHandler"," and the shared redirect guard:",[215,728,730],{"className":217,"code":729,"language":219,"meta":220,"style":220},"\u002F\u002F Accepts a relative path (\"\u002Fx\") or an absolute URL on `origin`; returns an absolute URL\n\u002F\u002F on that origin, or null when unsafe (protocol-relative, other host, unparsable).\nfunction resolveSameOriginUrl(input: string, origin: string): string | null\n",[191,731,732,737,742],{"__ignoreMap":220},[224,733,734],{"class":226,"line":227},[224,735,736],{"class":389},"\u002F\u002F Accepts a relative path (\"\u002Fx\") or an absolute URL on `origin`; returns an absolute URL\n",[224,738,739],{"class":226,"line":249},[224,740,741],{"class":389},"\u002F\u002F on that origin, or null when unsafe (protocol-relative, other host, unparsable).\n",[224,743,744,748,751,753,757,759,763,765,768,770,772,775,777,780],{"class":226,"line":295},[224,745,747],{"class":746},"spNyl","function",[224,749,750],{"class":237}," resolveSameOriginUrl",[224,752,242],{"class":245},[224,754,756],{"class":755},"sHdIc","input",[224,758,256],{"class":245},[224,760,762],{"class":761},"sBMFI"," string",[224,764,270],{"class":245},[224,766,767],{"class":755}," origin",[224,769,256],{"class":245},[224,771,762],{"class":761},[224,773,774],{"class":245},"):",[224,776,762],{"class":761},[224,778,779],{"class":245}," |",[224,781,782],{"class":761}," null\n",[159,784,785],{},"Every module that sends people through Stripe (payments, subscriptions, events) uses it for return URLs.",[210,787,696],{"id":788},"listening-to-events",[215,790,792],{"className":217,"code":791,"language":219,"meta":220,"style":220},"type StripeEventHandlerContext = {\n  stripe: Stripe          \u002F\u002F the useStripe() instance\n  userId: number | null   \u002F\u002F local user owning the event's customer, null if unknown\n  event: H3Event          \u002F\u002F the Nitro event of the webhook request\n}\n\ntype StripeEventHandler\u003CT extends StripeEventType = StripeEventType> = (\n  event: StripeEventOf\u003CT>,\n  ctx: StripeEventHandlerContext,\n) => void | Promise\u003Cvoid>\n\n\u002F\u002F Build time, from a module's setup()\nregisterStripeEventHandler(nuxt: Nuxt, options: {\n  events: string[] | '*'  \u002F\u002F Stripe event types, or '*' for every event\n  handler: string         \u002F\u002F absolute path to a file whose default export is a defineStripeEventHandler(...) result\n  order?: number          \u002F\u002F lower runs first, default 100\n}): void\n\n\u002F\u002F Runtime, from a Nitro plugin\nonStripeEvent\u003CT extends StripeEventType>(\n  type: T | T[] | '*',\n  handler: StripeEventHandler\u003CT>,\n): void\n",[191,793,794,807,819,837,850,855,861,892,909,921,945,950,956,980,1006,1019,1033,1042,1047,1053,1069,1096,1111],{"__ignoreMap":220},[224,795,796,799,802,805],{"class":226,"line":227},[224,797,798],{"class":746},"type",[224,800,801],{"class":761}," StripeEventHandlerContext",[224,803,804],{"class":245}," =",[224,806,362],{"class":245},[224,808,809,811,813,816],{"class":226,"line":249},[224,810,357],{"class":252},[224,812,256],{"class":245},[224,814,815],{"class":761}," Stripe",[224,817,818],{"class":389},"          \u002F\u002F the useStripe() instance\n",[224,820,821,824,826,829,831,834],{"class":226,"line":295},[224,822,823],{"class":252},"  userId",[224,825,256],{"class":245},[224,827,828],{"class":761}," number",[224,830,779],{"class":245},[224,832,833],{"class":761}," null",[224,835,836],{"class":389},"   \u002F\u002F local user owning the event's customer, null if unknown\n",[224,838,839,842,844,847],{"class":226,"line":354},[224,840,841],{"class":252},"  event",[224,843,256],{"class":245},[224,845,846],{"class":761}," H3Event",[224,848,849],{"class":389},"          \u002F\u002F the Nitro event of the webhook request\n",[224,851,852],{"class":226,"line":365},[224,853,854],{"class":245},"}\n",[224,856,857],{"class":226,"line":393},[224,858,860],{"emptyLinePlaceholder":859},true,"\n",[224,862,863,865,868,871,874,877,880,882,884,887,889],{"class":226,"line":399},[224,864,798],{"class":746},[224,866,867],{"class":761}," StripeEventHandler",[224,869,870],{"class":245},"\u003C",[224,872,873],{"class":761},"T",[224,875,876],{"class":746}," extends",[224,878,879],{"class":761}," StripeEventType",[224,881,804],{"class":245},[224,883,879],{"class":761},[224,885,886],{"class":245},">",[224,888,804],{"class":245},[224,890,891],{"class":241}," (\n",[224,893,895,897,899,902,904,906],{"class":226,"line":894},8,[224,896,841],{"class":755},[224,898,256],{"class":245},[224,900,901],{"class":761}," StripeEventOf",[224,903,870],{"class":245},[224,905,873],{"class":761},[224,907,908],{"class":245},">,\n",[224,910,912,915,917,919],{"class":226,"line":911},9,[224,913,914],{"class":755},"  ctx",[224,916,256],{"class":245},[224,918,801],{"class":761},[224,920,292],{"class":245},[224,922,924,927,930,933,935,938,940,942],{"class":226,"line":923},10,[224,925,926],{"class":241},") ",[224,928,929],{"class":746},"=>",[224,931,932],{"class":761}," void",[224,934,779],{"class":245},[224,936,937],{"class":761}," Promise",[224,939,870],{"class":245},[224,941,689],{"class":761},[224,943,944],{"class":245},">\n",[224,946,948],{"class":226,"line":947},11,[224,949,860],{"emptyLinePlaceholder":859},[224,951,953],{"class":226,"line":952},12,[224,954,955],{"class":389},"\u002F\u002F Build time, from a module's setup()\n",[224,957,959,961,963,966,968,971,973,976,978],{"class":226,"line":958},13,[224,960,718],{"class":761},[224,962,242],{"class":245},[224,964,965],{"class":755},"nuxt",[224,967,256],{"class":245},[224,969,970],{"class":761}," Nuxt",[224,972,270],{"class":245},[224,974,975],{"class":755}," options",[224,977,256],{"class":245},[224,979,362],{"class":245},[224,981,983,986,988,990,993,996,998,1001,1003],{"class":226,"line":982},14,[224,984,985],{"class":252},"  events",[224,987,256],{"class":245},[224,989,762],{"class":761},[224,991,992],{"class":241},"[] ",[224,994,995],{"class":245},"|",[224,997,273],{"class":245},[224,999,1000],{"class":265},"*",[224,1002,262],{"class":245},[224,1004,1005],{"class":389},"  \u002F\u002F Stripe event types, or '*' for every event\n",[224,1007,1009,1012,1014,1016],{"class":226,"line":1008},15,[224,1010,1011],{"class":252},"  handler",[224,1013,256],{"class":245},[224,1015,762],{"class":761},[224,1017,1018],{"class":389},"         \u002F\u002F absolute path to a file whose default export is a defineStripeEventHandler(...) result\n",[224,1020,1022,1025,1028,1030],{"class":226,"line":1021},16,[224,1023,1024],{"class":252},"  order",[224,1026,1027],{"class":245},"?:",[224,1029,828],{"class":761},[224,1031,1032],{"class":389},"          \u002F\u002F lower runs first, default 100\n",[224,1034,1036,1039],{"class":226,"line":1035},17,[224,1037,1038],{"class":245},"}):",[224,1040,1041],{"class":761}," void\n",[224,1043,1045],{"class":226,"line":1044},18,[224,1046,860],{"emptyLinePlaceholder":859},[224,1048,1050],{"class":226,"line":1049},19,[224,1051,1052],{"class":389},"\u002F\u002F Runtime, from a Nitro plugin\n",[224,1054,1056,1058,1060,1062,1064,1066],{"class":226,"line":1055},20,[224,1057,722],{"class":761},[224,1059,870],{"class":245},[224,1061,873],{"class":761},[224,1063,876],{"class":746},[224,1065,879],{"class":761},[224,1067,1068],{"class":241},">(\n",[224,1070,1072,1075,1077,1080,1082,1084,1086,1088,1090,1092,1094],{"class":226,"line":1071},21,[224,1073,1074],{"class":755},"  type",[224,1076,256],{"class":245},[224,1078,1079],{"class":761}," T",[224,1081,779],{"class":245},[224,1083,1079],{"class":761},[224,1085,992],{"class":241},[224,1087,995],{"class":245},[224,1089,273],{"class":245},[224,1091,1000],{"class":265},[224,1093,262],{"class":245},[224,1095,292],{"class":245},[224,1097,1099,1101,1103,1105,1107,1109],{"class":226,"line":1098},22,[224,1100,1011],{"class":755},[224,1102,256],{"class":245},[224,1104,867],{"class":761},[224,1106,870],{"class":245},[224,1108,873],{"class":761},[224,1110,908],{"class":245},[224,1112,1114,1117,1119],{"class":226,"line":1113},23,[224,1115,1116],{"class":241},")",[224,1118,256],{"class":245},[224,1120,1041],{"class":761},[473,1122,1124],{"id":1123},"in-a-module","In a module",[215,1126,1128],{"className":217,"code":1127,"language":219,"meta":220,"style":220},"import { createResolver, defineNuxtModule } from '@nuxt\u002Fkit'\nimport { registerStripeEventHandler } from '@frigear-nu\u002Fstripe\u002Futils'\n\nexport default defineNuxtModule({\n  meta: { name: '@frigear-nu\u002Fexample' },\n  setup(options, nuxt) {\n    const resolver = createResolver(import.meta.url)\n    registerStripeEventHandler(nuxt, {\n      events: ['customer.subscription.updated', 'checkout.session.completed'],\n      handler: resolver.resolve('.\u002Fruntime\u002Fserver\u002Fstripe\u002Fexample-events'),\n      order: 10,\n    })\n  },\n})\n",[191,1129,1130,1159,1178,1182,1194,1217,1235,1263,1276,1305,1332,1345,1352,1356],{"__ignoreMap":220},[224,1131,1132,1135,1137,1140,1142,1145,1148,1151,1153,1156],{"class":226,"line":227},[224,1133,1134],{"class":230},"import",[224,1136,303],{"class":245},[224,1138,1139],{"class":241}," createResolver",[224,1141,270],{"class":245},[224,1143,1144],{"class":241}," defineNuxtModule",[224,1146,1147],{"class":245}," }",[224,1149,1150],{"class":230}," from",[224,1152,273],{"class":245},[224,1154,1155],{"class":265},"@nuxt\u002Fkit",[224,1157,1158],{"class":245},"'\n",[224,1160,1161,1163,1165,1168,1170,1172,1174,1176],{"class":226,"line":249},[224,1162,1134],{"class":230},[224,1164,303],{"class":245},[224,1166,1167],{"class":241}," registerStripeEventHandler",[224,1169,1147],{"class":245},[224,1171,1150],{"class":230},[224,1173,273],{"class":245},[224,1175,714],{"class":265},[224,1177,1158],{"class":245},[224,1179,1180],{"class":226,"line":295},[224,1181,860],{"emptyLinePlaceholder":859},[224,1183,1184,1186,1188,1190,1192],{"class":226,"line":354},[224,1185,231],{"class":230},[224,1187,234],{"class":230},[224,1189,1144],{"class":237},[224,1191,242],{"class":241},[224,1193,246],{"class":245},[224,1195,1196,1199,1201,1203,1206,1208,1210,1213,1215],{"class":226,"line":365},[224,1197,1198],{"class":252},"  meta",[224,1200,256],{"class":245},[224,1202,303],{"class":245},[224,1204,1205],{"class":252}," name",[224,1207,256],{"class":245},[224,1209,273],{"class":245},[224,1211,1212],{"class":265},"@frigear-nu\u002Fexample",[224,1214,262],{"class":245},[224,1216,351],{"class":245},[224,1218,1219,1222,1224,1226,1228,1231,1233],{"class":226,"line":393},[224,1220,1221],{"class":252},"  setup",[224,1223,242],{"class":245},[224,1225,408],{"class":755},[224,1227,270],{"class":245},[224,1229,1230],{"class":755}," nuxt",[224,1232,1116],{"class":245},[224,1234,362],{"class":245},[224,1236,1237,1240,1243,1245,1247,1249,1251,1253,1256,1258,1261],{"class":226,"line":399},[224,1238,1239],{"class":746},"    const",[224,1241,1242],{"class":241}," resolver",[224,1244,804],{"class":245},[224,1246,1139],{"class":237},[224,1248,242],{"class":252},[224,1250,1134],{"class":230},[224,1252,208],{"class":245},[224,1254,1255],{"class":241},"meta",[224,1257,208],{"class":245},[224,1259,1260],{"class":241},"url",[224,1262,405],{"class":252},[224,1264,1265,1268,1270,1272,1274],{"class":226,"line":894},[224,1266,1267],{"class":237},"    registerStripeEventHandler",[224,1269,242],{"class":252},[224,1271,965],{"class":241},[224,1273,270],{"class":245},[224,1275,362],{"class":245},[224,1277,1278,1281,1283,1285,1287,1290,1292,1294,1296,1299,1301,1303],{"class":226,"line":911},[224,1279,1280],{"class":252},"      events",[224,1282,256],{"class":245},[224,1284,259],{"class":252},[224,1286,262],{"class":245},[224,1288,1289],{"class":265},"customer.subscription.updated",[224,1291,262],{"class":245},[224,1293,270],{"class":245},[224,1295,273],{"class":245},[224,1297,1298],{"class":265},"checkout.session.completed",[224,1300,262],{"class":245},[224,1302,289],{"class":252},[224,1304,292],{"class":245},[224,1306,1307,1310,1312,1314,1316,1319,1321,1323,1326,1328,1330],{"class":226,"line":923},[224,1308,1309],{"class":252},"      handler",[224,1311,256],{"class":245},[224,1313,1242],{"class":241},[224,1315,208],{"class":245},[224,1317,1318],{"class":237},"resolve",[224,1320,242],{"class":252},[224,1322,262],{"class":245},[224,1324,1325],{"class":265},".\u002Fruntime\u002Fserver\u002Fstripe\u002Fexample-events",[224,1327,262],{"class":245},[224,1329,1116],{"class":252},[224,1331,292],{"class":245},[224,1333,1334,1337,1339,1343],{"class":226,"line":947},[224,1335,1336],{"class":252},"      order",[224,1338,256],{"class":245},[224,1340,1342],{"class":1341},"sbssI"," 10",[224,1344,292],{"class":245},[224,1346,1347,1350],{"class":226,"line":952},[224,1348,1349],{"class":245},"    }",[224,1351,405],{"class":252},[224,1353,1354],{"class":226,"line":958},[224,1355,396],{"class":245},[224,1357,1358,1360],{"class":226,"line":982},[224,1359,402],{"class":245},[224,1361,405],{"class":241},[215,1363,1365],{"className":217,"code":1364,"language":219,"meta":220,"style":220},"\u002F\u002F runtime\u002Fserver\u002Fstripe\u002Fexample-events.ts\nimport { defineStripeEventHandler } from '@frigear-nu\u002Fstripe\u002Futils'\n\nexport default defineStripeEventHandler\u003C'customer.subscription.updated' | 'checkout.session.completed'>(\n  async (event, { stripe, userId }) => {\n    \u002F\u002F `event` is narrowed to the generic's event types. Must be idempotent.\n    if (!userId) return\n  },\n)\n",[191,1366,1367,1372,1391,1395,1424,1455,1460,1478,1482],{"__ignoreMap":220},[224,1368,1369],{"class":226,"line":227},[224,1370,1371],{"class":389},"\u002F\u002F runtime\u002Fserver\u002Fstripe\u002Fexample-events.ts\n",[224,1373,1374,1376,1378,1381,1383,1385,1387,1389],{"class":226,"line":249},[224,1375,1134],{"class":230},[224,1377,303],{"class":245},[224,1379,1380],{"class":241}," defineStripeEventHandler",[224,1382,1147],{"class":245},[224,1384,1150],{"class":230},[224,1386,273],{"class":245},[224,1388,714],{"class":265},[224,1390,1158],{"class":245},[224,1392,1393],{"class":226,"line":295},[224,1394,860],{"emptyLinePlaceholder":859},[224,1396,1397,1399,1401,1403,1405,1407,1409,1411,1413,1415,1417,1419,1421],{"class":226,"line":354},[224,1398,231],{"class":230},[224,1400,234],{"class":230},[224,1402,1380],{"class":237},[224,1404,870],{"class":245},[224,1406,262],{"class":245},[224,1408,1289],{"class":265},[224,1410,262],{"class":245},[224,1412,779],{"class":245},[224,1414,273],{"class":245},[224,1416,1298],{"class":265},[224,1418,262],{"class":245},[224,1420,886],{"class":245},[224,1422,1423],{"class":241},"(\n",[224,1425,1426,1429,1432,1435,1437,1439,1442,1444,1447,1450,1453],{"class":226,"line":365},[224,1427,1428],{"class":746},"  async",[224,1430,1431],{"class":245}," (",[224,1433,1434],{"class":755},"event",[224,1436,270],{"class":245},[224,1438,303],{"class":245},[224,1440,1441],{"class":755}," stripe",[224,1443,270],{"class":245},[224,1445,1446],{"class":755}," userId",[224,1448,1449],{"class":245}," })",[224,1451,1452],{"class":746}," =>",[224,1454,362],{"class":245},[224,1456,1457],{"class":226,"line":393},[224,1458,1459],{"class":389},"    \u002F\u002F `event` is narrowed to the generic's event types. Must be idempotent.\n",[224,1461,1462,1465,1467,1470,1473,1475],{"class":226,"line":399},[224,1463,1464],{"class":230},"    if",[224,1466,1431],{"class":252},[224,1468,1469],{"class":245},"!",[224,1471,1472],{"class":241},"userId",[224,1474,926],{"class":252},[224,1476,1477],{"class":230},"return\n",[224,1479,1480],{"class":226,"line":894},[224,1481,396],{"class":245},[224,1483,1484],{"class":226,"line":911},[224,1485,405],{"class":241},[159,1487,1488,1489,1492,1493,1496],{},"Handlers are bundled into a generated server template (",[191,1490,1491],{},"#stripe\u002Fhandlers",") after every module has run ",[191,1494,1495],{},"setup()",", so\nregistration order between modules does not matter and no runtime scanning happens. Registering the same file for the\nsame events twice is a no-op.",[473,1498,1500],{"id":1499},"in-a-host-app","In a host app",[215,1502,1504],{"className":217,"code":1503,"language":219,"meta":220,"style":220},"\u002F\u002F server\u002Fplugins\u002Fstripe.ts\nexport default defineNitroPlugin(() => {\n  onStripeEvent('invoice.payment_failed', async (event, ctx) => {\n    \u002F\u002F notify the user, flag the account, ...\n  })\n})\n",[191,1505,1506,1511,1529,1563,1568,1575],{"__ignoreMap":220},[224,1507,1508],{"class":226,"line":227},[224,1509,1510],{"class":389},"\u002F\u002F server\u002Fplugins\u002Fstripe.ts\n",[224,1512,1513,1515,1517,1520,1522,1525,1527],{"class":226,"line":249},[224,1514,231],{"class":230},[224,1516,234],{"class":230},[224,1518,1519],{"class":237}," defineNitroPlugin",[224,1521,242],{"class":241},[224,1523,1524],{"class":245},"()",[224,1526,1452],{"class":746},[224,1528,362],{"class":245},[224,1530,1531,1534,1536,1538,1541,1543,1545,1548,1550,1552,1554,1557,1559,1561],{"class":226,"line":295},[224,1532,1533],{"class":237},"  onStripeEvent",[224,1535,242],{"class":252},[224,1537,262],{"class":245},[224,1539,1540],{"class":265},"invoice.payment_failed",[224,1542,262],{"class":245},[224,1544,270],{"class":245},[224,1546,1547],{"class":746}," async",[224,1549,1431],{"class":245},[224,1551,1434],{"class":755},[224,1553,270],{"class":245},[224,1555,1556],{"class":755}," ctx",[224,1558,1116],{"class":245},[224,1560,1452],{"class":746},[224,1562,362],{"class":245},[224,1564,1565],{"class":226,"line":354},[224,1566,1567],{"class":389},"    \u002F\u002F notify the user, flag the account, ...\n",[224,1569,1570,1573],{"class":226,"line":365},[224,1571,1572],{"class":245},"  }",[224,1574,405],{"class":252},[224,1576,1577,1579],{"class":226,"line":393},[224,1578,402],{"class":245},[224,1580,405],{"class":241},[159,1582,1583,1584,1587],{},"Runtime handlers use order ",[191,1585,1586],{},"100",", after build-time handlers of equal order.",[473,1589,1591],{"id":1590},"delivery-and-retries","Delivery and retries",[1593,1594,1595,1603,1614],"ul",{},[1596,1597,1598,1599,1602],"li",{},"Matching handlers run sequentially, sorted by ",[191,1600,1601],{},"order"," (stable for equal values). An error in one is logged and does\nnot stop the others.",[1596,1604,1605,1606,1609,1610,1613],{},"If ",[170,1607,1608],{},"any"," handler throws, the webhook responds ",[191,1611,1612],{},"500"," and Stripe retries the whole event, so handlers must be\nidempotent.",[1596,1615,1616,1617,1620],{},"The event id is written to KV (TTL 7 days) only ",[170,1618,1619],{},"after all handlers succeed","; a duplicate delivery is acknowledged\nwithout running handlers again.",[210,1622,1624],{"id":1623},"hooks","Hooks",[411,1626,1627,1640],{},[414,1628,1629],{},[417,1630,1631,1634,1637],{},[420,1632,1633],{},"Hook",[420,1635,1636],{},"When",[420,1638,1639],{},"Payload",[433,1641,1642],{},[417,1643,1644,1649,1656],{},[438,1645,1646],{},[191,1647,1648],{},"stripe:event",[438,1650,1651,1652,1655],{},"Nitro hook, after the handlers ran, for every verified, not yet processed event, ",[170,1653,1654],{},"including events whose handlers failed"," (and will be retried). Errors in it are logged and never fail the webhook.",[438,1657,1658],{},[191,1659,1660],{},"(event: Stripe.Event, ctx: StripeEventHandlerContext)",[210,1662,1664],{"id":1663},"routes","Routes",[411,1666,1667,1681],{},[414,1668,1669],{},[417,1670,1671,1674,1677,1679],{},[420,1672,1673],{},"Method",[420,1675,1676],{},"Path",[420,1678,73],{},[420,1680,431],{},[433,1682,1683],{},[417,1684,1685,1688,1695,1698],{},[438,1686,1687],{},"POST",[438,1689,1690,1431,1692,1116],{},[191,1691,382],{},[191,1693,1694],{},"webhookPath",[438,1696,1697],{},"none (Stripe signature)",[438,1699,1700],{},"Verifies the signature, dispatches the event to handlers.",[159,1702,1703,1704,1707],{},"It reads the raw body and verifies with ",[191,1705,1706],{},"constructEventAsync",". Make sure no auth or CSRF middleware sits in front of it.",[411,1709,1710,1720],{},[414,1711,1712],{},[417,1713,1714,1717],{},[420,1715,1716],{},"Status",[420,1718,1719],{},"Meaning",[433,1721,1722,1739,1753],{},[417,1723,1724,1729],{},[438,1725,1726],{},[191,1727,1728],{},"200",[438,1730,1731,1734,1735,1738],{},[191,1732,1733],{},"{ received: true }",", or ",[191,1736,1737],{},"{ received: true, duplicate: true }"," for an already processed event id.",[417,1740,1741,1746],{},[438,1742,1743],{},[191,1744,1745],{},"400",[438,1747,1748,1749,1752],{},"Missing ",[191,1750,1751],{},"stripe-signature"," header, missing body, or an invalid signature.",[417,1754,1755,1759],{},[438,1756,1757],{},[191,1758,1612],{},[438,1760,1761,1763],{},[191,1762,524],{}," is not set, or at least one handler threw (Stripe will retry).",[473,1765,1767],{"id":1766},"stripe-dashboard-setup","Stripe dashboard setup",[1769,1770,1771,1781,1787],"ol",{},[1596,1772,1773,1774,1777,1778,208],{},"In ",[170,1775,1776],{},"Developers > Webhooks",", add an endpoint pointing at ",[191,1779,1780],{},"https:\u002F\u002F\u003Cyour-host>\u002Fapi\u002Fstripe\u002Fwebhook",[1596,1782,1783,1784,536],{},"Select the events your installed modules need (for example the list in\n",[163,1785,125],{"href":1786},"\u002Fmodules\u002Fsubscriptions#stripe-dashboard-setup",[1596,1788,1789,1790,208],{},"Copy the signing secret into ",[191,1791,524],{},[159,1793,1794],{},"For local development, forward events with the Stripe CLI and use the secret it prints:",[215,1796,1800],{"className":1797,"code":1798,"language":1799,"meta":220,"style":220},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","stripe listen --forward-to localhost:3000\u002Fapi\u002Fstripe\u002Fwebhook\n","bash",[191,1801,1802],{"__ignoreMap":220},[224,1803,1804,1807,1810,1813],{"class":226,"line":227},[224,1805,1806],{"class":761},"stripe",[224,1808,1809],{"class":265}," listen",[224,1811,1812],{"class":265}," --forward-to",[224,1814,1815],{"class":265}," localhost:3000\u002Fapi\u002Fstripe\u002Fwebhook\n",[210,1817,1819],{"id":1818},"database","Database",[159,1821,1822,1823,1827,1828,1431,1830,1833,1834,1837,1838,208],{},"Extends the ",[163,1824,1825],{"href":134},[191,1826,676],{}," table with a nullable ",[191,1829,657],{},[191,1831,1832],{},"stripe_customer_id",") column through\n",[191,1835,1836],{},"extendDatabaseTable",". Do not add it to your host ",[191,1839,1840],{},"extend.sqlite.ts",[1842,1843,1844,1845,208],"warning",{},"The module changes the generated schema, not the database: generate and commit a migration in every host app and\nfixture that uses it. See ",[163,1846,101],{"href":102},[1848,1849,1850],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}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 .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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":220,"searchDepth":249,"depth":249,"links":1852},[1853,1854,1858,1859,1864,1865,1868],{"id":212,"depth":249,"text":213},{"id":408,"depth":249,"text":409,"children":1855},[1856,1857],{"id":475,"depth":295,"text":476},{"id":575,"depth":295,"text":576},{"id":596,"depth":249,"text":597},{"id":788,"depth":249,"text":696,"children":1860},[1861,1862,1863],{"id":1123,"depth":295,"text":1124},{"id":1499,"depth":295,"text":1500},{"id":1590,"depth":295,"text":1591},{"id":1623,"depth":249,"text":1624},{"id":1663,"depth":249,"text":1664,"children":1866},[1867],{"id":1766,"depth":295,"text":1767},{"id":1818,"depth":249,"text":1819},"Stripe core - the SDK client, user-to-customer linking, one verified webhook endpoint and an event-listener API other modules plug into.","md",null,{},{"title":121,"description":1869},"-YT7zUam0G1-JPk-jWt3_jIviyVKd2w1_I287dwasXY",[1876,1878],{"title":117,"path":118,"stem":119,"description":1877,"children":-1},"Typed per-user preferences that modules and the host app register, stored on the user and optionally forwarded to OAuth applications as claims.",{"title":125,"path":126,"stem":127,"description":1879,"children":-1},"Recurring Stripe subscriptions - host-defined plans, checkout, upgrade\u002Fdowngrade, billing portal, entitlements and account UI.",1792824486598]