[{"data":1,"prerenderedAt":1393},["ShallowReactive",2],{"navigation_docs":3,"-packages-fluent-php-testing":465,"-packages-fluent-php-testing-surround":1388},[4,8,62,115,450],{"title":5,"path":6,"stem":7},"Introduction","\u002Fintroduction","0.introduction",{"title":9,"path":10,"stem":11,"children":12,"page":61},"Guides","\u002Fguides","1.guides",[13,17,21,25,29,33,37,41,45,49,53,57],{"title":14,"path":15,"stem":16},"Quickstart","\u002Fguides\u002Fquickstart","1.guides\u002F1.quickstart",{"title":18,"path":19,"stem":20},"Payouts & Settlement","\u002Fguides\u002Fpayouts","1.guides\u002F10.payouts",{"title":22,"path":23,"stem":24},"Customer Emails","\u002Fguides\u002Fcustomer-emails","1.guides\u002F11.customer-emails",{"title":26,"path":27,"stem":28},"Build your own integration","\u002Fguides\u002Fbuild-your-own-integration","1.guides\u002F2.build-your-own-integration",{"title":30,"path":31,"stem":32},"Selling Workflow","\u002Fguides\u002Fselling-workflow","1.guides\u002F2.selling-workflow",{"title":34,"path":35,"stem":36},"Vatly SDKs","\u002Fguides\u002Fsdks","1.guides\u002F3.sdks",{"title":38,"path":39,"stem":40},"Authentication","\u002Fguides\u002Fauthentication","1.guides\u002F4.authentication",{"title":42,"path":43,"stem":44},"Pagination","\u002Fguides\u002Fpagination","1.guides\u002F5.pagination",{"title":46,"path":47,"stem":48},"Errors","\u002Fguides\u002Ferrors","1.guides\u002F6.errors",{"title":50,"path":51,"stem":52},"Webhooks","\u002Fguides\u002Fwebhooks","1.guides\u002F7.webhooks",{"title":54,"path":55,"stem":56},"Idempotency","\u002Fguides\u002Fidempotency","1.guides\u002F8.idempotency",{"title":58,"path":59,"stem":60},"Testing","\u002Fguides\u002Ftesting","1.guides\u002F9.testing",false,{"title":63,"path":64,"stem":65,"children":66,"page":61},"Api Reference","\u002Fapi-reference","2.api-reference",[67,71,75,79,83,87,91,95,99,103,107,111],{"title":68,"path":69,"stem":70},"Customers","\u002Fapi-reference\u002Fcustomers","2.api-reference\u002F1.customers",{"title":72,"path":73,"stem":74},"Webhook Endpoints","\u002Fapi-reference\u002Fwebhook-endpoints","2.api-reference\u002F10.webhook-endpoints",{"title":76,"path":77,"stem":78},"Test helpers","\u002Fapi-reference\u002Ftest-helpers","2.api-reference\u002F11.test-helpers",{"title":80,"path":81,"stem":82},"Checkouts","\u002Fapi-reference\u002Fcheckouts","2.api-reference\u002F2.checkouts",{"title":84,"path":85,"stem":86},"One-off Products","\u002Fapi-reference\u002Fone-off-products","2.api-reference\u002F3.one-off-products",{"title":88,"path":89,"stem":90},"Subscriptions","\u002Fapi-reference\u002Fsubscriptions","2.api-reference\u002F4.subscriptions",{"title":92,"path":93,"stem":94},"Subscription Plans","\u002Fapi-reference\u002Fsubscription-plans","2.api-reference\u002F5.subscription-plans",{"title":96,"path":97,"stem":98},"Orders","\u002Fapi-reference\u002Forders","2.api-reference\u002F6.orders",{"title":100,"path":101,"stem":102},"Order Refunds","\u002Fapi-reference\u002Frefunds","2.api-reference\u002F7.refunds",{"title":104,"path":105,"stem":106},"Refunds","\u002Fapi-reference\u002Fglobal-refunds","2.api-reference\u002F8.global-refunds",{"title":108,"path":109,"stem":110},"Chargebacks","\u002Fapi-reference\u002Fchargebacks","2.api-reference\u002F9.chargebacks",{"title":112,"path":113,"stem":114},"Webhook Events","\u002Fapi-reference\u002Fwebhook-events","2.api-reference\u002F99.webhook-events",{"title":116,"path":117,"stem":118,"children":119},"Packages","\u002Fpackages","3.packages",[120,122,164,210,244,283,318,366,408],{"title":116,"path":117,"stem":121},"3.packages\u002Findex",{"title":123,"path":124,"stem":125,"children":126,"page":61},"PHP SDK","\u002Fpackages\u002Fphp","3.packages\u002F1.php",[127,131,134,137,140,144,147,151,154,157,160],{"title":128,"path":129,"stem":130},"Getting started","\u002Fpackages\u002Fphp\u002Freadme","3.packages\u002F1.php\u002F00.readme",{"title":68,"path":132,"stem":133},"\u002Fpackages\u002Fphp\u002Fcustomers","3.packages\u002F1.php\u002F02.customers",{"title":80,"path":135,"stem":136},"\u002Fpackages\u002Fphp\u002Fcheckouts","3.packages\u002F1.php\u002F03.checkouts",{"title":88,"path":138,"stem":139},"\u002Fpackages\u002Fphp\u002Fsubscriptions","3.packages\u002F1.php\u002F04.subscriptions",{"title":141,"path":142,"stem":143},"Subscription plans","\u002Fpackages\u002Fphp\u002Fsubscriptionplans","3.packages\u002F1.php\u002F05.subscriptionplans",{"title":96,"path":145,"stem":146},"\u002Fpackages\u002Fphp\u002Forders","3.packages\u002F1.php\u002F06.orders",{"title":148,"path":149,"stem":150},"One-off products","\u002Fpackages\u002Fphp\u002Foneoffproducts","3.packages\u002F1.php\u002F07.oneoffproducts",{"title":104,"path":152,"stem":153},"\u002Fpackages\u002Fphp\u002Frefunds","3.packages\u002F1.php\u002F08.refunds",{"title":108,"path":155,"stem":156},"\u002Fpackages\u002Fphp\u002Fchargebacks","3.packages\u002F1.php\u002F09.chargebacks",{"title":50,"path":158,"stem":159},"\u002Fpackages\u002Fphp\u002Fwebhooks","3.packages\u002F1.php\u002F10.webhooks",{"title":161,"path":162,"stem":163},"Webhook URLs","\u002Fpackages\u002Fphp\u002Fwebhookendpoints","3.packages\u002F1.php\u002F11.webhookendpoints",{"title":165,"path":166,"stem":167,"children":168,"page":61},"PHP Fluent","\u002Fpackages\u002Ffluent-php","3.packages\u002F2.fluent-php",[169,172,176,180,183,186,189,192,196,199,203,207],{"title":128,"path":170,"stem":171},"\u002Fpackages\u002Ffluent-php\u002Freadme","3.packages\u002F2.fluent-php\u002F00.readme",{"title":173,"path":174,"stem":175},"Configuration","\u002Fpackages\u002Ffluent-php\u002Fconfiguration","3.packages\u002F2.fluent-php\u002F01.configuration",{"title":177,"path":178,"stem":179},"Core concepts","\u002Fpackages\u002Ffluent-php\u002Fcoreconcepts","3.packages\u002F2.fluent-php\u002F02.coreconcepts",{"title":68,"path":181,"stem":182},"\u002Fpackages\u002Ffluent-php\u002Fcustomers","3.packages\u002F2.fluent-php\u002F03.customers",{"title":80,"path":184,"stem":185},"\u002Fpackages\u002Ffluent-php\u002Fcheckouts","3.packages\u002F2.fluent-php\u002F04.checkouts",{"title":88,"path":187,"stem":188},"\u002Fpackages\u002Ffluent-php\u002Fsubscriptions","3.packages\u002F2.fluent-php\u002F05.subscriptions",{"title":96,"path":190,"stem":191},"\u002Fpackages\u002Ffluent-php\u002Forders","3.packages\u002F2.fluent-php\u002F06.orders",{"title":193,"path":194,"stem":195},"Customer portal","\u002Fpackages\u002Ffluent-php\u002Fcustomerportal","3.packages\u002F2.fluent-php\u002F07.customerportal",{"title":50,"path":197,"stem":198},"\u002Fpackages\u002Ffluent-php\u002Fwebhooks","3.packages\u002F2.fluent-php\u002F08.webhooks",{"title":200,"path":201,"stem":202},"Webhook event flow","\u002Fpackages\u002Ffluent-php\u002Fwebhook-flow","3.packages\u002F2.fluent-php\u002F09.webhook-flow",{"title":204,"path":205,"stem":206},"Existing tables","\u002Fpackages\u002Ffluent-php\u002Fhost-owns-its-tables","3.packages\u002F2.fluent-php\u002F10.host-owns-its-tables",{"title":58,"path":208,"stem":209},"\u002Fpackages\u002Ffluent-php\u002Ftesting","3.packages\u002F2.fluent-php\u002F11.testing",{"title":211,"path":212,"stem":213,"children":214,"page":61},"Laravel","\u002Fpackages\u002Flaravel","3.packages\u002F3.laravel",[215,218,221,224,227,230,233,236,240],{"title":128,"path":216,"stem":217},"\u002Fpackages\u002Flaravel\u002Freadme","3.packages\u002F3.laravel\u002F00.readme",{"title":173,"path":219,"stem":220},"\u002Fpackages\u002Flaravel\u002Fconfiguration","3.packages\u002F3.laravel\u002F01.configuration",{"title":68,"path":222,"stem":223},"\u002Fpackages\u002Flaravel\u002Fcustomers","3.packages\u002F3.laravel\u002F02.customers",{"title":80,"path":225,"stem":226},"\u002Fpackages\u002Flaravel\u002Fcheckouts","3.packages\u002F3.laravel\u002F03.checkouts",{"title":88,"path":228,"stem":229},"\u002Fpackages\u002Flaravel\u002Fsubscriptions","3.packages\u002F3.laravel\u002F04.subscriptions",{"title":96,"path":231,"stem":232},"\u002Fpackages\u002Flaravel\u002Forders","3.packages\u002F3.laravel\u002F05.orders",{"title":50,"path":234,"stem":235},"\u002Fpackages\u002Flaravel\u002Fwebhooks","3.packages\u002F3.laravel\u002F06.webhooks",{"title":237,"path":238,"stem":239},"Comparison","\u002Fpackages\u002Flaravel\u002Fcomparison","3.packages\u002F3.laravel\u002F07.comparison",{"title":241,"path":242,"stem":243},"Migrating from Cashier","\u002Fpackages\u002Flaravel\u002Fmigrating-to-vatly","3.packages\u002F3.laravel\u002F08.migrating-to-vatly",{"title":245,"path":246,"stem":247,"children":248,"page":61},"JavaScript SDK","\u002Fpackages\u002Fjavascript","3.packages\u002F4.javascript",[249,252,255,258,261,264,267,270,273,276,279],{"title":128,"path":250,"stem":251},"\u002Fpackages\u002Fjavascript\u002Freadme","3.packages\u002F4.javascript\u002F00.readme",{"title":68,"path":253,"stem":254},"\u002Fpackages\u002Fjavascript\u002Fcustomers","3.packages\u002F4.javascript\u002F02.customers",{"title":80,"path":256,"stem":257},"\u002Fpackages\u002Fjavascript\u002Fcheckouts","3.packages\u002F4.javascript\u002F03.checkouts",{"title":88,"path":259,"stem":260},"\u002Fpackages\u002Fjavascript\u002Fsubscriptions","3.packages\u002F4.javascript\u002F04.subscriptions",{"title":141,"path":262,"stem":263},"\u002Fpackages\u002Fjavascript\u002Fsubscriptionplans","3.packages\u002F4.javascript\u002F05.subscriptionplans",{"title":96,"path":265,"stem":266},"\u002Fpackages\u002Fjavascript\u002Forders","3.packages\u002F4.javascript\u002F06.orders",{"title":148,"path":268,"stem":269},"\u002Fpackages\u002Fjavascript\u002Foneoffproducts","3.packages\u002F4.javascript\u002F07.oneoffproducts",{"title":104,"path":271,"stem":272},"\u002Fpackages\u002Fjavascript\u002Frefunds","3.packages\u002F4.javascript\u002F08.refunds",{"title":108,"path":274,"stem":275},"\u002Fpackages\u002Fjavascript\u002Fchargebacks","3.packages\u002F4.javascript\u002F09.chargebacks",{"title":50,"path":277,"stem":278},"\u002Fpackages\u002Fjavascript\u002Fwebhooks","3.packages\u002F4.javascript\u002F10.webhooks",{"title":280,"path":281,"stem":282},"API reference","\u002Fpackages\u002Fjavascript\u002Fapi","3.packages\u002F4.javascript\u002F12.api",{"title":284,"path":285,"stem":286,"children":287,"page":61},"JavaScript Fluent","\u002Fpackages\u002Ffluent-js","3.packages\u002F5.fluent-js",[288,291,294,297,300,303,306,309,312,315],{"title":128,"path":289,"stem":290},"\u002Fpackages\u002Ffluent-js\u002Freadme","3.packages\u002F5.fluent-js\u002F00.readme",{"title":173,"path":292,"stem":293},"\u002Fpackages\u002Ffluent-js\u002Fconfiguration","3.packages\u002F5.fluent-js\u002F01.configuration",{"title":177,"path":295,"stem":296},"\u002Fpackages\u002Ffluent-js\u002Fcoreconcepts","3.packages\u002F5.fluent-js\u002F02.coreconcepts",{"title":68,"path":298,"stem":299},"\u002Fpackages\u002Ffluent-js\u002Fcustomers","3.packages\u002F5.fluent-js\u002F03.customers",{"title":80,"path":301,"stem":302},"\u002Fpackages\u002Ffluent-js\u002Fcheckouts","3.packages\u002F5.fluent-js\u002F04.checkouts",{"title":88,"path":304,"stem":305},"\u002Fpackages\u002Ffluent-js\u002Fsubscriptions","3.packages\u002F5.fluent-js\u002F05.subscriptions",{"title":96,"path":307,"stem":308},"\u002Fpackages\u002Ffluent-js\u002Forders","3.packages\u002F5.fluent-js\u002F06.orders",{"title":193,"path":310,"stem":311},"\u002Fpackages\u002Ffluent-js\u002Fcustomerportal","3.packages\u002F5.fluent-js\u002F07.customerportal",{"title":50,"path":313,"stem":314},"\u002Fpackages\u002Ffluent-js\u002Fwebhooks","3.packages\u002F5.fluent-js\u002F08.webhooks",{"title":58,"path":316,"stem":317},"\u002Fpackages\u002Ffluent-js\u002Ftesting","3.packages\u002F5.fluent-js\u002F11.testing",{"title":319,"path":320,"stem":321,"children":322,"page":61},"Python SDK","\u002Fpackages\u002Fpython","3.packages\u002F6.python",[323,326,329,332,335,338,341,344,347,350,353,356,359,362],{"title":128,"path":324,"stem":325},"\u002Fpackages\u002Fpython\u002Freadme","3.packages\u002F6.python\u002F00.readme",{"title":173,"path":327,"stem":328},"\u002Fpackages\u002Fpython\u002Fconfiguration","3.packages\u002F6.python\u002F01.configuration",{"title":68,"path":330,"stem":331},"\u002Fpackages\u002Fpython\u002Fcustomers","3.packages\u002F6.python\u002F02.customers",{"title":80,"path":333,"stem":334},"\u002Fpackages\u002Fpython\u002Fcheckouts","3.packages\u002F6.python\u002F03.checkouts",{"title":88,"path":336,"stem":337},"\u002Fpackages\u002Fpython\u002Fsubscriptions","3.packages\u002F6.python\u002F04.subscriptions",{"title":141,"path":339,"stem":340},"\u002Fpackages\u002Fpython\u002Fsubscriptionplans","3.packages\u002F6.python\u002F05.subscriptionplans",{"title":96,"path":342,"stem":343},"\u002Fpackages\u002Fpython\u002Forders","3.packages\u002F6.python\u002F06.orders",{"title":148,"path":345,"stem":346},"\u002Fpackages\u002Fpython\u002Foneoffproducts","3.packages\u002F6.python\u002F07.oneoffproducts",{"title":104,"path":348,"stem":349},"\u002Fpackages\u002Fpython\u002Frefunds","3.packages\u002F6.python\u002F08.refunds",{"title":108,"path":351,"stem":352},"\u002Fpackages\u002Fpython\u002Fchargebacks","3.packages\u002F6.python\u002F09.chargebacks",{"title":50,"path":354,"stem":355},"\u002Fpackages\u002Fpython\u002Fwebhooks","3.packages\u002F6.python\u002F10.webhooks",{"title":161,"path":357,"stem":358},"\u002Fpackages\u002Fpython\u002Fwebhookendpoints","3.packages\u002F6.python\u002F11.webhookendpoints",{"title":280,"path":360,"stem":361},"\u002Fpackages\u002Fpython\u002Fapi","3.packages\u002F6.python\u002F12.api",{"title":363,"path":364,"stem":365},"Development","\u002Fpackages\u002Fpython\u002Fdevelopment","3.packages\u002F6.python\u002F13.development",{"title":367,"path":368,"stem":369,"children":370,"page":61},"Python Fluent","\u002Fpackages\u002Ffluent-python","3.packages\u002F7.fluent-python",[371,374,377,380,383,386,389,392,395,398,401,405],{"title":128,"path":372,"stem":373},"\u002Fpackages\u002Ffluent-python\u002Freadme","3.packages\u002F7.fluent-python\u002F00.readme",{"title":173,"path":375,"stem":376},"\u002Fpackages\u002Ffluent-python\u002Fconfiguration","3.packages\u002F7.fluent-python\u002F01.configuration",{"title":177,"path":378,"stem":379},"\u002Fpackages\u002Ffluent-python\u002Fcoreconcepts","3.packages\u002F7.fluent-python\u002F02.coreconcepts",{"title":68,"path":381,"stem":382},"\u002Fpackages\u002Ffluent-python\u002Fcustomers","3.packages\u002F7.fluent-python\u002F03.customers",{"title":80,"path":384,"stem":385},"\u002Fpackages\u002Ffluent-python\u002Fcheckouts","3.packages\u002F7.fluent-python\u002F04.checkouts",{"title":88,"path":387,"stem":388},"\u002Fpackages\u002Ffluent-python\u002Fsubscriptions","3.packages\u002F7.fluent-python\u002F05.subscriptions",{"title":96,"path":390,"stem":391},"\u002Fpackages\u002Ffluent-python\u002Forders","3.packages\u002F7.fluent-python\u002F06.orders",{"title":193,"path":393,"stem":394},"\u002Fpackages\u002Ffluent-python\u002Fcustomerportal","3.packages\u002F7.fluent-python\u002F07.customerportal",{"title":50,"path":396,"stem":397},"\u002Fpackages\u002Ffluent-python\u002Fwebhooks","3.packages\u002F7.fluent-python\u002F08.webhooks",{"title":58,"path":399,"stem":400},"\u002Fpackages\u002Ffluent-python\u002Ftesting","3.packages\u002F7.fluent-python\u002F11.testing",{"title":402,"path":403,"stem":404},"Porting","\u002Fpackages\u002Ffluent-python\u002Fporting","3.packages\u002F7.fluent-python\u002F12.porting",{"title":363,"path":406,"stem":407},"\u002Fpackages\u002Ffluent-python\u002Fdevelopment","3.packages\u002F7.fluent-python\u002F13.development",{"title":409,"path":410,"stem":411,"children":412,"page":61},"Django","\u002Fpackages\u002Fdjango","3.packages\u002F8.django",[413,416,420,423,427,431,434,437,440,444,447],{"title":128,"path":414,"stem":415},"\u002Fpackages\u002Fdjango\u002Freadme","3.packages\u002F8.django\u002F00.readme",{"title":417,"path":418,"stem":419},"Installation","\u002Fpackages\u002Fdjango\u002Finstallation","3.packages\u002F8.django\u002F01.installation",{"title":173,"path":421,"stem":422},"\u002Fpackages\u002Fdjango\u002Fconfiguration","3.packages\u002F8.django\u002F02.configuration",{"title":424,"path":425,"stem":426},"Billable models","\u002Fpackages\u002Fdjango\u002Fbillablemodels","3.packages\u002F8.django\u002F03.billablemodels",{"title":428,"path":429,"stem":430},"Checkout","\u002Fpackages\u002Fdjango\u002Fcheckout","3.packages\u002F8.django\u002F04.checkout",{"title":88,"path":432,"stem":433},"\u002Fpackages\u002Fdjango\u002Fbilling","3.packages\u002F8.django\u002F05.billing",{"title":193,"path":435,"stem":436},"\u002Fpackages\u002Fdjango\u002Fcustomerportal","3.packages\u002F8.django\u002F06.customerportal",{"title":50,"path":438,"stem":439},"\u002Fpackages\u002Fdjango\u002Fwebhooks","3.packages\u002F8.django\u002F07.webhooks",{"title":441,"path":442,"stem":443},"Admin","\u002Fpackages\u002Fdjango\u002Fadmin","3.packages\u002F8.django\u002F08.admin",{"title":58,"path":445,"stem":446},"\u002Fpackages\u002Fdjango\u002Ftesting","3.packages\u002F8.django\u002F09.testing",{"title":363,"path":448,"stem":449},"\u002Fpackages\u002Fdjango\u002Fdevelopment","3.packages\u002F8.django\u002F10.development",{"title":451,"path":452,"stem":453,"children":454},"Integrations","\u002Fintegrations","4.integrations",[455,457,461],{"title":451,"path":452,"stem":456},"4.integrations\u002Findex",{"title":458,"path":459,"stem":460},"Lovable payments with Vatly","\u002Fintegrations\u002Flovable","4.integrations\u002F1.lovable",{"title":462,"path":463,"stem":464},"Bolt payments with Vatly","\u002Fintegrations\u002Fbolt","4.integrations\u002F2.bolt",{"id":466,"title":58,"body":467,"description":1381,"extension":1382,"links":1383,"meta":1384,"navigation":1385,"path":208,"seo":1386,"stem":209,"__hash__":1387},"docs\u002F3.packages\u002F2.fluent-php\u002F11.testing.md",{"type":468,"value":469,"toc":1377},"minimark",[470,483,860,875,878,883,886,1332,1335,1342,1346,1361,1373],[471,472,473,474,478,479,482],"p",{},"Test your application's checkout decisions without making a request to Vatly. Inject ",[475,476,477],"code",{},"FakeVatly"," where your application expects ",[475,480,481],{},"Vatly",", then call your real checkout handler with it.",[484,485,490],"pre",{"className":486,"code":487,"language":488,"meta":489,"style":489},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","use Vatly\\Fluent\\CustomerProfile;\nuse Vatly\\Fluent\\Testing\\FakeCheckout;\nuse Vatly\\Fluent\\Testing\\FakeVatly;\n\n$fake = (new FakeVatly())->onSubscriptionCreate(\n    fn (string $planId) => FakeCheckout::make('https:\u002F\u002Fcheckout.vatly.test\u002Fexample'),\n);\n$checkout = $fake->subscriptionBuilder(new CustomerProfile(vatlyId: 'customer_example'))\n    ->toPlan('subscription_plan_pro')\n    ->withQuantity(3)\n    ->create();\n\n\\PHPUnit\\Framework\\Assert::assertSame(\n    'https:\u002F\u002Fcheckout.vatly.test\u002Fexample',\n    $checkout->links->checkoutUrl->href,\n);\n$fake->assertSubscriptionCreated('subscription_plan_pro');\n$fake->assertNothingCanceled();\n","php","",[475,491,492,520,542,563,570,602,650,656,703,724,739,750,755,780,793,819,824,846],{"__ignoreMap":489},[493,494,497,501,505,509,512,514,517],"span",{"class":495,"line":496},"line",1,[493,498,500],{"class":499},"sbssI","use",[493,502,504],{"class":503},"sTEyZ"," Vatly",[493,506,508],{"class":507},"sMK4o","\\",[493,510,511],{"class":503},"Fluent",[493,513,508],{"class":507},[493,515,516],{"class":503},"CustomerProfile",[493,518,519],{"class":507},";\n",[493,521,523,525,527,529,531,533,535,537,540],{"class":495,"line":522},2,[493,524,500],{"class":499},[493,526,504],{"class":503},[493,528,508],{"class":507},[493,530,511],{"class":503},[493,532,508],{"class":507},[493,534,58],{"class":503},[493,536,508],{"class":507},[493,538,539],{"class":503},"FakeCheckout",[493,541,519],{"class":507},[493,543,545,547,549,551,553,555,557,559,561],{"class":495,"line":544},3,[493,546,500],{"class":499},[493,548,504],{"class":503},[493,550,508],{"class":507},[493,552,511],{"class":503},[493,554,508],{"class":507},[493,556,58],{"class":503},[493,558,508],{"class":507},[493,560,477],{"class":503},[493,562,519],{"class":507},[493,564,566],{"class":495,"line":565},4,[493,567,569],{"emptyLinePlaceholder":568},true,"\n",[493,571,573,576,579,582,585,588,592,595,599],{"class":495,"line":572},5,[493,574,575],{"class":507},"$",[493,577,578],{"class":503},"fake ",[493,580,581],{"class":507},"=",[493,583,584],{"class":507}," (",[493,586,587],{"class":499},"new",[493,589,591],{"class":590},"sBMFI"," FakeVatly",[493,593,594],{"class":507},"())->",[493,596,598],{"class":597},"s2Zo4","onSubscriptionCreate",[493,600,601],{"class":507},"(\n",[493,603,605,609,611,614,617,620,623,626,629,632,635,638,641,645,647],{"class":495,"line":604},6,[493,606,608],{"class":607},"spNyl","    fn",[493,610,584],{"class":507},[493,612,613],{"class":499},"string",[493,615,616],{"class":507}," $",[493,618,619],{"class":503},"planId",[493,621,622],{"class":507},")",[493,624,625],{"class":507}," =>",[493,627,628],{"class":590}," FakeCheckout",[493,630,631],{"class":507},"::",[493,633,634],{"class":597},"make",[493,636,637],{"class":507},"(",[493,639,640],{"class":507},"'",[493,642,644],{"class":643},"sfazB","https:\u002F\u002Fcheckout.vatly.test\u002Fexample",[493,646,640],{"class":507},[493,648,649],{"class":507},"),\n",[493,651,653],{"class":495,"line":652},7,[493,654,655],{"class":507},");\n",[493,657,659,661,664,666,668,671,674,677,679,681,684,686,689,692,695,698,700],{"class":495,"line":658},8,[493,660,575],{"class":507},[493,662,663],{"class":503},"checkout ",[493,665,581],{"class":507},[493,667,616],{"class":507},[493,669,670],{"class":503},"fake",[493,672,673],{"class":507},"->",[493,675,676],{"class":597},"subscriptionBuilder",[493,678,637],{"class":507},[493,680,587],{"class":499},[493,682,683],{"class":590}," CustomerProfile",[493,685,637],{"class":507},[493,687,688],{"class":590},"vatlyId",[493,690,691],{"class":507},":",[493,693,694],{"class":507}," '",[493,696,697],{"class":643},"customer_example",[493,699,640],{"class":507},[493,701,702],{"class":507},"))\n",[493,704,706,709,712,714,716,719,721],{"class":495,"line":705},9,[493,707,708],{"class":507},"    ->",[493,710,711],{"class":597},"toPlan",[493,713,637],{"class":507},[493,715,640],{"class":507},[493,717,718],{"class":643},"subscription_plan_pro",[493,720,640],{"class":507},[493,722,723],{"class":507},")\n",[493,725,727,729,732,734,737],{"class":495,"line":726},10,[493,728,708],{"class":507},[493,730,731],{"class":597},"withQuantity",[493,733,637],{"class":507},[493,735,736],{"class":499},"3",[493,738,723],{"class":507},[493,740,742,744,747],{"class":495,"line":741},11,[493,743,708],{"class":507},[493,745,746],{"class":597},"create",[493,748,749],{"class":507},"();\n",[493,751,753],{"class":495,"line":752},12,[493,754,569],{"emptyLinePlaceholder":568},[493,756,758,760,763,765,768,770,773,775,778],{"class":495,"line":757},13,[493,759,508],{"class":507},[493,761,762],{"class":503},"PHPUnit",[493,764,508],{"class":507},[493,766,767],{"class":503},"Framework",[493,769,508],{"class":507},[493,771,772],{"class":590},"Assert",[493,774,631],{"class":507},[493,776,777],{"class":597},"assertSame",[493,779,601],{"class":507},[493,781,783,786,788,790],{"class":495,"line":782},14,[493,784,785],{"class":507},"    '",[493,787,644],{"class":643},[493,789,640],{"class":507},[493,791,792],{"class":507},",\n",[493,794,796,799,802,804,807,809,812,814,817],{"class":495,"line":795},15,[493,797,798],{"class":507},"    $",[493,800,801],{"class":503},"checkout",[493,803,673],{"class":507},[493,805,806],{"class":503},"links",[493,808,673],{"class":507},[493,810,811],{"class":503},"checkoutUrl",[493,813,673],{"class":507},[493,815,816],{"class":503},"href",[493,818,792],{"class":507},[493,820,822],{"class":495,"line":821},16,[493,823,655],{"class":507},[493,825,827,829,831,833,836,838,840,842,844],{"class":495,"line":826},17,[493,828,575],{"class":507},[493,830,670],{"class":503},[493,832,673],{"class":507},[493,834,835],{"class":597},"assertSubscriptionCreated",[493,837,637],{"class":507},[493,839,640],{"class":507},[493,841,718],{"class":643},[493,843,640],{"class":507},[493,845,655],{"class":507},[493,847,849,851,853,855,858],{"class":495,"line":848},18,[493,850,575],{"class":507},[493,852,670],{"class":503},[493,854,673],{"class":507},[493,856,857],{"class":597},"assertNothingCanceled",[493,859,749],{"class":507},[471,861,862,863,866,867,870,871,874],{},"Install PHPUnit as a development dependency to use the ",[475,864,865],{},"assert*"," helpers. ",[475,868,869],{},"withDefaultCheckout()"," sets a shared result; ",[475,872,873],{},"onCheckoutCreate()"," scripts one-off checkout results. The fake also records swaps and cancellations routed through its subscription handles.",[471,876,877],{},"Fakes test your application branches, not API validation, signature checking, or database behavior. Only use the fake surfaces you have scripted; it is not a sandbox for every SDK operation.",[879,880,882],"h2",{"id":881},"test-your-webhook-receiver","Test your webhook receiver",[471,884,885],{},"Use a local fixture and an independent HMAC signature. This sends no request to Vatly:",[484,887,889],{"className":486,"code":888,"language":488,"meta":489,"style":489},"$secret = 'local-fixture-secret';\n$payload = json_encode([\n    'id' => 'event_fixture',\n    'resource' => 'webhook_event',\n    'eventName' => 'webhook.setup',\n    'entityType' => 'webhook_endpoint',\n    'entityId' => 'webhook_endpoint_fixture',\n    'testmode' => true,\n    'createdAt' => '2026-01-01T00:00:00Z',\n    'object' => ['id' => 'webhook_endpoint_fixture'],\n], JSON_THROW_ON_ERROR);\n$timestamp = time();\n$signature = 't=' . $timestamp . ',v1='\n    . hash_hmac('sha256', $timestamp . '.' . $payload, $secret);\n\n$verifier = new \\Vatly\\Fluent\\Webhooks\\SignatureVerifier();\n\\PHPUnit\\Framework\\Assert::assertTrue($verifier->isValid($signature, $payload, $secret));\n\\PHPUnit\\Framework\\Assert::assertFalse($verifier->isValid($signature, $payload . ' ', $secret));\n",[475,890,891,909,924,944,964,984,1004,1024,1038,1058,1089,1099,1113,1147,1195,1199,1231,1281],{"__ignoreMap":489},[493,892,893,895,898,900,902,905,907],{"class":495,"line":496},[493,894,575],{"class":507},[493,896,897],{"class":503},"secret ",[493,899,581],{"class":507},[493,901,694],{"class":507},[493,903,904],{"class":643},"local-fixture-secret",[493,906,640],{"class":507},[493,908,519],{"class":507},[493,910,911,913,916,918,921],{"class":495,"line":522},[493,912,575],{"class":507},[493,914,915],{"class":503},"payload ",[493,917,581],{"class":507},[493,919,920],{"class":597}," json_encode",[493,922,923],{"class":507},"([\n",[493,925,926,928,931,933,935,937,940,942],{"class":495,"line":544},[493,927,785],{"class":507},[493,929,930],{"class":643},"id",[493,932,640],{"class":507},[493,934,625],{"class":507},[493,936,694],{"class":507},[493,938,939],{"class":643},"event_fixture",[493,941,640],{"class":507},[493,943,792],{"class":507},[493,945,946,948,951,953,955,957,960,962],{"class":495,"line":565},[493,947,785],{"class":507},[493,949,950],{"class":643},"resource",[493,952,640],{"class":507},[493,954,625],{"class":507},[493,956,694],{"class":507},[493,958,959],{"class":643},"webhook_event",[493,961,640],{"class":507},[493,963,792],{"class":507},[493,965,966,968,971,973,975,977,980,982],{"class":495,"line":572},[493,967,785],{"class":507},[493,969,970],{"class":643},"eventName",[493,972,640],{"class":507},[493,974,625],{"class":507},[493,976,694],{"class":507},[493,978,979],{"class":643},"webhook.setup",[493,981,640],{"class":507},[493,983,792],{"class":507},[493,985,986,988,991,993,995,997,1000,1002],{"class":495,"line":604},[493,987,785],{"class":507},[493,989,990],{"class":643},"entityType",[493,992,640],{"class":507},[493,994,625],{"class":507},[493,996,694],{"class":507},[493,998,999],{"class":643},"webhook_endpoint",[493,1001,640],{"class":507},[493,1003,792],{"class":507},[493,1005,1006,1008,1011,1013,1015,1017,1020,1022],{"class":495,"line":652},[493,1007,785],{"class":507},[493,1009,1010],{"class":643},"entityId",[493,1012,640],{"class":507},[493,1014,625],{"class":507},[493,1016,694],{"class":507},[493,1018,1019],{"class":643},"webhook_endpoint_fixture",[493,1021,640],{"class":507},[493,1023,792],{"class":507},[493,1025,1026,1028,1031,1033,1035],{"class":495,"line":658},[493,1027,785],{"class":507},[493,1029,1030],{"class":643},"testmode",[493,1032,640],{"class":507},[493,1034,625],{"class":507},[493,1036,1037],{"class":507}," true,\n",[493,1039,1040,1042,1045,1047,1049,1051,1054,1056],{"class":495,"line":705},[493,1041,785],{"class":507},[493,1043,1044],{"class":643},"createdAt",[493,1046,640],{"class":507},[493,1048,625],{"class":507},[493,1050,694],{"class":507},[493,1052,1053],{"class":643},"2026-01-01T00:00:00Z",[493,1055,640],{"class":507},[493,1057,792],{"class":507},[493,1059,1060,1062,1065,1067,1069,1072,1074,1076,1078,1080,1082,1084,1086],{"class":495,"line":726},[493,1061,785],{"class":507},[493,1063,1064],{"class":643},"object",[493,1066,640],{"class":507},[493,1068,625],{"class":507},[493,1070,1071],{"class":507}," [",[493,1073,640],{"class":507},[493,1075,930],{"class":643},[493,1077,640],{"class":507},[493,1079,625],{"class":507},[493,1081,694],{"class":507},[493,1083,1019],{"class":643},[493,1085,640],{"class":507},[493,1087,1088],{"class":507},"],\n",[493,1090,1091,1094,1097],{"class":495,"line":741},[493,1092,1093],{"class":507},"],",[493,1095,1096],{"class":503}," JSON_THROW_ON_ERROR",[493,1098,655],{"class":507},[493,1100,1101,1103,1106,1108,1111],{"class":495,"line":752},[493,1102,575],{"class":507},[493,1104,1105],{"class":503},"timestamp ",[493,1107,581],{"class":507},[493,1109,1110],{"class":597}," time",[493,1112,749],{"class":507},[493,1114,1115,1117,1120,1122,1124,1127,1129,1132,1134,1136,1139,1141,1144],{"class":495,"line":757},[493,1116,575],{"class":507},[493,1118,1119],{"class":503},"signature ",[493,1121,581],{"class":507},[493,1123,694],{"class":507},[493,1125,1126],{"class":643},"t=",[493,1128,640],{"class":507},[493,1130,1131],{"class":507}," .",[493,1133,616],{"class":507},[493,1135,1105],{"class":503},[493,1137,1138],{"class":507},".",[493,1140,694],{"class":507},[493,1142,1143],{"class":643},",v1=",[493,1145,1146],{"class":507},"'\n",[493,1148,1149,1152,1155,1157,1159,1162,1164,1167,1169,1171,1173,1175,1177,1179,1181,1183,1186,1188,1190,1193],{"class":495,"line":782},[493,1150,1151],{"class":507},"    .",[493,1153,1154],{"class":597}," hash_hmac",[493,1156,637],{"class":507},[493,1158,640],{"class":507},[493,1160,1161],{"class":643},"sha256",[493,1163,640],{"class":507},[493,1165,1166],{"class":507},",",[493,1168,616],{"class":507},[493,1170,1105],{"class":503},[493,1172,1138],{"class":507},[493,1174,694],{"class":507},[493,1176,1138],{"class":643},[493,1178,640],{"class":507},[493,1180,1131],{"class":507},[493,1182,616],{"class":507},[493,1184,1185],{"class":503},"payload",[493,1187,1166],{"class":507},[493,1189,616],{"class":507},[493,1191,1192],{"class":503},"secret",[493,1194,655],{"class":507},[493,1196,1197],{"class":495,"line":795},[493,1198,569],{"emptyLinePlaceholder":568},[493,1200,1201,1203,1206,1208,1211,1214,1216,1218,1220,1222,1224,1226,1229],{"class":495,"line":821},[493,1202,575],{"class":507},[493,1204,1205],{"class":503},"verifier ",[493,1207,581],{"class":507},[493,1209,1210],{"class":499}," new",[493,1212,1213],{"class":507}," \\",[493,1215,481],{"class":503},[493,1217,508],{"class":507},[493,1219,511],{"class":503},[493,1221,508],{"class":507},[493,1223,50],{"class":503},[493,1225,508],{"class":507},[493,1227,1228],{"class":590},"SignatureVerifier",[493,1230,749],{"class":507},[493,1232,1233,1235,1237,1239,1241,1243,1245,1247,1250,1253,1256,1258,1261,1263,1266,1268,1270,1272,1274,1276,1278],{"class":495,"line":826},[493,1234,508],{"class":507},[493,1236,762],{"class":503},[493,1238,508],{"class":507},[493,1240,767],{"class":503},[493,1242,508],{"class":507},[493,1244,772],{"class":590},[493,1246,631],{"class":507},[493,1248,1249],{"class":597},"assertTrue",[493,1251,1252],{"class":507},"($",[493,1254,1255],{"class":503},"verifier",[493,1257,673],{"class":507},[493,1259,1260],{"class":597},"isValid",[493,1262,1252],{"class":507},[493,1264,1265],{"class":503},"signature",[493,1267,1166],{"class":507},[493,1269,616],{"class":507},[493,1271,1185],{"class":503},[493,1273,1166],{"class":507},[493,1275,616],{"class":507},[493,1277,1192],{"class":503},[493,1279,1280],{"class":507},"));\n",[493,1282,1283,1285,1287,1289,1291,1293,1295,1297,1300,1302,1304,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1326,1328,1330],{"class":495,"line":848},[493,1284,508],{"class":507},[493,1286,762],{"class":503},[493,1288,508],{"class":507},[493,1290,767],{"class":503},[493,1292,508],{"class":507},[493,1294,772],{"class":590},[493,1296,631],{"class":507},[493,1298,1299],{"class":597},"assertFalse",[493,1301,1252],{"class":507},[493,1303,1255],{"class":503},[493,1305,673],{"class":507},[493,1307,1260],{"class":597},[493,1309,1252],{"class":507},[493,1311,1265],{"class":503},[493,1313,1166],{"class":507},[493,1315,616],{"class":507},[493,1317,915],{"class":503},[493,1319,1138],{"class":507},[493,1321,694],{"class":507},[493,1323,694],{"class":507},[493,1325,1166],{"class":507},[493,1327,616],{"class":507},[493,1329,1192],{"class":503},[493,1331,1280],{"class":507},[471,1333,1334],{},"Configure your test processor with that secret and pass the raw body and header through your HTTP handler. Assert a valid delivery is committed, an invalid signature writes nothing, and redelivery does not fulfill twice. Force a repository error after the audit write and prove the whole transaction rolls back. Test two concurrent deliveries against your real database, not just an in-memory repository.",[471,1336,1337,1338,1341],{},"For subscription access, cover a future grace end, a past end, resume clearing the date, and nonpayment cancellation. For orders, cover initial payment, renewal, duplicate delivery, and a reversal without changing ",[475,1339,1340],{},"paid"," to a made-up status.",[879,1343,1345],{"id":1344},"exercise-the-vatly-sandbox","Exercise the Vatly sandbox",[471,1347,1348,1349,1352,1353,1356,1357,1360],{},"With a test key, ",[475,1350,1351],{},"testHelpers()->advanceRenewal($id)",", ",[475,1354,1355],{},"forceRenewalPaid($id)",", and ",[475,1358,1359],{},"forceRenewalFailed($id, 'card_expired')"," advance real test-mode state and provoke webhooks. Unlike the fakes above, these make remote writes. Use them only in a dedicated sandbox integration test, never with live records.",[471,1362,1363,1364,1370,1371,1138],{},"For sandbox fields, see the ",[1365,1366,280],"a",{"href":1367,"rel":1368},"https:\u002F\u002Fdocs.vatly.com\u002Fapi-reference",[1369],"nofollow",". For receiver design, see ",[1365,1372,50],{"href":197},[1374,1375,1376],"style",{},"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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":489,"searchDepth":522,"depth":522,"links":1378},[1379,1380],{"id":881,"depth":522,"text":882},{"id":1344,"depth":522,"text":1345},"Test your application's checkout decisions without making a request to Vatly.","md",null,{},{"title":58},{"title":58,"description":1381},"24N02EiSBQWLsNhVxkDyYhrukdIjP26XyCl4XVT9DL8",[1389,1391],{"title":204,"path":205,"stem":206,"description":1390,"children":-1},"Reuse an application's existing orders instead of creating parallel Fluent tables.",{"title":128,"path":216,"stem":217,"description":1392,"children":-1},"Vatly Laravel provides a Cashier-like integration for Vatly billing in your Laravel application.",1794594927815]