[{"data":1,"prerenderedAt":3697},["ShallowReactive",2],{"navigation_docs":3,"-packages-laravel-migrating-to-vatly":190,"-packages-laravel-migrating-to-vatly-surround":3692},[4,8,50,103,186],{"title":5,"path":6,"stem":7},"Introduction","/introduction","0.introduction",{"title":9,"path":10,"stem":11,"children":12,"page":49},"Guides","/guides","1.guides",[13,17,21,25,29,33,37,41,45],{"title":14,"path":15,"stem":16},"Quickstart","/guides/quickstart","1.guides/1.quickstart",{"title":18,"path":19,"stem":20},"Selling Workflow","/guides/selling-workflow","1.guides/2.selling-workflow",{"title":22,"path":23,"stem":24},"Vatly SDKs","/guides/sdks","1.guides/3.sdks",{"title":26,"path":27,"stem":28},"Authentication","/guides/authentication","1.guides/4.authentication",{"title":30,"path":31,"stem":32},"Pagination","/guides/pagination","1.guides/5.pagination",{"title":34,"path":35,"stem":36},"Errors","/guides/errors","1.guides/6.errors",{"title":38,"path":39,"stem":40},"Webhooks","/guides/webhooks","1.guides/7.webhooks",{"title":42,"path":43,"stem":44},"Idempotency","/guides/idempotency","1.guides/8.idempotency",{"title":46,"path":47,"stem":48},"Testing","/guides/testing","1.guides/9.testing",false,{"title":51,"path":52,"stem":53,"children":54,"page":49},"Api Reference","/api-reference","2.api-reference",[55,59,63,67,71,75,79,83,87,91,95,99],{"title":56,"path":57,"stem":58},"Customers","/api-reference/customers","2.api-reference/1.customers",{"title":60,"path":61,"stem":62},"Webhook Endpoints","/api-reference/webhook-endpoints","2.api-reference/10.webhook-endpoints",{"title":64,"path":65,"stem":66},"Test helpers","/api-reference/test-helpers","2.api-reference/11.test-helpers",{"title":68,"path":69,"stem":70},"Checkouts","/api-reference/checkouts","2.api-reference/2.checkouts",{"title":72,"path":73,"stem":74},"One-off Products","/api-reference/one-off-products","2.api-reference/3.one-off-products",{"title":76,"path":77,"stem":78},"Subscriptions","/api-reference/subscriptions","2.api-reference/4.subscriptions",{"title":80,"path":81,"stem":82},"Subscription Plans","/api-reference/subscription-plans","2.api-reference/5.subscription-plans",{"title":84,"path":85,"stem":86},"Orders","/api-reference/orders","2.api-reference/6.orders",{"title":88,"path":89,"stem":90},"Order Refunds","/api-reference/refunds","2.api-reference/7.refunds",{"title":92,"path":93,"stem":94},"Refunds","/api-reference/global-refunds","2.api-reference/8.global-refunds",{"title":96,"path":97,"stem":98},"Chargebacks","/api-reference/chargebacks","2.api-reference/9.chargebacks",{"title":100,"path":101,"stem":102},"Webhook Events","/api-reference/webhook-events","2.api-reference/99.webhook-events",{"title":104,"path":105,"stem":106,"children":107},"Packages","/packages","3.packages",[108,111,151],{"title":109,"path":105,"stem":110},"","3.packages/index",{"title":112,"path":113,"stem":114,"children":115,"page":49},"Php","/packages/php","3.packages/1.php",[116,120,123,126,129,132,135,138,142,145,148],{"title":117,"path":118,"stem":119},"Getting Started","/packages/php/readme","3.packages/1.php/0.readme",{"title":56,"path":121,"stem":122},"/packages/php/customers","3.packages/1.php/1.customers",{"title":68,"path":124,"stem":125},"/packages/php/checkouts","3.packages/1.php/2.checkouts",{"title":76,"path":127,"stem":128},"/packages/php/subscriptions","3.packages/1.php/3.subscriptions",{"title":80,"path":130,"stem":131},"/packages/php/subscriptionplans","3.packages/1.php/4.subscriptionplans",{"title":84,"path":133,"stem":134},"/packages/php/orders","3.packages/1.php/5.orders",{"title":92,"path":136,"stem":137},"/packages/php/refunds","3.packages/1.php/6.refunds",{"title":139,"path":140,"stem":141},"One-Off Products","/packages/php/oneoffproducts","3.packages/1.php/7.oneoffproducts",{"title":96,"path":143,"stem":144},"/packages/php/chargebacks","3.packages/1.php/8.chargebacks",{"title":38,"path":146,"stem":147},"/packages/php/webhooks","3.packages/1.php/9.webhooks",{"title":60,"path":149,"stem":150},"/packages/php/webhookendpoints","3.packages/1.php/99.webhookendpoints",{"title":152,"path":153,"stem":154,"children":155,"page":49},"Laravel","/packages/laravel","3.packages/2.laravel",[156,159,162,165,168,171,174,178,182],{"title":117,"path":157,"stem":158},"/packages/laravel/readme","3.packages/2.laravel/0.readme",{"title":56,"path":160,"stem":161},"/packages/laravel/customers","3.packages/2.laravel/1.customers",{"title":68,"path":163,"stem":164},"/packages/laravel/checkouts","3.packages/2.laravel/2.checkouts",{"title":76,"path":166,"stem":167},"/packages/laravel/subscriptions","3.packages/2.laravel/3.subscriptions",{"title":84,"path":169,"stem":170},"/packages/laravel/orders","3.packages/2.laravel/4.orders",{"title":38,"path":172,"stem":173},"/packages/laravel/webhooks","3.packages/2.laravel/5.webhooks",{"title":175,"path":176,"stem":177},"Vs Cashier (Stripe, Paddle) & Lemon Squeezy","/packages/laravel/comparison","3.packages/2.laravel/6.comparison",{"title":179,"path":180,"stem":181},"Migrating from Cashier","/packages/laravel/migrating-to-vatly","3.packages/2.laravel/7.migrating-to-vatly",{"title":183,"path":184,"stem":185},"Configuration","/packages/laravel/configuration","3.packages/2.laravel/99.configuration",{"title":187,"path":188,"stem":189},"Integrations","/integrations","4.integrations",{"id":191,"title":179,"body":192,"description":3686,"extension":3687,"links":3688,"meta":3689,"navigation":761,"path":180,"seo":3690,"stem":181,"__hash__":3691},"docs/3.packages/2.laravel/7.migrating-to-vatly.md",{"type":193,"value":194,"toc":3668},"minimark",[195,204,230,244,247,257,267,387,402,446,515,533,538,541,564,566,574,577,614,620,695,710,720,723,725,729,733,812,826,868,874,919,1033,1036,1080,1103,2445,2769,2773,2776,2826,2878,2881,3021,3025,3030,3111,3115,3122,3163,3166,3168,3172,3189,3553,3556,3607,3609,3613,3647,3664],[196,197,198,199,203],"p",{},"You don't swap a Merchant of Record overnight. The payment mandate for every active customer\nlives with your ",[200,201,202],"em",{},"current"," seller of record, and the only way to move a customer is to have them\nre-authorize at the new one. So in practice you run two billing stacks side by side for a while:\nexisting customers keep paying through the old provider until they re-subscribe, new signups go\nstraight to Vatly, and you retire the old integration once the tail has migrated.",[196,205,206,207,214,215,214,220,225,226,229],{},"This is the integration playbook for exactly that — adding Vatly beside an existing Cashier-style\nintegration (",[208,209,213],"a",{"href":210,"rel":211},"https://laravel.com/docs/12.x/billing",[212],"nofollow","Stripe"," /\n",[208,216,219],{"href":217,"rel":218},"https://laravel.com/docs/12.x/cashier-paddle",[212],"Paddle",[208,221,224],{"href":222,"rel":223},"https://github.com/lmsqueezy/laravel",[212],"Lemon Squeezy","): the one thing you have to resolve, the\nthings that ",[200,227,228],{},"don't"," need resolving, and the step-by-step.",[231,232,233],"blockquote",{},[196,234,235,239,240,243],{},[236,237,238],"strong",{},"Still deciding whether to switch?"," Start with ",[208,241,242],{"href":176},"How Vatly compares"," — the\nside-by-side on the Merchant-of-Record model, features, and what's on the roadmap. This page\nassumes you've decided to run Vatly alongside what you already have.",[245,246],"hr",{},[248,249,251,252,256],"h2",{"id":250},"the-one-thing-that-actually-collides-the-billable-trait","The one thing that actually collides: the ",[253,254,255],"code",{},"Billable"," trait",[196,258,259,260,262,263,266],{},"Every package here is modelled on Cashier, so every one ships a ",[253,261,255],{}," trait that defines the\n",[200,264,265],{},"same"," method names:",[268,269,270,290],"table",{},[271,272,273],"thead",{},[274,275,276,280,283,285,287],"tr",{},[277,278,279],"th",{},"Method",[277,281,213],{"align":282},"center",[277,284,219],{"align":282},[277,286,224],{"align":282},[277,288,289],{"align":282},"Vatly",[291,292,293,310,325,341,356,372],"tbody",{},[274,294,295,301,304,306,308],{},[296,297,298],"td",{},[253,299,300],{},"subscribed()",[296,302,303],{"align":282},"✓",[296,305,303],{"align":282},[296,307,303],{"align":282},[296,309,303],{"align":282},[274,311,312,317,319,321,323],{},[296,313,314],{},[253,315,316],{},"subscription()",[296,318,303],{"align":282},[296,320,303],{"align":282},[296,322,303],{"align":282},[296,324,303],{"align":282},[274,326,327,333,335,337,339],{},[296,328,329,332],{},[253,330,331],{},"subscriptions()"," (relation)",[296,334,303],{"align":282},[296,336,303],{"align":282},[296,338,303],{"align":282},[296,340,303],{"align":282},[274,342,343,348,350,352,354],{},[296,344,345],{},[253,346,347],{},"checkout()",[296,349,303],{"align":282},[296,351,303],{"align":282},[296,353,303],{"align":282},[296,355,303],{"align":282},[274,357,358,363,366,368,370],{},[296,359,360],{},[253,361,362],{},"subscribe()",[296,364,365],{"align":282},"—",[296,367,303],{"align":282},[296,369,303],{"align":282},[296,371,303],{"align":282},[274,373,374,379,381,383,385],{},[296,375,376,332],{},[253,377,378],{},"orders()",[296,380,365],{"align":282},[296,382,365],{"align":282},[296,384,303],{"align":282},[296,386,303],{"align":282},[196,388,389,390,393,394,397,398,401],{},"PHP does not let two traits define the same method on one class — you get a fatal\n",[200,391,392],{},"\"trait method collision\""," the moment you write ",[253,395,396],{},"use LemonSqueezyBillable, VatlyBillable;",". So you\nhave to decide, deliberately, ",[236,399,400],{},"which provider owns the unprefixed method names",".",[231,403,404],{},[196,405,406,410,413,414,416,417,420,421,424,425,424,428,431,432,435,436,439,440,442,443,445],{},[407,408,409],"span",{},"!TIP",[236,411,412],{},"The cleanest fix is often to not share a model at all."," None of these ",[253,415,255],{}," traits is\ntied to ",[253,418,419],{},"User"," — they work on any Eloquent model (",[253,422,423],{},"Team",", ",[253,426,427],{},"Account",[253,429,430],{},"Organization",", …), and\nVatly's records are polymorphic (",[253,433,434],{},"owner_type"," / ",[253,437,438],{},"owner_id","). If your app bills a model that\nisn't already carrying a Cashier-style trait — or you can introduce one — put Vatly's ",[253,441,255],{},"\nthere and the collision disappears entirely. When both providers genuinely must live on the\n",[200,444,265],{}," model, read on.",[231,447,448],{},[196,449,450,453,456,457,435,460,463,464,467,468,470,471,473,474,477,478,481,482,484,485,488,489,492,493,496,497,424,500,503,504,507,508,424,511,514],{},[407,451,452],{},"!IMPORTANT",[236,454,455],{},"The self-call trap."," Plain trait aliasing (",[253,458,459],{},"insteadof",[253,461,462],{},"as",") is ",[200,465,466],{},"not"," enough here, and it\nfails quietly. Vatly's ",[253,469,316],{}," and ",[253,472,300],{}," call ",[253,475,476],{},"$this->subscriptions()","\ninternally. If you alias ",[253,479,480],{},"subscriptions"," to the legacy provider with ",[253,483,459],{},", then\n",[253,486,487],{},"vatlySubscription()"," will read the ",[200,490,491],{},"legacy"," subscriptions table and silently return the wrong\nthing. Aliasing is safe only for the ",[200,494,495],{},"builder"," methods (",[253,498,499],{},"subscribe",[253,501,502],{},"checkout",") that don't\nself-call a relation; the ",[200,505,506],{},"state readers"," (",[253,509,510],{},"subscription",[253,512,513],{},"subscribed",") need their relation to\nstay wired to Vatly.",[196,516,517,518,521,522,525,526,529,532],{},"Because of that trap, the recommended approach below uses Vatly's purpose-built ",[253,519,520],{},"VatlyBillable","\ntrait, which exposes the whole Vatly surface under ",[253,523,524],{},"vatly*"," names and owns its ",[200,527,528],{},"own",[253,530,531],{},"vatlySubscriptions()"," relation — so there's nothing to alias and nothing to cross-wire.",[534,535,537],"h3",{"id":536},"which-provider-owns-the-unprefixed-names","Which provider owns the unprefixed names?",[196,539,540],{},"Pick the one most of your code already calls.",[542,543,544,558],"ul",{},[545,546,547,550,551,554,555,557],"li",{},[236,548,549],{},"During a migration, that's almost always the legacy provider."," Don't churn working call\nsites — keep ",[253,552,553],{},"$user->subscribed()"," meaning \"subscribed via your existing provider\" and give\nVatly a ",[253,556,524],{}," prefix. This is the default below.",[545,559,560,563],{},[236,561,562],{},"Once Vatly is your default"," for new signups and the legacy tail is winding down, flip it:\nmake Vatly the plain trait and reach the shrinking legacy cohort through the old provider's\nmodels directly.",[245,565],{},[248,567,569,570,573],{"id":568},"what-doesnt-collide-and-why-thats-deliberate","What ",[200,571,572],{},"doesn't"," collide — and why that's deliberate",[196,575,576],{},"The trait is the only friction. Everything underneath is namespaced so the two stacks never\nfight:",[196,578,579,582,583,424,586,589,590,424,593,424,596,424,599,602,603,606,607,610,611,613],{},[236,580,581],{},"Database tables."," Vatly prefixes every table — ",[253,584,585],{},"vatly_subscriptions",[253,587,588],{},"vatly_orders",",\n",[253,591,592],{},"vatly_order_lines",[253,594,595],{},"vatly_refunds",[253,597,598],{},"vatly_chargebacks",[253,600,601],{},"vatly_webhook_calls"," — and adds a\nsingle ",[253,604,605],{},"vatly_id"," column to your billable model's table. Nothing of Vatly's overlaps a Cashier\ntable. (Worth knowing: Cashier/Stripe and Cashier/Paddle ",[200,608,609],{},"both"," claim the unprefixed\n",[253,612,480],{}," table, so they can't run side by side without overriding models. Vatly never\ncontends for a table name with anyone.)",[196,615,616,619],{},[236,617,618],{},"Webhooks."," Each provider registers its own route, verified with its own secret, pointed at its\nown dashboard. Run all of them at once:",[268,621,622,635],{},[271,623,624],{},[274,625,626,629,632],{},[277,627,628],{},"Provider",[277,630,631],{},"Route",[277,633,634],{},"Signature secret",[291,636,637,651,665,679],{},[274,638,639,641,646],{},[296,640,213],{},[296,642,643],{},[253,644,645],{},"POST /stripe/webhook",[296,647,648],{},[253,649,650],{},"STRIPE_WEBHOOK_SECRET",[274,652,653,655,660],{},[296,654,219],{},[296,656,657],{},[253,658,659],{},"POST /paddle/webhook",[296,661,662],{},[253,663,664],{},"PADDLE_WEBHOOK_SECRET",[274,666,667,669,674],{},[296,668,224],{},[296,670,671],{},[253,672,673],{},"POST /lemon-squeezy/webhook",[296,675,676],{},[253,677,678],{},"LEMON_SQUEEZY_SIGNING_SECRET",[274,680,681,685,690],{},[296,682,683],{},[236,684,289],{},[296,686,687],{},[253,688,689],{},"POST /webhooks/vatly",[296,691,692],{},[253,693,694],{},"VATLY_WEBHOOK_SECRET",[196,696,697,698,701,702,705,706,709],{},"Vatly uses its own ",[253,699,700],{},"VATLY_*"," environment variables and its own route name (",[253,703,704],{},"vatly.webhook","), so\nit never collides with Cashier's ",[253,707,708],{},"CASHIER_WEBHOOK"," env or anyone else's config.",[196,711,712,715,716,719],{},[236,713,714],{},"Config & service bindings."," Vatly binds its services under its own namespace via\n",[253,717,718],{},"VatlyServiceProvider","; nothing is rebound out from under your existing provider.",[196,721,722],{},"In short: two sets of tables, two webhook endpoints, two dashboards, one model. The only line of\ncode you have to think about is the trait.",[245,724],{},[248,726,728],{"id":727},"add-vatly-beside-your-current-provider","Add Vatly beside your current provider",[534,730,732],{"id":731},"_1-install-and-migrate","1. Install and migrate",[734,735,739],"pre",{"className":736,"code":737,"language":738,"meta":109,"style":109},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","composer require vatly/vatly-laravel:v0.7.0-alpha.14\n\nphp artisan vendor:publish --tag=vatly-config\nphp artisan vendor:publish --tag=vatly-migrations\nphp artisan vendor:publish --tag=vatly-billable-migrations\nphp artisan migrate\n","bash",[253,740,741,756,763,778,790,802],{"__ignoreMap":109},[407,742,745,749,753],{"class":743,"line":744},"line",1,[407,746,748],{"class":747},"sBMFI","composer",[407,750,752],{"class":751},"sfazB"," require",[407,754,755],{"class":751}," vatly/vatly-laravel:v0.7.0-alpha.14\n",[407,757,759],{"class":743,"line":758},2,[407,760,762],{"emptyLinePlaceholder":761},true,"\n",[407,764,766,769,772,775],{"class":743,"line":765},3,[407,767,768],{"class":747},"php",[407,770,771],{"class":751}," artisan",[407,773,774],{"class":751}," vendor:publish",[407,776,777],{"class":751}," --tag=vatly-config\n",[407,779,781,783,785,787],{"class":743,"line":780},4,[407,782,768],{"class":747},[407,784,771],{"class":751},[407,786,774],{"class":751},[407,788,789],{"class":751}," --tag=vatly-migrations\n",[407,791,793,795,797,799],{"class":743,"line":792},5,[407,794,768],{"class":747},[407,796,771],{"class":751},[407,798,774],{"class":751},[407,800,801],{"class":751}," --tag=vatly-billable-migrations\n",[407,803,805,807,809],{"class":743,"line":804},6,[407,806,768],{"class":747},[407,808,771],{"class":751},[407,810,811],{"class":751}," migrate\n",[196,813,814,815,817,818,821,822,825],{},"This adds the ",[253,816,605],{}," column and the ",[253,819,820],{},"vatly_*"," tables. Your existing tables are untouched. Add\nthe Vatly credentials alongside your current ones in ",[253,823,824],{},".env",":",[734,827,831],{"className":828,"code":829,"language":830,"meta":109,"style":109},"language-env shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# existing provider stays exactly as-is — its own keys, untouched\n\n# new, additive:\nVATLY_KEY=test_xxxxxxxxxxxx\nVATLY_WEBHOOK_SECRET=your-webhook-secret\nVATLY_REDIRECT_URL_SUCCESS=https://your-app.test/checkout/success\nVATLY_REDIRECT_URL_CANCELED=https://your-app.test/checkout/canceled\n","env",[253,832,833,838,842,847,852,857,862],{"__ignoreMap":109},[407,834,835],{"class":743,"line":744},[407,836,837],{},"# existing provider stays exactly as-is — its own keys, untouched\n",[407,839,840],{"class":743,"line":758},[407,841,762],{"emptyLinePlaceholder":761},[407,843,844],{"class":743,"line":765},[407,845,846],{},"# new, additive:\n",[407,848,849],{"class":743,"line":780},[407,850,851],{},"VATLY_KEY=test_xxxxxxxxxxxx\n",[407,853,854],{"class":743,"line":792},[407,855,856],{},"VATLY_WEBHOOK_SECRET=your-webhook-secret\n",[407,858,859],{"class":743,"line":804},[407,860,861],{},"VATLY_REDIRECT_URL_SUCCESS=https://your-app.test/checkout/success\n",[407,863,865],{"class":743,"line":864},7,[407,866,867],{},"VATLY_REDIRECT_URL_CANCELED=https://your-app.test/checkout/canceled\n",[534,869,871,872,256],{"id":870},"_2-add-the-vatlybillable-trait","2. Add the ",[253,873,520],{},[196,875,876,879,880,884,885,887,888,424,891,589,894,424,896,424,899,902,903,214,906,435,909,435,912,915,916,918],{},[253,877,878],{},"vatly-laravel"," ships a second trait, ",[236,881,882],{},[253,883,520],{},", built for exactly this. It exposes the\nfull Vatly surface under ",[253,886,524],{},"-prefixed names — ",[253,889,890],{},"vatlySubscribe()",[253,892,893],{},"vatlySubscribed()",[253,895,487],{},[253,897,898],{},"vatlyCheckout()",[253,900,901],{},"vatlyOrder()",", plus the ",[253,904,905],{},"vatlySubscriptions",[253,907,908],{},"vatlyOrders",[253,910,911],{},"vatlyRefunds",[253,913,914],{},"vatlyChargebacks"," relations — so it drops in beside any\nCashier-style ",[253,917,255],{}," with no collision and no aliasing. Add it next to the trait you already\nhave:",[734,920,923],{"className":921,"code":922,"language":768,"meta":109,"style":109},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","// app/Models/User.php\nuse LemonSqueezy\\Laravel\\Billable;   // your existing provider — unchanged\nuse Vatly\\Laravel\\VatlyBillable;     // Vatly, under vatly* names\n\nclass User extends Authenticatable\n{\n    use Billable;          // $user->subscribed(), $user->checkout(), … → existing provider\n    use VatlyBillable;     // $user->vatlySubscribed(), $user->vatlyCheckout(), … → Vatly\n}\n",[253,924,925,931,957,977,981,996,1001,1014,1027],{"__ignoreMap":109},[407,926,927],{"class":743,"line":744},[407,928,930],{"class":929},"sHwdD","// app/Models/User.php\n",[407,932,933,937,941,945,947,949,951,954],{"class":743,"line":758},[407,934,936],{"class":935},"sbssI","use",[407,938,940],{"class":939},"sTEyZ"," LemonSqueezy",[407,942,944],{"class":943},"sMK4o","\\",[407,946,152],{"class":939},[407,948,944],{"class":943},[407,950,255],{"class":939},[407,952,953],{"class":943},";",[407,955,956],{"class":929},"   // your existing provider — unchanged\n",[407,958,959,961,964,966,968,970,972,974],{"class":743,"line":765},[407,960,936],{"class":935},[407,962,963],{"class":939}," Vatly",[407,965,944],{"class":943},[407,967,152],{"class":939},[407,969,944],{"class":943},[407,971,520],{"class":939},[407,973,953],{"class":943},[407,975,976],{"class":929},"     // Vatly, under vatly* names\n",[407,978,979],{"class":743,"line":780},[407,980,762],{"emptyLinePlaceholder":761},[407,982,983,987,990,993],{"class":743,"line":792},[407,984,986],{"class":985},"spNyl","class",[407,988,989],{"class":747}," User",[407,991,992],{"class":985}," extends",[407,994,995],{"class":747}," Authenticatable\n",[407,997,998],{"class":743,"line":804},[407,999,1000],{"class":943},"{\n",[407,1002,1003,1006,1009,1011],{"class":743,"line":864},[407,1004,1005],{"class":935},"    use",[407,1007,1008],{"class":939}," Billable",[407,1010,953],{"class":943},[407,1012,1013],{"class":929},"          // $user->subscribed(), $user->checkout(), … → existing provider\n",[407,1015,1017,1019,1022,1024],{"class":743,"line":1016},8,[407,1018,1005],{"class":935},[407,1020,1021],{"class":939}," VatlyBillable",[407,1023,953],{"class":943},[407,1025,1026],{"class":929},"     // $user->vatlySubscribed(), $user->vatlyCheckout(), … → Vatly\n",[407,1028,1030],{"class":743,"line":1029},9,[407,1031,1032],{"class":943},"}\n",[196,1034,1035],{},"That's the whole integration step. Two things make it safe by construction:",[542,1037,1038,1055],{},[545,1039,1040,1043,1044,435,1046,1048,1049,1051,1052,1054],{},[236,1041,1042],{},"The state readers query their own relation."," ",[253,1045,893],{},[253,1047,487],{}," read\n",[253,1050,531],{},", never an unprefixed ",[253,1053,331],{}," the other provider owns — so the\nself-call trap can't bite.",[545,1056,1057,1060,1061,424,1064,424,1067,589,1070,1073,1074,1076,1077,1079],{},[236,1058,1059],{},"The customer helpers are shared, not duplicated."," Methods whose names already carry \"Vatly\" —\n",[253,1062,1063],{},"createAsVatlyCustomer()",[253,1065,1066],{},"claimVatlyCustomerFromReturn()",[253,1068,1069],{},"asVatlyCustomer()",[253,1071,1072],{},"findBillable()"," — don't collide, so ",[253,1075,520],{}," and the standalone ",[253,1078,255],{}," share one\ntested implementation; a fix to the claim / re-attribution logic reaches both.",[231,1081,1082],{},[196,1083,1084,1087,1088,1090,1091,589,1093,1095,1096,1099,1100,1102],{},[236,1085,1086],{},"Vatly is your only biller?"," Use the plain ",[253,1089,255],{}," trait instead (",[253,1092,362],{},[253,1094,300],{},", …) — see ",[208,1097,1098],{"href":157},"Getting started",". ",[253,1101,520],{}," exists purely for running\nbeside another provider.",[1104,1105,1106,1110,1116],"details",{},[1107,1108,1109],"summary",{},"Under the hood — the equivalent hand-written concern",[196,1111,1112,1113,1115],{},"You never need this; ",[253,1114,520],{}," ships with the package. But if you'd rather own the code — to\nrename methods, narrow the surface, or add behavior — it's essentially this trait over Vatly's\ncomposition root:",[734,1117,1119],{"className":921,"code":1118,"language":768,"meta":109,"style":109},"// app/Billing/VatlyBilling.php\nnamespace App\\Billing;\n\nuse Illuminate\\Database\\Eloquent\\Relations\\MorphMany;\nuse Illuminate\\Http\\Request;\nuse Vatly\\Fluent\\Builders\\CheckoutBuilder;\nuse Vatly\\Fluent\\Builders\\SubscriptionBuilder;\nuse Vatly\\Fluent\\CustomerProfile;\nuse Vatly\\Fluent\\SubscriptionHandle;\nuse Vatly\\Fluent\\Vatly;\nuse Vatly\\Laravel\\Models\\Order as VatlyOrder;\nuse Vatly\\Laravel\\Models\\Subscription as VatlySubscription;\n\ntrait VatlyBilling\n{\n    /** @return MorphMany\u003CVatlySubscription> */\n    public function vatlySubscriptions(): MorphMany\n    {\n        return $this->morphMany(VatlySubscription::class, 'owner')->orderByDesc('created_at');\n    }\n\n    public function vatlySubscribe(): SubscriptionBuilder\n    {\n        return app(Vatly::class)->subscriptionBuilder($this->vatlyProfile());\n    }\n\n    public function vatlyCheckout(): CheckoutBuilder\n    {\n        return app(Vatly::class)->checkoutBuilder($this->vatlyProfile());\n    }\n\n    public function vatlySubscribed(string $type = VatlySubscription::DEFAULT_TYPE): bool\n    {\n        // Uses our own relation — never the legacy one.\n        $sub = $this->vatlySubscriptions()->where('type', $type)->first();\n\n        return $sub !== null && $sub->isActive();\n    }\n\n    public function vatlySubscription(string $type = VatlySubscription::DEFAULT_TYPE): ?SubscriptionHandle\n    {\n        $sub = $this->vatlySubscriptions()->where('type', $type)->first();\n\n        return $sub !== null ? app(Vatly::class)->subscription($sub) : null;\n    }\n\n    /**\n     * Claim an anonymous Vatly customer on the checkout-success redirect.\n     * Mirrors Vatly\\Laravel\\VatlyBillable::claimVatlyCustomerFromReturn().\n     */\n    public function claimVatlyCustomerFromReturn(Request $request, string $key = 'checkout_id'): bool\n    {\n        $checkoutId = $request->query($key);\n\n        if (! is_string($checkoutId) || $checkoutId === '') {\n            return false;\n        }\n\n        $customerId = app(Vatly::class)->customerIdFromCheckout($checkoutId);\n\n        if ($customerId === null) {\n            return false;\n        }\n\n        app(Vatly::class)->customers()->attribute($customerId, (string) $this->getKey());\n        $this->forceFill(['vatly_id' => $customerId])->save();\n\n        // Re-attribute rows the webhook persisted during the anonymous flow.\n        $owner = ['owner_type' => $this->getMorphClass(), 'owner_id' => $this->getKey()];\n        VatlySubscription::query()->whereNull('owner_id')->where('customer_id', $customerId)->update($owner);\n        VatlyOrder::query()->whereNull('owner_id')->where('customer_id', $customerId)->update($owner);\n\n        return true;\n    }\n\n    private function vatlyProfile(): CustomerProfile\n    {\n        return new CustomerProfile(\n            vatlyId: $this->vatly_id,\n            email: $this->email,\n            name: $this->name,\n        );\n    }\n}\n",[253,1120,1121,1126,1142,1146,1175,1193,1216,1237,1254,1271,1288,1317,1344,1349,1358,1363,1386,1405,1411,1464,1470,1475,1490,1495,1525,1530,1535,1550,1555,1581,1586,1591,1628,1633,1639,1683,1688,1719,1724,1729,1763,1768,1805,1810,1853,1858,1863,1869,1875,1881,1887,1929,1934,1960,1965,2002,2011,2017,2022,2053,2058,2075,2082,2087,2092,2136,2169,2174,2180,2224,2277,2327,2332,2340,2345,2350,2366,2371,2385,2399,2414,2429,2435,2440],{"__ignoreMap":109},[407,1122,1123],{"class":743,"line":744},[407,1124,1125],{"class":929},"// app/Billing/VatlyBilling.php\n",[407,1127,1128,1131,1134,1136,1139],{"class":743,"line":758},[407,1129,1130],{"class":935},"namespace",[407,1132,1133],{"class":747}," App",[407,1135,944],{"class":943},[407,1137,1138],{"class":747},"Billing",[407,1140,1141],{"class":943},";\n",[407,1143,1144],{"class":743,"line":765},[407,1145,762],{"emptyLinePlaceholder":761},[407,1147,1148,1150,1153,1155,1158,1160,1163,1165,1168,1170,1173],{"class":743,"line":780},[407,1149,936],{"class":935},[407,1151,1152],{"class":939}," Illuminate",[407,1154,944],{"class":943},[407,1156,1157],{"class":939},"Database",[407,1159,944],{"class":943},[407,1161,1162],{"class":939},"Eloquent",[407,1164,944],{"class":943},[407,1166,1167],{"class":939},"Relations",[407,1169,944],{"class":943},[407,1171,1172],{"class":939},"MorphMany",[407,1174,1141],{"class":943},[407,1176,1177,1179,1181,1183,1186,1188,1191],{"class":743,"line":792},[407,1178,936],{"class":935},[407,1180,1152],{"class":939},[407,1182,944],{"class":943},[407,1184,1185],{"class":939},"Http",[407,1187,944],{"class":943},[407,1189,1190],{"class":939},"Request",[407,1192,1141],{"class":943},[407,1194,1195,1197,1199,1201,1204,1206,1209,1211,1214],{"class":743,"line":804},[407,1196,936],{"class":935},[407,1198,963],{"class":939},[407,1200,944],{"class":943},[407,1202,1203],{"class":939},"Fluent",[407,1205,944],{"class":943},[407,1207,1208],{"class":939},"Builders",[407,1210,944],{"class":943},[407,1212,1213],{"class":939},"CheckoutBuilder",[407,1215,1141],{"class":943},[407,1217,1218,1220,1222,1224,1226,1228,1230,1232,1235],{"class":743,"line":864},[407,1219,936],{"class":935},[407,1221,963],{"class":939},[407,1223,944],{"class":943},[407,1225,1203],{"class":939},[407,1227,944],{"class":943},[407,1229,1208],{"class":939},[407,1231,944],{"class":943},[407,1233,1234],{"class":939},"SubscriptionBuilder",[407,1236,1141],{"class":943},[407,1238,1239,1241,1243,1245,1247,1249,1252],{"class":743,"line":1016},[407,1240,936],{"class":935},[407,1242,963],{"class":939},[407,1244,944],{"class":943},[407,1246,1203],{"class":939},[407,1248,944],{"class":943},[407,1250,1251],{"class":939},"CustomerProfile",[407,1253,1141],{"class":943},[407,1255,1256,1258,1260,1262,1264,1266,1269],{"class":743,"line":1029},[407,1257,936],{"class":935},[407,1259,963],{"class":939},[407,1261,944],{"class":943},[407,1263,1203],{"class":939},[407,1265,944],{"class":943},[407,1267,1268],{"class":939},"SubscriptionHandle",[407,1270,1141],{"class":943},[407,1272,1274,1276,1278,1280,1282,1284,1286],{"class":743,"line":1273},10,[407,1275,936],{"class":935},[407,1277,963],{"class":939},[407,1279,944],{"class":943},[407,1281,1203],{"class":939},[407,1283,944],{"class":943},[407,1285,289],{"class":939},[407,1287,1141],{"class":943},[407,1289,1291,1293,1295,1297,1299,1301,1304,1306,1309,1312,1315],{"class":743,"line":1290},11,[407,1292,936],{"class":935},[407,1294,963],{"class":939},[407,1296,944],{"class":943},[407,1298,152],{"class":939},[407,1300,944],{"class":943},[407,1302,1303],{"class":939},"Models",[407,1305,944],{"class":943},[407,1307,1308],{"class":939},"Order",[407,1310,1311],{"class":935}," as",[407,1313,1314],{"class":747}," VatlyOrder",[407,1316,1141],{"class":943},[407,1318,1320,1322,1324,1326,1328,1330,1332,1334,1337,1339,1342],{"class":743,"line":1319},12,[407,1321,936],{"class":935},[407,1323,963],{"class":939},[407,1325,944],{"class":943},[407,1327,152],{"class":939},[407,1329,944],{"class":943},[407,1331,1303],{"class":939},[407,1333,944],{"class":943},[407,1335,1336],{"class":939},"Subscription",[407,1338,1311],{"class":935},[407,1340,1341],{"class":747}," VatlySubscription",[407,1343,1141],{"class":943},[407,1345,1347],{"class":743,"line":1346},13,[407,1348,762],{"emptyLinePlaceholder":761},[407,1350,1352,1355],{"class":743,"line":1351},14,[407,1353,1354],{"class":985},"trait",[407,1356,1357],{"class":747}," VatlyBilling\n",[407,1359,1361],{"class":743,"line":1360},15,[407,1362,1000],{"class":943},[407,1364,1366,1369,1373,1377,1380,1383],{"class":743,"line":1365},16,[407,1367,1368],{"class":929},"    /** ",[407,1370,1372],{"class":1371},"svl4J","@return",[407,1374,1376],{"class":1375},"sFweD"," MorphMany",[407,1378,1379],{"class":929},"\u003C",[407,1381,1382],{"class":1375},"VatlySubscription",[407,1384,1385],{"class":929},"> */\n",[407,1387,1389,1392,1395,1399,1402],{"class":743,"line":1388},17,[407,1390,1391],{"class":985},"    public",[407,1393,1394],{"class":985}," function",[407,1396,1398],{"class":1397},"s2Zo4"," vatlySubscriptions",[407,1400,1401],{"class":943},"():",[407,1403,1404],{"class":747}," MorphMany\n",[407,1406,1408],{"class":743,"line":1407},18,[407,1409,1410],{"class":943},"    {\n",[407,1412,1414,1418,1421,1424,1427,1429,1432,1434,1437,1440,1443,1446,1449,1452,1454,1456,1459,1461],{"class":743,"line":1413},19,[407,1415,1417],{"class":1416},"s7zQu","        return",[407,1419,1420],{"class":943}," $this->",[407,1422,1423],{"class":1397},"morphMany",[407,1425,1426],{"class":943},"(",[407,1428,1382],{"class":747},[407,1430,1431],{"class":943},"::",[407,1433,986],{"class":935},[407,1435,1436],{"class":943},",",[407,1438,1439],{"class":943}," '",[407,1441,1442],{"class":751},"owner",[407,1444,1445],{"class":943},"'",[407,1447,1448],{"class":943},")->",[407,1450,1451],{"class":1397},"orderByDesc",[407,1453,1426],{"class":943},[407,1455,1445],{"class":943},[407,1457,1458],{"class":751},"created_at",[407,1460,1445],{"class":943},[407,1462,1463],{"class":943},");\n",[407,1465,1467],{"class":743,"line":1466},20,[407,1468,1469],{"class":943},"    }\n",[407,1471,1473],{"class":743,"line":1472},21,[407,1474,762],{"emptyLinePlaceholder":761},[407,1476,1478,1480,1482,1485,1487],{"class":743,"line":1477},22,[407,1479,1391],{"class":985},[407,1481,1394],{"class":985},[407,1483,1484],{"class":1397}," vatlySubscribe",[407,1486,1401],{"class":943},[407,1488,1489],{"class":747}," SubscriptionBuilder\n",[407,1491,1493],{"class":743,"line":1492},23,[407,1494,1410],{"class":943},[407,1496,1498,1500,1503,1505,1507,1509,1511,1513,1516,1519,1522],{"class":743,"line":1497},24,[407,1499,1417],{"class":1416},[407,1501,1502],{"class":1397}," app",[407,1504,1426],{"class":943},[407,1506,289],{"class":747},[407,1508,1431],{"class":943},[407,1510,986],{"class":935},[407,1512,1448],{"class":943},[407,1514,1515],{"class":1397},"subscriptionBuilder",[407,1517,1518],{"class":943},"($this->",[407,1520,1521],{"class":1397},"vatlyProfile",[407,1523,1524],{"class":943},"());\n",[407,1526,1528],{"class":743,"line":1527},25,[407,1529,1469],{"class":943},[407,1531,1533],{"class":743,"line":1532},26,[407,1534,762],{"emptyLinePlaceholder":761},[407,1536,1538,1540,1542,1545,1547],{"class":743,"line":1537},27,[407,1539,1391],{"class":985},[407,1541,1394],{"class":985},[407,1543,1544],{"class":1397}," vatlyCheckout",[407,1546,1401],{"class":943},[407,1548,1549],{"class":747}," CheckoutBuilder\n",[407,1551,1553],{"class":743,"line":1552},28,[407,1554,1410],{"class":943},[407,1556,1558,1560,1562,1564,1566,1568,1570,1572,1575,1577,1579],{"class":743,"line":1557},29,[407,1559,1417],{"class":1416},[407,1561,1502],{"class":1397},[407,1563,1426],{"class":943},[407,1565,289],{"class":747},[407,1567,1431],{"class":943},[407,1569,986],{"class":935},[407,1571,1448],{"class":943},[407,1573,1574],{"class":1397},"checkoutBuilder",[407,1576,1518],{"class":943},[407,1578,1521],{"class":1397},[407,1580,1524],{"class":943},[407,1582,1584],{"class":743,"line":1583},30,[407,1585,1469],{"class":943},[407,1587,1589],{"class":743,"line":1588},31,[407,1590,762],{"emptyLinePlaceholder":761},[407,1592,1594,1596,1598,1601,1603,1606,1609,1612,1615,1617,1619,1622,1625],{"class":743,"line":1593},32,[407,1595,1391],{"class":985},[407,1597,1394],{"class":985},[407,1599,1600],{"class":1397}," vatlySubscribed",[407,1602,1426],{"class":943},[407,1604,1605],{"class":935},"string",[407,1607,1608],{"class":943}," $",[407,1610,1611],{"class":939},"type ",[407,1613,1614],{"class":943},"=",[407,1616,1341],{"class":747},[407,1618,1431],{"class":943},[407,1620,1621],{"class":939},"DEFAULT_TYPE",[407,1623,1624],{"class":943},"):",[407,1626,1627],{"class":935}," bool\n",[407,1629,1631],{"class":743,"line":1630},33,[407,1632,1410],{"class":943},[407,1634,1636],{"class":743,"line":1635},34,[407,1637,1638],{"class":929},"        // Uses our own relation — never the legacy one.\n",[407,1640,1642,1645,1648,1650,1652,1654,1657,1660,1662,1664,1667,1669,1671,1673,1675,1677,1680],{"class":743,"line":1641},35,[407,1643,1644],{"class":943},"        $",[407,1646,1647],{"class":939},"sub ",[407,1649,1614],{"class":943},[407,1651,1420],{"class":943},[407,1653,905],{"class":1397},[407,1655,1656],{"class":943},"()->",[407,1658,1659],{"class":1397},"where",[407,1661,1426],{"class":943},[407,1663,1445],{"class":943},[407,1665,1666],{"class":751},"type",[407,1668,1445],{"class":943},[407,1670,1436],{"class":943},[407,1672,1608],{"class":943},[407,1674,1666],{"class":939},[407,1676,1448],{"class":943},[407,1678,1679],{"class":1397},"first",[407,1681,1682],{"class":943},"();\n",[407,1684,1686],{"class":743,"line":1685},36,[407,1687,762],{"emptyLinePlaceholder":761},[407,1689,1691,1693,1695,1697,1700,1703,1706,1708,1711,1714,1717],{"class":743,"line":1690},37,[407,1692,1417],{"class":1416},[407,1694,1608],{"class":943},[407,1696,1647],{"class":939},[407,1698,1699],{"class":943},"!==",[407,1701,1702],{"class":943}," null",[407,1704,1705],{"class":943}," &&",[407,1707,1608],{"class":943},[407,1709,1710],{"class":939},"sub",[407,1712,1713],{"class":943},"->",[407,1715,1716],{"class":1397},"isActive",[407,1718,1682],{"class":943},[407,1720,1722],{"class":743,"line":1721},38,[407,1723,1469],{"class":943},[407,1725,1727],{"class":743,"line":1726},39,[407,1728,762],{"emptyLinePlaceholder":761},[407,1730,1732,1734,1736,1739,1741,1743,1745,1747,1749,1751,1753,1755,1757,1760],{"class":743,"line":1731},40,[407,1733,1391],{"class":985},[407,1735,1394],{"class":985},[407,1737,1738],{"class":1397}," vatlySubscription",[407,1740,1426],{"class":943},[407,1742,1605],{"class":935},[407,1744,1608],{"class":943},[407,1746,1611],{"class":939},[407,1748,1614],{"class":943},[407,1750,1341],{"class":747},[407,1752,1431],{"class":943},[407,1754,1621],{"class":939},[407,1756,1624],{"class":943},[407,1758,1759],{"class":943}," ?",[407,1761,1762],{"class":747},"SubscriptionHandle\n",[407,1764,1766],{"class":743,"line":1765},41,[407,1767,1410],{"class":943},[407,1769,1771,1773,1775,1777,1779,1781,1783,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803],{"class":743,"line":1770},42,[407,1772,1644],{"class":943},[407,1774,1647],{"class":939},[407,1776,1614],{"class":943},[407,1778,1420],{"class":943},[407,1780,905],{"class":1397},[407,1782,1656],{"class":943},[407,1784,1659],{"class":1397},[407,1786,1426],{"class":943},[407,1788,1445],{"class":943},[407,1790,1666],{"class":751},[407,1792,1445],{"class":943},[407,1794,1436],{"class":943},[407,1796,1608],{"class":943},[407,1798,1666],{"class":939},[407,1800,1448],{"class":943},[407,1802,1679],{"class":1397},[407,1804,1682],{"class":943},[407,1806,1808],{"class":743,"line":1807},43,[407,1809,762],{"emptyLinePlaceholder":761},[407,1811,1813,1815,1817,1819,1821,1823,1825,1827,1829,1831,1833,1835,1837,1839,1842,1844,1847,1850],{"class":743,"line":1812},44,[407,1814,1417],{"class":1416},[407,1816,1608],{"class":943},[407,1818,1647],{"class":939},[407,1820,1699],{"class":943},[407,1822,1702],{"class":943},[407,1824,1759],{"class":943},[407,1826,1502],{"class":1397},[407,1828,1426],{"class":943},[407,1830,289],{"class":747},[407,1832,1431],{"class":943},[407,1834,986],{"class":935},[407,1836,1448],{"class":943},[407,1838,510],{"class":1397},[407,1840,1841],{"class":943},"($",[407,1843,1710],{"class":939},[407,1845,1846],{"class":943},")",[407,1848,1849],{"class":943}," :",[407,1851,1852],{"class":943}," null;\n",[407,1854,1856],{"class":743,"line":1855},45,[407,1857,1469],{"class":943},[407,1859,1861],{"class":743,"line":1860},46,[407,1862,762],{"emptyLinePlaceholder":761},[407,1864,1866],{"class":743,"line":1865},47,[407,1867,1868],{"class":929},"    /**\n",[407,1870,1872],{"class":743,"line":1871},48,[407,1873,1874],{"class":929},"     * Claim an anonymous Vatly customer on the checkout-success redirect.\n",[407,1876,1878],{"class":743,"line":1877},49,[407,1879,1880],{"class":929},"     * Mirrors Vatly\\Laravel\\VatlyBillable::claimVatlyCustomerFromReturn().\n",[407,1882,1884],{"class":743,"line":1883},50,[407,1885,1886],{"class":929},"     */\n",[407,1888,1890,1892,1894,1897,1899,1901,1903,1906,1908,1911,1913,1916,1918,1920,1923,1925,1927],{"class":743,"line":1889},51,[407,1891,1391],{"class":985},[407,1893,1394],{"class":985},[407,1895,1896],{"class":1397}," claimVatlyCustomerFromReturn",[407,1898,1426],{"class":943},[407,1900,1190],{"class":747},[407,1902,1608],{"class":943},[407,1904,1905],{"class":939},"request",[407,1907,1436],{"class":943},[407,1909,1910],{"class":935}," string",[407,1912,1608],{"class":943},[407,1914,1915],{"class":939},"key ",[407,1917,1614],{"class":943},[407,1919,1439],{"class":943},[407,1921,1922],{"class":751},"checkout_id",[407,1924,1445],{"class":943},[407,1926,1624],{"class":943},[407,1928,1627],{"class":935},[407,1930,1932],{"class":743,"line":1931},52,[407,1933,1410],{"class":943},[407,1935,1937,1939,1942,1944,1946,1948,1950,1953,1955,1958],{"class":743,"line":1936},53,[407,1938,1644],{"class":943},[407,1940,1941],{"class":939},"checkoutId ",[407,1943,1614],{"class":943},[407,1945,1608],{"class":943},[407,1947,1905],{"class":939},[407,1949,1713],{"class":943},[407,1951,1952],{"class":1397},"query",[407,1954,1841],{"class":943},[407,1956,1957],{"class":939},"key",[407,1959,1463],{"class":943},[407,1961,1963],{"class":743,"line":1962},54,[407,1964,762],{"emptyLinePlaceholder":761},[407,1966,1968,1971,1974,1977,1979,1982,1984,1987,1989,1991,1994,1997,1999],{"class":743,"line":1967},55,[407,1969,1970],{"class":1416},"        if",[407,1972,1973],{"class":943}," (!",[407,1975,1976],{"class":1397}," is_string",[407,1978,1841],{"class":943},[407,1980,1981],{"class":939},"checkoutId",[407,1983,1846],{"class":943},[407,1985,1986],{"class":943}," ||",[407,1988,1608],{"class":943},[407,1990,1941],{"class":939},[407,1992,1993],{"class":943},"===",[407,1995,1996],{"class":943}," ''",[407,1998,1846],{"class":943},[407,2000,2001],{"class":943}," {\n",[407,2003,2005,2008],{"class":743,"line":2004},56,[407,2006,2007],{"class":1416},"            return",[407,2009,2010],{"class":943}," false;\n",[407,2012,2014],{"class":743,"line":2013},57,[407,2015,2016],{"class":943},"        }\n",[407,2018,2020],{"class":743,"line":2019},58,[407,2021,762],{"emptyLinePlaceholder":761},[407,2023,2025,2027,2030,2032,2034,2036,2038,2040,2042,2044,2047,2049,2051],{"class":743,"line":2024},59,[407,2026,1644],{"class":943},[407,2028,2029],{"class":939},"customerId ",[407,2031,1614],{"class":943},[407,2033,1502],{"class":1397},[407,2035,1426],{"class":943},[407,2037,289],{"class":747},[407,2039,1431],{"class":943},[407,2041,986],{"class":935},[407,2043,1448],{"class":943},[407,2045,2046],{"class":1397},"customerIdFromCheckout",[407,2048,1841],{"class":943},[407,2050,1981],{"class":939},[407,2052,1463],{"class":943},[407,2054,2056],{"class":743,"line":2055},60,[407,2057,762],{"emptyLinePlaceholder":761},[407,2059,2061,2063,2066,2068,2070,2073],{"class":743,"line":2060},61,[407,2062,1970],{"class":1416},[407,2064,2065],{"class":943}," ($",[407,2067,2029],{"class":939},[407,2069,1993],{"class":943},[407,2071,2072],{"class":943}," null)",[407,2074,2001],{"class":943},[407,2076,2078,2080],{"class":743,"line":2077},62,[407,2079,2007],{"class":1416},[407,2081,2010],{"class":943},[407,2083,2085],{"class":743,"line":2084},63,[407,2086,2016],{"class":943},[407,2088,2090],{"class":743,"line":2089},64,[407,2091,762],{"emptyLinePlaceholder":761},[407,2093,2095,2098,2100,2102,2104,2106,2108,2111,2113,2116,2118,2121,2123,2125,2127,2129,2131,2134],{"class":743,"line":2094},65,[407,2096,2097],{"class":1397},"        app",[407,2099,1426],{"class":943},[407,2101,289],{"class":747},[407,2103,1431],{"class":943},[407,2105,986],{"class":935},[407,2107,1448],{"class":943},[407,2109,2110],{"class":1397},"customers",[407,2112,1656],{"class":943},[407,2114,2115],{"class":1397},"attribute",[407,2117,1841],{"class":943},[407,2119,2120],{"class":939},"customerId",[407,2122,1436],{"class":943},[407,2124,507],{"class":943},[407,2126,1605],{"class":985},[407,2128,1846],{"class":943},[407,2130,1420],{"class":943},[407,2132,2133],{"class":1397},"getKey",[407,2135,1524],{"class":943},[407,2137,2139,2142,2145,2148,2150,2152,2154,2157,2159,2161,2164,2167],{"class":743,"line":2138},66,[407,2140,2141],{"class":943},"        $this->",[407,2143,2144],{"class":1397},"forceFill",[407,2146,2147],{"class":943},"([",[407,2149,1445],{"class":943},[407,2151,605],{"class":751},[407,2153,1445],{"class":943},[407,2155,2156],{"class":943}," =>",[407,2158,1608],{"class":943},[407,2160,2120],{"class":939},[407,2162,2163],{"class":943},"])->",[407,2165,2166],{"class":1397},"save",[407,2168,1682],{"class":943},[407,2170,2172],{"class":743,"line":2171},67,[407,2173,762],{"emptyLinePlaceholder":761},[407,2175,2177],{"class":743,"line":2176},68,[407,2178,2179],{"class":929},"        // Re-attribute rows the webhook persisted during the anonymous flow.\n",[407,2181,2183,2185,2188,2190,2193,2195,2197,2199,2201,2203,2206,2209,2211,2213,2215,2217,2219,2221],{"class":743,"line":2182},69,[407,2184,1644],{"class":943},[407,2186,2187],{"class":939},"owner ",[407,2189,1614],{"class":943},[407,2191,2192],{"class":943}," [",[407,2194,1445],{"class":943},[407,2196,434],{"class":751},[407,2198,1445],{"class":943},[407,2200,2156],{"class":943},[407,2202,1420],{"class":943},[407,2204,2205],{"class":1397},"getMorphClass",[407,2207,2208],{"class":943},"(),",[407,2210,1439],{"class":943},[407,2212,438],{"class":751},[407,2214,1445],{"class":943},[407,2216,2156],{"class":943},[407,2218,1420],{"class":943},[407,2220,2133],{"class":1397},[407,2222,2223],{"class":943},"()];\n",[407,2225,2227,2230,2232,2234,2236,2239,2241,2243,2245,2247,2249,2251,2253,2255,2258,2260,2262,2264,2266,2268,2271,2273,2275],{"class":743,"line":2226},70,[407,2228,2229],{"class":747},"        VatlySubscription",[407,2231,1431],{"class":943},[407,2233,1952],{"class":1397},[407,2235,1656],{"class":943},[407,2237,2238],{"class":1397},"whereNull",[407,2240,1426],{"class":943},[407,2242,1445],{"class":943},[407,2244,438],{"class":751},[407,2246,1445],{"class":943},[407,2248,1448],{"class":943},[407,2250,1659],{"class":1397},[407,2252,1426],{"class":943},[407,2254,1445],{"class":943},[407,2256,2257],{"class":751},"customer_id",[407,2259,1445],{"class":943},[407,2261,1436],{"class":943},[407,2263,1608],{"class":943},[407,2265,2120],{"class":939},[407,2267,1448],{"class":943},[407,2269,2270],{"class":1397},"update",[407,2272,1841],{"class":943},[407,2274,1442],{"class":939},[407,2276,1463],{"class":943},[407,2278,2280,2283,2285,2287,2289,2291,2293,2295,2297,2299,2301,2303,2305,2307,2309,2311,2313,2315,2317,2319,2321,2323,2325],{"class":743,"line":2279},71,[407,2281,2282],{"class":747},"        VatlyOrder",[407,2284,1431],{"class":943},[407,2286,1952],{"class":1397},[407,2288,1656],{"class":943},[407,2290,2238],{"class":1397},[407,2292,1426],{"class":943},[407,2294,1445],{"class":943},[407,2296,438],{"class":751},[407,2298,1445],{"class":943},[407,2300,1448],{"class":943},[407,2302,1659],{"class":1397},[407,2304,1426],{"class":943},[407,2306,1445],{"class":943},[407,2308,2257],{"class":751},[407,2310,1445],{"class":943},[407,2312,1436],{"class":943},[407,2314,1608],{"class":943},[407,2316,2120],{"class":939},[407,2318,1448],{"class":943},[407,2320,2270],{"class":1397},[407,2322,1841],{"class":943},[407,2324,1442],{"class":939},[407,2326,1463],{"class":943},[407,2328,2330],{"class":743,"line":2329},72,[407,2331,762],{"emptyLinePlaceholder":761},[407,2333,2335,2337],{"class":743,"line":2334},73,[407,2336,1417],{"class":1416},[407,2338,2339],{"class":943}," true;\n",[407,2341,2343],{"class":743,"line":2342},74,[407,2344,1469],{"class":943},[407,2346,2348],{"class":743,"line":2347},75,[407,2349,762],{"emptyLinePlaceholder":761},[407,2351,2353,2356,2358,2361,2363],{"class":743,"line":2352},76,[407,2354,2355],{"class":985},"    private",[407,2357,1394],{"class":985},[407,2359,2360],{"class":1397}," vatlyProfile",[407,2362,1401],{"class":943},[407,2364,2365],{"class":747}," CustomerProfile\n",[407,2367,2369],{"class":743,"line":2368},77,[407,2370,1410],{"class":943},[407,2372,2374,2376,2379,2382],{"class":743,"line":2373},78,[407,2375,1417],{"class":1416},[407,2377,2378],{"class":935}," new",[407,2380,2381],{"class":747}," CustomerProfile",[407,2383,2384],{"class":943},"(\n",[407,2386,2388,2391,2393,2395,2397],{"class":743,"line":2387},79,[407,2389,2390],{"class":747},"            vatlyId",[407,2392,825],{"class":943},[407,2394,1420],{"class":943},[407,2396,605],{"class":939},[407,2398,589],{"class":943},[407,2400,2402,2405,2407,2409,2412],{"class":743,"line":2401},80,[407,2403,2404],{"class":747},"            email",[407,2406,825],{"class":943},[407,2408,1420],{"class":943},[407,2410,2411],{"class":939},"email",[407,2413,589],{"class":943},[407,2415,2417,2420,2422,2424,2427],{"class":743,"line":2416},81,[407,2418,2419],{"class":747},"            name",[407,2421,825],{"class":943},[407,2423,1420],{"class":943},[407,2425,2426],{"class":939},"name",[407,2428,589],{"class":943},[407,2430,2432],{"class":743,"line":2431},82,[407,2433,2434],{"class":943},"        );\n",[407,2436,2438],{"class":743,"line":2437},83,[407,2439,1469],{"class":943},[407,2441,2443],{"class":743,"line":2442},84,[407,2444,1032],{"class":943},[1104,2446,2447,2453,2468,2760],{},[1107,2448,2449,2452],{},[236,2450,2451],{},"Alternative — trait aliasing"," (only if you're making Vatly primary)",[196,2454,2455,2457,2458,2460,2461,2463,2464,435,2466,825],{},[253,2456,520],{}," keeps the incumbent on the unprefixed names — what you want during a migration. If\ninstead you're making ",[236,2459,289],{}," primary and pushing the legacy provider under a prefix, use\nVatly's standalone ",[253,2462,255],{}," and resolve the collision with ",[253,2465,459],{},[253,2467,462],{},[734,2469,2471],{"className":921,"code":2470,"language":768,"meta":109,"style":109},"use LemonSqueezy\\Laravel\\Billable as LegacyBillable;\nuse Vatly\\Laravel\\Billable as VatlyBaseBillable;\n\nclass User extends Authenticatable\n{\n    use VatlyBaseBillable, LegacyBillable {\n        // Vatly OWNS the unprefixed names — including subscriptions(), so its\n        // internal self-calls stay correct.\n        VatlyBaseBillable::subscriptions  insteadof LegacyBillable;\n        VatlyBaseBillable::subscription   insteadof LegacyBillable;\n        VatlyBaseBillable::subscribed     insteadof LegacyBillable;\n        VatlyBaseBillable::subscribe      insteadof LegacyBillable;\n        VatlyBaseBillable::checkout       insteadof LegacyBillable;\n        VatlyBaseBillable::orders         insteadof LegacyBillable;\n\n        // Legacy provider moves under a prefix; update its call sites accordingly.\n        LegacyBillable::subscriptions as legacySubscriptions;\n        LegacyBillable::subscription  as legacySubscription;\n        LegacyBillable::subscribed    as legacySubscribed;\n        LegacyBillable::subscribe     as legacySubscribe;\n        LegacyBillable::checkout      as legacyCheckout;\n        LegacyBillable::orders        as legacyOrders;\n    }\n}\n",[253,2472,2473,2494,2515,2519,2529,2533,2545,2550,2555,2571,2586,2601,2616,2631,2646,2650,2655,2672,2688,2704,2720,2736,2752,2756],{"__ignoreMap":109},[407,2474,2475,2477,2479,2481,2483,2485,2487,2489,2492],{"class":743,"line":744},[407,2476,936],{"class":935},[407,2478,940],{"class":939},[407,2480,944],{"class":943},[407,2482,152],{"class":939},[407,2484,944],{"class":943},[407,2486,255],{"class":939},[407,2488,1311],{"class":935},[407,2490,2491],{"class":747}," LegacyBillable",[407,2493,1141],{"class":943},[407,2495,2496,2498,2500,2502,2504,2506,2508,2510,2513],{"class":743,"line":758},[407,2497,936],{"class":935},[407,2499,963],{"class":939},[407,2501,944],{"class":943},[407,2503,152],{"class":939},[407,2505,944],{"class":943},[407,2507,255],{"class":939},[407,2509,1311],{"class":935},[407,2511,2512],{"class":747}," VatlyBaseBillable",[407,2514,1141],{"class":943},[407,2516,2517],{"class":743,"line":765},[407,2518,762],{"emptyLinePlaceholder":761},[407,2520,2521,2523,2525,2527],{"class":743,"line":780},[407,2522,986],{"class":985},[407,2524,989],{"class":747},[407,2526,992],{"class":985},[407,2528,995],{"class":747},[407,2530,2531],{"class":743,"line":792},[407,2532,1000],{"class":943},[407,2534,2535,2537,2539,2541,2543],{"class":743,"line":804},[407,2536,1005],{"class":935},[407,2538,2512],{"class":939},[407,2540,1436],{"class":943},[407,2542,2491],{"class":939},[407,2544,2001],{"class":943},[407,2546,2547],{"class":743,"line":864},[407,2548,2549],{"class":929},"        // Vatly OWNS the unprefixed names — including subscriptions(), so its\n",[407,2551,2552],{"class":743,"line":1016},[407,2553,2554],{"class":929},"        // internal self-calls stay correct.\n",[407,2556,2557,2560,2562,2565,2567,2569],{"class":743,"line":1029},[407,2558,2559],{"class":939},"        VatlyBaseBillable",[407,2561,1431],{"class":943},[407,2563,2564],{"class":747},"subscriptions  ",[407,2566,459],{"class":935},[407,2568,2491],{"class":939},[407,2570,1141],{"class":943},[407,2572,2573,2575,2577,2580,2582,2584],{"class":743,"line":1273},[407,2574,2559],{"class":939},[407,2576,1431],{"class":943},[407,2578,2579],{"class":747},"subscription   ",[407,2581,459],{"class":935},[407,2583,2491],{"class":939},[407,2585,1141],{"class":943},[407,2587,2588,2590,2592,2595,2597,2599],{"class":743,"line":1290},[407,2589,2559],{"class":939},[407,2591,1431],{"class":943},[407,2593,2594],{"class":747},"subscribed     ",[407,2596,459],{"class":935},[407,2598,2491],{"class":939},[407,2600,1141],{"class":943},[407,2602,2603,2605,2607,2610,2612,2614],{"class":743,"line":1319},[407,2604,2559],{"class":939},[407,2606,1431],{"class":943},[407,2608,2609],{"class":747},"subscribe      ",[407,2611,459],{"class":935},[407,2613,2491],{"class":939},[407,2615,1141],{"class":943},[407,2617,2618,2620,2622,2625,2627,2629],{"class":743,"line":1346},[407,2619,2559],{"class":939},[407,2621,1431],{"class":943},[407,2623,2624],{"class":747},"checkout       ",[407,2626,459],{"class":935},[407,2628,2491],{"class":939},[407,2630,1141],{"class":943},[407,2632,2633,2635,2637,2640,2642,2644],{"class":743,"line":1351},[407,2634,2559],{"class":939},[407,2636,1431],{"class":943},[407,2638,2639],{"class":747},"orders         ",[407,2641,459],{"class":935},[407,2643,2491],{"class":939},[407,2645,1141],{"class":943},[407,2647,2648],{"class":743,"line":1360},[407,2649,762],{"emptyLinePlaceholder":761},[407,2651,2652],{"class":743,"line":1365},[407,2653,2654],{"class":929},"        // Legacy provider moves under a prefix; update its call sites accordingly.\n",[407,2656,2657,2660,2662,2665,2667,2670],{"class":743,"line":1388},[407,2658,2659],{"class":939},"        LegacyBillable",[407,2661,1431],{"class":943},[407,2663,2664],{"class":747},"subscriptions ",[407,2666,462],{"class":935},[407,2668,2669],{"class":747}," legacySubscriptions",[407,2671,1141],{"class":943},[407,2673,2674,2676,2678,2681,2683,2686],{"class":743,"line":1407},[407,2675,2659],{"class":939},[407,2677,1431],{"class":943},[407,2679,2680],{"class":747},"subscription  ",[407,2682,462],{"class":935},[407,2684,2685],{"class":747}," legacySubscription",[407,2687,1141],{"class":943},[407,2689,2690,2692,2694,2697,2699,2702],{"class":743,"line":1413},[407,2691,2659],{"class":939},[407,2693,1431],{"class":943},[407,2695,2696],{"class":747},"subscribed    ",[407,2698,462],{"class":935},[407,2700,2701],{"class":747}," legacySubscribed",[407,2703,1141],{"class":943},[407,2705,2706,2708,2710,2713,2715,2718],{"class":743,"line":1466},[407,2707,2659],{"class":939},[407,2709,1431],{"class":943},[407,2711,2712],{"class":747},"subscribe     ",[407,2714,462],{"class":935},[407,2716,2717],{"class":747}," legacySubscribe",[407,2719,1141],{"class":943},[407,2721,2722,2724,2726,2729,2731,2734],{"class":743,"line":1472},[407,2723,2659],{"class":939},[407,2725,1431],{"class":943},[407,2727,2728],{"class":747},"checkout      ",[407,2730,462],{"class":935},[407,2732,2733],{"class":747}," legacyCheckout",[407,2735,1141],{"class":943},[407,2737,2738,2740,2742,2745,2747,2750],{"class":743,"line":1477},[407,2739,2659],{"class":939},[407,2741,1431],{"class":943},[407,2743,2744],{"class":747},"orders        ",[407,2746,462],{"class":935},[407,2748,2749],{"class":747}," legacyOrders",[407,2751,1141],{"class":943},[407,2753,2754],{"class":743,"line":1492},[407,2755,1469],{"class":943},[407,2757,2758],{"class":743,"line":1497},[407,2759,1032],{"class":943},[196,2761,2762,2763,2765,2766,2768],{},"Don't hand-alias the inverse (legacy keeps ",[253,2764,480],{},", Vatly pushed under a prefix) — the\nprefixed Vatly readers would then read the wrong relation, the self-call trap above. That case is\nexactly what ",[253,2767,520],{}," is built for, so reach for it instead of aliasing.",[534,2770,2772],{"id":2771},"_3-decide-who-bills-through-whom","3. Decide who bills through whom",[196,2774,2775],{},"Add a column that records which provider owns a given user, and default new signups to Vatly:",[734,2777,2779],{"className":921,"code":2778,"language":768,"meta":109,"style":109},"// migration\n$table->string('billing_provider')->default('vatly'); // existing rows: backfill to 'legacy'\n",[253,2780,2781,2786],{"__ignoreMap":109},[407,2782,2783],{"class":743,"line":744},[407,2784,2785],{"class":929},"// migration\n",[407,2787,2788,2791,2793,2795,2797,2799,2801,2804,2806,2808,2811,2813,2815,2818,2820,2823],{"class":743,"line":758},[407,2789,2790],{"class":943},"$",[407,2792,268],{"class":939},[407,2794,1713],{"class":943},[407,2796,1605],{"class":1397},[407,2798,1426],{"class":943},[407,2800,1445],{"class":943},[407,2802,2803],{"class":751},"billing_provider",[407,2805,1445],{"class":943},[407,2807,1448],{"class":943},[407,2809,2810],{"class":1397},"default",[407,2812,1426],{"class":943},[407,2814,1445],{"class":943},[407,2816,2817],{"class":751},"vatly",[407,2819,1445],{"class":943},[407,2821,2822],{"class":943},");",[407,2824,2825],{"class":929}," // existing rows: backfill to 'legacy'\n",[734,2827,2829],{"className":921,"code":2828,"language":768,"meta":109,"style":109},"// a single gate your UI and middleware can read\npublic function billsThroughVatly(): bool\n{\n    return $this->billing_provider === 'vatly';\n}\n",[253,2830,2831,2836,2850,2854,2874],{"__ignoreMap":109},[407,2832,2833],{"class":743,"line":744},[407,2834,2835],{"class":929},"// a single gate your UI and middleware can read\n",[407,2837,2838,2841,2843,2846,2848],{"class":743,"line":758},[407,2839,2840],{"class":985},"public",[407,2842,1394],{"class":985},[407,2844,2845],{"class":1397}," billsThroughVatly",[407,2847,1401],{"class":943},[407,2849,1627],{"class":935},[407,2851,2852],{"class":743,"line":765},[407,2853,1000],{"class":943},[407,2855,2856,2859,2861,2864,2866,2868,2870,2872],{"class":743,"line":780},[407,2857,2858],{"class":1416},"    return",[407,2860,1420],{"class":943},[407,2862,2863],{"class":939},"billing_provider ",[407,2865,1993],{"class":943},[407,2867,1439],{"class":943},[407,2869,2817],{"class":751},[407,2871,1445],{"class":943},[407,2873,1141],{"class":943},[407,2875,2876],{"class":743,"line":792},[407,2877,1032],{"class":943},[196,2879,2880],{},"Your billing screen then branches on it:",[734,2882,2884],{"className":921,"code":2883,"language":768,"meta":109,"style":109},"if ($user->billsThroughVatly()) {\n    $checkout = $user->vatlySubscribe()->toPlan('subscription_plan_7Hd9Kf2Lm')->create();\n\n    return redirect($checkout->links->checkoutUrl->href);\n}\n\n// legacy cohort keeps its current flow until they choose to move\nreturn redirect($user->checkout('variant-id')); // your existing provider\n",[253,2885,2886,2906,2946,2950,2978,2982,2986,2991],{"__ignoreMap":109},[407,2887,2888,2891,2893,2896,2898,2901,2904],{"class":743,"line":744},[407,2889,2890],{"class":1416},"if",[407,2892,2065],{"class":943},[407,2894,2895],{"class":939},"user",[407,2897,1713],{"class":943},[407,2899,2900],{"class":1397},"billsThroughVatly",[407,2902,2903],{"class":943},"())",[407,2905,2001],{"class":943},[407,2907,2908,2911,2914,2916,2918,2920,2922,2925,2927,2930,2932,2934,2937,2939,2941,2944],{"class":743,"line":758},[407,2909,2910],{"class":943},"    $",[407,2912,2913],{"class":939},"checkout ",[407,2915,1614],{"class":943},[407,2917,1608],{"class":943},[407,2919,2895],{"class":939},[407,2921,1713],{"class":943},[407,2923,2924],{"class":1397},"vatlySubscribe",[407,2926,1656],{"class":943},[407,2928,2929],{"class":1397},"toPlan",[407,2931,1426],{"class":943},[407,2933,1445],{"class":943},[407,2935,2936],{"class":751},"subscription_plan_7Hd9Kf2Lm",[407,2938,1445],{"class":943},[407,2940,1448],{"class":943},[407,2942,2943],{"class":1397},"create",[407,2945,1682],{"class":943},[407,2947,2948],{"class":743,"line":765},[407,2949,762],{"emptyLinePlaceholder":761},[407,2951,2952,2954,2957,2959,2961,2963,2966,2968,2971,2973,2976],{"class":743,"line":780},[407,2953,2858],{"class":1416},[407,2955,2956],{"class":1397}," redirect",[407,2958,1841],{"class":943},[407,2960,502],{"class":939},[407,2962,1713],{"class":943},[407,2964,2965],{"class":939},"links",[407,2967,1713],{"class":943},[407,2969,2970],{"class":939},"checkoutUrl",[407,2972,1713],{"class":943},[407,2974,2975],{"class":939},"href",[407,2977,1463],{"class":943},[407,2979,2980],{"class":743,"line":792},[407,2981,1032],{"class":943},[407,2983,2984],{"class":743,"line":804},[407,2985,762],{"emptyLinePlaceholder":761},[407,2987,2988],{"class":743,"line":864},[407,2989,2990],{"class":929},"// legacy cohort keeps its current flow until they choose to move\n",[407,2992,2993,2996,2998,3000,3002,3004,3006,3008,3010,3013,3015,3018],{"class":743,"line":1016},[407,2994,2995],{"class":1416},"return",[407,2997,2956],{"class":1397},[407,2999,1841],{"class":943},[407,3001,2895],{"class":939},[407,3003,1713],{"class":943},[407,3005,502],{"class":1397},[407,3007,1426],{"class":943},[407,3009,1445],{"class":943},[407,3011,3012],{"class":751},"variant-id",[407,3014,1445],{"class":943},[407,3016,3017],{"class":943},"));",[407,3019,3020],{"class":929}," // your existing provider\n",[534,3022,3024],{"id":3023},"_4-run-both-webhook-endpoints","4. Run both webhook endpoints",[196,3026,3027,3028,1624],{},"Nothing special — register Vatly's webhook URL and secret in the Vatly dashboard, keep your\nexisting provider's webhook pointed where it already is. Subscriptions and orders from each\nprovider sync into their own tables. Listen for Vatly events on Laravel's event bus the usual way\n(see ",[208,3029,38],{"href":172},[734,3031,3033],{"className":921,"code":3032,"language":768,"meta":109,"style":109},"use Vatly\\API\\Webhooks\\Events\\SubscriptionStarted;\n\nEvent::listen(SubscriptionStarted::class, function (SubscriptionStarted $event) {\n    // a customer is now live on Vatly — safe to wind down their legacy subscription\n});\n",[253,3034,3035,3062,3066,3101,3106],{"__ignoreMap":109},[407,3036,3037,3039,3041,3043,3046,3048,3050,3052,3055,3057,3060],{"class":743,"line":744},[407,3038,936],{"class":935},[407,3040,963],{"class":939},[407,3042,944],{"class":943},[407,3044,3045],{"class":939},"API",[407,3047,944],{"class":943},[407,3049,38],{"class":939},[407,3051,944],{"class":943},[407,3053,3054],{"class":939},"Events",[407,3056,944],{"class":943},[407,3058,3059],{"class":939},"SubscriptionStarted",[407,3061,1141],{"class":943},[407,3063,3064],{"class":743,"line":758},[407,3065,762],{"emptyLinePlaceholder":761},[407,3067,3068,3071,3073,3076,3078,3080,3082,3084,3086,3088,3090,3092,3094,3097,3099],{"class":743,"line":765},[407,3069,3070],{"class":747},"Event",[407,3072,1431],{"class":943},[407,3074,3075],{"class":1397},"listen",[407,3077,1426],{"class":943},[407,3079,3059],{"class":747},[407,3081,1431],{"class":943},[407,3083,986],{"class":935},[407,3085,1436],{"class":943},[407,3087,1394],{"class":985},[407,3089,507],{"class":943},[407,3091,3059],{"class":747},[407,3093,1608],{"class":943},[407,3095,3096],{"class":939},"event",[407,3098,1846],{"class":943},[407,3100,2001],{"class":943},[407,3102,3103],{"class":743,"line":780},[407,3104,3105],{"class":929},"    // a customer is now live on Vatly — safe to wind down their legacy subscription\n",[407,3107,3108],{"class":743,"line":792},[407,3109,3110],{"class":943},"});\n",[534,3112,3114],{"id":3113},"_5-migrate-a-customer-the-re-authorization-flow","5. Migrate a customer: the re-authorization flow",[196,3116,3117,3118,3121],{},"A MoR mandate belongs to the legal seller — your old provider's mandate is theirs, Vatly's is\nVatly's. You ",[236,3119,3120],{},"cannot"," transfer a mandate between Merchants of Record; the customer has to\nauthorize payment at the new seller. So a migration is a re-subscribe, sequenced to avoid both a\ndouble charge and a gap in access:",[3123,3124,3125,3128,3135,3142,3155],"ol",{},[545,3126,3127],{},"Show the legacy-active customer a \"move to Vatly\" prompt (a re-authentication, in plain\nlanguage: \"confirm your payment details to switch\").",[545,3129,3130,3131,3134],{},"They complete a fresh Vatly checkout — ",[253,3132,3133],{},"vatlySubscribe()->toPlan(...)->create()"," — which\ncreates the new mandate at Vatly.",[545,3136,3137,3138,3141],{},"On return, ",[253,3139,3140],{},"claimVatlyCustomerFromReturn($request)"," links the new Vatly customer to the user\n(guest-checkout and multi-tab safe).",[545,3143,3144,3150,3151,3154],{},[236,3145,3146,3147,3149],{},"When Vatly's ",[253,3148,3059],{}," webhook lands"," — not before — cancel the legacy\nsubscription at period end (",[253,3152,3153],{},"$user->subscription()->cancel()"," on the legacy trait) so the\ncustomer is never double-billed and never loses access mid-period.",[545,3156,3157,3158,3160,3161,401],{},"Flip ",[253,3159,2803],{}," to ",[253,3162,2817],{},[196,3164,3165],{},"Order matters: start Vatly only after the customer opts in (no surprise charge), cancel legacy\nonly after Vatly is active (no service gap).",[245,3167],{},[248,3169,3171],{"id":3170},"translation-cheat-sheet-cashier-vatly","Translation cheat-sheet (Cashier → Vatly)",[196,3173,3174,3175,3178,3179,3182,3183,3185,3186,3188],{},"Mapping for the engineer or agent porting a flow. Vatly ids are prefixed —\n",[253,3176,3177],{},"subscription_plan_…"," for plans, ",[253,3180,3181],{},"one_off_product_…"," for one-offs. The Vatly column uses the\n",[253,3184,524],{}," methods from the ",[253,3187,520],{}," trait (step 2).",[268,3190,3191,3210],{},[271,3192,3193],{},[274,3194,3195,3198,3201,3204,3206],{},[277,3196,3197],{},"Task",[277,3199,3200],{},"Cashier (Stripe)",[277,3202,3203],{},"Cashier (Paddle)",[277,3205,224],{},[277,3207,3208],{},[236,3209,289],{},[291,3211,3212,3237,3264,3292,3314,3336,3360,3385,3407,3431,3455,3480,3503,3531],{},[274,3213,3214,3217,3222,3227,3232],{},[296,3215,3216],{},"Start a subscription",[296,3218,3219],{},[253,3220,3221],{},"newSubscription('default','price')->create($pm)",[296,3223,3224],{},[253,3225,3226],{},"subscribe('pri_123','default')",[296,3228,3229],{},[253,3230,3231],{},"subscribe('variant')",[296,3233,3234],{},[253,3235,3236],{},"vatlySubscribe()->toPlan('subscription_plan_…')->create()",[274,3238,3239,3242,3247,3253,3259],{},[296,3240,3241],{},"Redirect to checkout",[296,3243,3244],{},[253,3245,3246],{},"->checkout([...])",[296,3248,3249,3252],{},[253,3250,3251],{},"->returnTo($url)"," (Paddle.js)",[296,3254,3255,3256],{},"redirect / ",[253,3257,3258],{},"\u003Cx-lemon-button>",[296,3260,3261],{},[253,3262,3263],{},"redirect($checkout->links->checkoutUrl->href)",[274,3265,3266,3269,3274,3280,3283],{},[296,3267,3268],{},"Free trial",[296,3270,3271],{},[253,3272,3273],{},"->trialDays(14)",[296,3275,3276,3277],{},"plan-level / ",[253,3278,3279],{},"->trialDays()",[296,3281,3282],{},"plan-level",[296,3284,3285,3288,3289],{},[253,3286,3287],{},"->withTrialDays(14)"," or ",[253,3290,3291],{},"->withTrialEndsAt($date)",[274,3293,3294,3297,3302,3306,3310],{},[296,3295,3296],{},"Is subscribed?",[296,3298,3299],{},[253,3300,3301],{},"subscribed('default')",[296,3303,3304],{},[253,3305,300],{},[296,3307,3308],{},[253,3309,300],{},[296,3311,3312],{},[253,3313,893],{},[274,3315,3316,3319,3324,3328,3332],{},[296,3317,3318],{},"Get the subscription",[296,3320,3321],{},[253,3322,3323],{},"subscription('default')",[296,3325,3326],{},[253,3327,316],{},[296,3329,3330],{},[253,3331,316],{},[296,3333,3334],{},[253,3335,487],{},[274,3337,3338,3341,3346,3351,3355],{},[296,3339,3340],{},"In grace period?",[296,3342,3343],{},[253,3344,3345],{},"subscription()->onGracePeriod()",[296,3347,3348],{},[253,3349,3350],{},"->onGracePeriod()",[296,3352,3353],{},[253,3354,3350],{},[296,3356,3357],{},[253,3358,3359],{},"vatlySubscription()->onGracePeriod()",[274,3361,3362,3365,3370,3375,3380],{},[296,3363,3364],{},"Swap plan",[296,3366,3367],{},[253,3368,3369],{},"subscription()->swap('price')",[296,3371,3372],{},[253,3373,3374],{},"->swap('pri')",[296,3376,3377],{},[253,3378,3379],{},"->swap('prod','variant')",[296,3381,3382],{},[253,3383,3384],{},"vatlySubscription()->swap('subscription_plan_…')",[274,3386,3387,3390,3395,3397,3402],{},[296,3388,3389],{},"Swap + invoice now",[296,3391,3392],{},[253,3393,3394],{},"->swapAndInvoice('price')",[296,3396,365],{},[296,3398,3399],{},[253,3400,3401],{},"->swapAndInvoice(...)",[296,3403,3404],{},[253,3405,3406],{},"vatlySubscription()->swapAndInvoice('subscription_plan_…')",[274,3408,3409,3412,3417,3422,3426],{},[296,3410,3411],{},"Cancel (grace)",[296,3413,3414],{},[253,3415,3416],{},"subscription()->cancel()",[296,3418,3419],{},[253,3420,3421],{},"->cancel()",[296,3423,3424],{},[253,3425,3421],{},[296,3427,3428],{},[253,3429,3430],{},"vatlySubscription()->cancel()",[274,3432,3433,3436,3441,3446,3450],{},[296,3434,3435],{},"Resume",[296,3437,3438],{},[253,3439,3440],{},"subscription()->resume()",[296,3442,3443],{},[253,3444,3445],{},"->resume()",[296,3447,3448],{},[253,3449,3445],{},[296,3451,3452],{},[253,3453,3454],{},"vatlySubscription()->resume()",[274,3456,3457,3460,3465,3470,3475],{},[296,3458,3459],{},"One-off purchase",[296,3461,3462],{},[253,3463,3464],{},"checkout(['price'=>1])",[296,3466,3467],{},[253,3468,3469],{},"checkout('pri_123')",[296,3471,3472],{},[253,3473,3474],{},"checkout('variant')",[296,3476,3477],{},[253,3478,3479],{},"vatlyCheckout()->create(items: [['id'=>'one_off_product_…','quantity'=>1]], redirectUrlSuccess: …, redirectUrlCanceled: …)",[274,3481,3482,3485,3490,3493,3498],{},[296,3483,3484],{},"Update payment / billing",[296,3486,3487],{},[253,3488,3489],{},"redirectToBillingPortal()",[296,3491,3492],{},"hosted update",[296,3494,3495],{},[253,3496,3497],{},"redirect($portalUrl)",[296,3499,3500],{},[253,3501,3502],{},"vatlySubscription()->updateBilling()",[274,3504,3505,3508,3513,3518,3522],{},[296,3506,3507],{},"List orders / receipts",[296,3509,3510],{},[253,3511,3512],{},"invoices()",[296,3514,3515],{},[253,3516,3517],{},"transactions()",[296,3519,3520],{},[253,3521,378],{},[296,3523,3524,3527,3528],{},[253,3525,3526],{},"$user->vatlyOrders"," → ",[253,3529,3530],{},"$order->invoiceUrl()",[274,3532,3533,3536,3541,3546,3549],{},[296,3534,3535],{},"Customer id field",[296,3537,3538],{},[253,3539,3540],{},"stripe_id",[296,3542,3543],{},[253,3544,3545],{},"paddle_id",[296,3547,3548],{},"(relation)",[296,3550,3551],{},[253,3552,605],{},[196,3554,3555],{},"A couple of shape differences worth flagging for whoever's implementing:",[542,3557,3558,3575,3590],{},[545,3559,3560,3563,3564,3567,3568,424,3571,3574],{},[236,3561,3562],{},"Vatly checkout is a server-side redirect",", like Stripe Checkout — you build the checkout\nserver-side and ",[253,3565,3566],{},"redirect()"," to a hosted URL. Paddle and Lemon Squeezy lean on a client-side JS\noverlay (",[253,3569,3570],{},"@paddleJS",[253,3572,3573],{},"@lemonJS","). If you're moving off an overlay, you're removing front-end\nJS, not adding it.",[545,3576,3577,3580,3581,3584,3585,3587,3588,401],{},[236,3578,3579],{},"Guest checkout"," is first-class in Vatly: put ",[253,3582,3583],{},"{CHECKOUT_ID}"," in your return URL and call\n",[253,3586,1066],{}," on the way back to link the purchase — no session plumbing,\nmulti-tab safe. See ",[208,3589,56],{"href":160},[545,3591,3592,3595,3596,589,3599,3602,3603,3606],{},[236,3593,3594],{},"Refunds and chargebacks are real models"," in Vatly (",[253,3597,3598],{},"$user->vatlyRefunds",[253,3600,3601],{},"$order->chargebacks",", reversal helpers like ",[253,3604,3605],{},"$order->isFullyReversed()","), with dedicated\nwebhook events — not something you reconstruct from raw payloads.",[245,3608],{},[248,3610,3612],{"id":3611},"reference","Reference",[542,3614,3615,3623,3632],{},[545,3616,3617,3527,3620,3622],{},[236,3618,3619],{},"Deciding / comparing",[208,3621,242],{"href":176}," (Merchant-of-Record model,\nfeature parity, roadmap)",[545,3624,3625,3527,3627,3629,3630],{},[236,3626,1098],{},[208,3628,1098],{"href":157}," · ",[208,3631,183],{"href":184},[545,3633,3634,3527,3637,3629,3639,3629,3641,3629,3643,3629,3645],{},[236,3635,3636],{},"API surface",[208,3638,56],{"href":160},[208,3640,68],{"href":163},[208,3642,76],{"href":166},[208,3644,84],{"href":169},[208,3646,38],{"href":172},[196,3648,3649,3650,3654,3655,3654,3659,3663],{},"Compared against, at time of writing:\n",[208,3651,3653],{"href":210,"rel":3652},[212],"Laravel Cashier (Stripe)"," ·\n",[208,3656,3658],{"href":217,"rel":3657},[212],"Laravel Cashier (Paddle)",[208,3660,3662],{"href":222,"rel":3661},[212],"Lemon Squeezy for Laravel",".\nMethod names and table layouts follow those packages' current releases — verify against the\nversion you have pinned before relying on a specific signature.",[3665,3666,3667],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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 .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .svl4J, html code.shiki .svl4J{--shiki-light:#F76D47;--shiki-light-font-style:italic;--shiki-default:#F78C6C;--shiki-default-font-style:italic;--shiki-dark:#F78C6C;--shiki-dark-font-style:italic}html pre.shiki code .sFweD, html code.shiki .sFweD{--shiki-light:#E2931D;--shiki-light-font-style:italic;--shiki-default:#FFCB6B;--shiki-default-font-style:italic;--shiki-dark:#FFCB6B;--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 .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}",{"title":109,"searchDepth":758,"depth":758,"links":3669},[3670,3674,3676,3684,3685],{"id":250,"depth":758,"text":3671,"children":3672},"The one thing that actually collides: the Billable trait",[3673],{"id":536,"depth":765,"text":537},{"id":568,"depth":758,"text":3675},"What doesn't collide — and why that's deliberate",{"id":727,"depth":758,"text":728,"children":3677},[3678,3679,3681,3682,3683],{"id":731,"depth":765,"text":732},{"id":870,"depth":765,"text":3680},"2. Add the VatlyBillable trait",{"id":2771,"depth":765,"text":2772},{"id":3023,"depth":765,"text":3024},{"id":3113,"depth":765,"text":3114},{"id":3170,"depth":758,"text":3171},{"id":3611,"depth":758,"text":3612},"Vatly Laravel Package - Migrating from Cashier","md",null,{},{"title":179,"description":3686},"vKnSkUsGCxWXVK24VTmaJ-OWeup3yNvjaUBeyrJ2E3Q",[3693,3695],{"title":175,"path":176,"stem":177,"description":3694,"children":-1},"Vatly Laravel Package - Vs Cashier (Stripe, Paddle) & Lemon Squeezy",{"title":183,"path":184,"stem":185,"description":3696,"children":-1},"Vatly Laravel Package - Configuration",1783281131447]