{"id":23293651,"url":"https://github.com/programmatordev/kirby-stripe-checkout","last_synced_at":"2025-07-24T19:09:22.395Z","repository":{"id":268425747,"uuid":"852261099","full_name":"programmatordev/kirby-stripe-checkout","owner":"programmatordev","description":"Stripe Checkout for Kirby CMS","archived":false,"fork":false,"pushed_at":"2025-05-25T14:54:37.000Z","size":203,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-05-25T15:39:16.212Z","etag":null,"topics":["kirby","kirby-cms","kirby-plugin","stripe","stripe-checkout"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/programmatordev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-09-04T14:02:40.000Z","updated_at":"2025-05-08T11:22:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"f329ccfd-c628-4744-862c-6e776b05224c","html_url":"https://github.com/programmatordev/kirby-stripe-checkout","commit_stats":null,"previous_names":["programmatordev/kirby-stripe-checkout"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/programmatordev/kirby-stripe-checkout","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/programmatordev%2Fkirby-stripe-checkout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/programmatordev%2Fkirby-stripe-checkout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/programmatordev%2Fkirby-stripe-checkout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/programmatordev%2Fkirby-stripe-checkout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/programmatordev","download_url":"https://codeload.github.com/programmatordev/kirby-stripe-checkout/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/programmatordev%2Fkirby-stripe-checkout/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266890368,"owners_count":24001538,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-24T02:00:09.469Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kirby","kirby-cms","kirby-plugin","stripe","stripe-checkout"],"created_at":"2024-12-20T06:16:25.994Z","updated_at":"2025-07-24T19:09:22.349Z","avatar_url":"https://github.com/programmatordev.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kirby Stripe Checkout\n\n[![Latest Version](https://img.shields.io/github/release/programmatordev/kirby-stripe-checkout.svg?style=flat-square)](https://github.com/programmatordev/kirby-stripe-checkout/releases)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)\n[![Tests](https://github.com/programmatordev/kirby-stripe-checkout/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/programmatordev/kirby-stripe-checkout/actions/workflows/ci.yml?query=branch%3Amain)\n\n[Stripe Checkout](https://stripe.com/en-pt/payments/checkout) for [Kirby CMS](https://getkirby.com).\n\n\u003e [!CAUTION]\n\u003e This plugin is still in its early stages.\n\u003e This means that it should not be considered stable, so use it at your own risk.\n\u003e Expect a lot of breaking changes until version `1.0`.\n\n## Features\n\n- 🔥 Stripe Checkout for both `hosted` and `embedded` modes;\n- 💸 Handles sync and async payments (credit card, bank transfer, etc.);\n- 📦 Orders panel page;\n- ⚙️ Checkout Settings panel page;\n- 🪝 Hooks for all payment status (completed, pending and failed), orders and checkout sessions;\n- 🛒 Cart management;\n- ...and more.\n\n## Documentation\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Options](#options)\n- [Hooks](#hooks)\n- [Cart](#cart)\n- [Translations](#translations-1)\n- [Setup](#setup)\n- [Development](#development)\n- [Production](#production)\n\n## Requirements\n\n- PHP `8.2` or higher;\n- Kirby CMS `4.0` or higher;\n- [Stripe account](https://dashboard.stripe.com/register).\n\n## Installation\n\nInstall the plugin via [Composer](https://getcomposer.org/):\n\n```bash\ncomposer require programmatordev/kirby-stripe-checkout\n```\n\n## Options\n\nDefault options:\n\n```php\n// config.php\n\nreturn [\n    'programmatordev.stripe-checkout' =\u003e [\n        'stripePublicKey' =\u003e null,\n        'stripeSecretKey' =\u003e null,\n        'stripeWebhookSecret' =\u003e null,\n        'currency' =\u003e 'EUR',\n        'uiMode' =\u003e 'hosted',\n        'successPage' =\u003e null,\n        'cancelPage' =\u003e null,\n        'returnPage' =\u003e null,\n        'ordersPage' =\u003e 'orders',\n        'settingsPage' =\u003e 'checkout-settings',\n        'cartSnippet' =\u003e null,\n        'translations' =\u003e []\n    ]\n];\n```\n\n\u003e [!TIP]\n\u003e It is recommended that you use a library that enables environment variables\n\u003e to store your project credentials in a separate place from your code\n\u003e and to have separate development and production access keys.\n\nList of all available options:\n\n- [stripePublicKey](#stripepublickey)\n- [stripeSecretKey](#stripesecretkey)\n- [stripeWebhookSecret](#stripewebhooksecret)\n- [uiMode](#uimode)\n- [currency](#currency)\n- [successPage](#successpage)\n- [cancelPage](#cancelpage)\n- [returnPage](#returnpage)\n- [ordersPage](#orderspage)\n- [settingsPage](#settingspage)\n- [cartSnippet](#cartsnippet)\n- [translations](#translations)\n\n### `stripePublicKey`\n\ntype: `string` `required`\n\nStripe public key found on the Stripe Dashboard.\n\n### `stripeSecretKey`\n\ntype: `string` `required`\n\nStripe secret key found on the Stripe Dashboard.\n\n### `stripeWebhookSecret`\n\ntype: `string` `required`\n\nWebhook secret found when a Webhook is created in the Stripe Dashboard.\n\nCheck the [Setup](#setup) section for more information.\n\n### `currency`\n\ntype: `string` default: `EUR` `required`\n\nThree-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html).\nMust be a [supported currency](https://stripe.com/docs/currencies).\n\n### `uiMode`\n\ntype: `string` default: `hosted` `required`\n\nThe UI mode of the Checkout Session.\n\nAvailable options:\n- `hosted` the Checkout Session will be displayed on a Stripe-hosted page (where the user will be redirected);\n- `embedded` the Checkout Session will be displayed as an embedded form on the website page.\n\n### `successPage`\n\ntype: `string`\n\nThis option is `required` if `uiMode` is set to `hosted`.\n\nPage to where a user will be redirected when a Checkout Session is completed (form successfully submitted).\n\nMust be a valid Kirby page `id`.\nThe `id` is used, instead of a URL, to make sure that the user is redirected correctly in case of multi-language setups.\n\n### `cancelPage`\n\ntype: `string`\n\nThis option is `required` if `uiMode` is set to `hosted`.\n\nPage to where a user will be redirected if decides to cancel the payment and return to the website.\n\nMust be a valid Kirby page `id`.\nThe `id` is used, instead of a URL, to make sure that the user is redirected correctly in case of multi-language setups.\n\n### `returnPage`\n\ntype: `string`\n\nThis option is `required` if `uiMode` is set to `embedded`.\n\nPage to where a user will be redirected when a Checkout Session is completed (form successfully submitted).\n\nMust be a valid Kirby page `id`.\nThe `id` is used, instead of a URL, to make sure that the user is redirected correctly in case of multi-language setups.\n\n### `ordersPage`\n\ntype: `string` default: `orders` `required`\n\nKirby Panel page with the overview of all orders.\n\nMust be a valid Kirby page `id`.\n\nCheck the [Setup](#setup) section for more information.\n\n### `settingsPage`\n\ntype: `string` default: `checkout-settings` `required`\n\nKirby Panel page with Checkout settings.\n\nMust be a valid Kirby page `id`.\n\nCheck the [Setup](#setup) section for more information.\n\n### `cartSnippet`\n\ntype: `?string` default: `null`\n\nWhen set, it will look for the snippet with the same name and return the HTML content on every cart API response.\nUseful when adding, updating or removing cart contents, and you want to update the HTML on every request.\n\nIf snippet does not exist or is empty, it will return `null`.\n\n### `translations`\n\ntype: `array` default: `[]`\n\nUse this option to overwrite existing translations or to add a new one that is not bundled with the plugin.\nCheck the [`translations`](translations) folder for all available translations.\n\nAn example when overwriting an existing translation:\n\n```php\n// site/config/config.php\n\nreturn [\n    'programmatordev.stripe-checkout' =\u003e [\n        'translations' =\u003e [\n            'en' =\u003e [\n                // overwrites \"Orders\" to \"Tickets\"\n                'stripe-checkout.fields.orders.ordersHeadline.label' =\u003e 'Tickets'\n            ]\n        ]\n    ]\n];\n```\n\nIf a translation does not exist, you can provide yours:\n\n```php\n// site/config/config.php\n\nreturn [\n    'programmatordev.stripe-checkout.translations' =\u003e [\n        'translations' =\u003e [\n            // The German translation is not currently bundled with the plugin, so you can provide your own\n            'de' =\u003e [\n                'stripe-checkout.fields.product.price.label' =\u003e 'Preis',\n                'stripe-checkout.fields.product.thumbnail.label' =\u003e 'Vorschaubild',\n                'stripe-checkout.fields.settings.shippingHeadline.label' =\u003e 'Versand',\n                'stripe-checkout.fields.settings.shippingEnabled.label' =\u003e 'Versandeinstellungen',\n                'stripe-checkout.fields.settings.shippingAllowedCountries.label' =\u003e 'Erlaubte Länder',\n                // ...\n            ]\n        ]\n    ]\n];\n```\n\n## Hooks\n\n- [stripe-checkout.session.create:before](#stripe-checkoutsessioncreatebefore)\n- [stripe-checkout.order.create:before](#stripe-checkoutordercreatebefore)\n- [stripe-checkout.payment:succeeded](#stripe-checkoutpaymentsucceeded)\n- [stripe-checkout.payment:pending](#stripe-checkoutpaymentpending)\n- [stripe-checkout.payment:failed](#stripe-checkoutpaymentfailed)\n\n### `stripe-checkout.session.create:before`\n\nTriggered before creating a Checkout Session.\nUseful to set additional Checkout Session parameters.\n\nYou can check all the available parameters in the Stripe API [documentation page](https://docs.stripe.com/api/checkout/sessions/create?lang=php).\n\n```php\n// config.php\n\nreturn [\n    'hooks' =\u003e [\n        'stripe-checkout.session.create:before' =\u003e function (array $sessionParams): array\n        {\n            // for example, if you want to enable promotion codes\n            // https://docs.stripe.com/api/checkout/sessions/create?lang=php#create_checkout_session-allow_promotion_codes\n            $sessionParams['allow_promotion_codes'] = true;\n\n            return $sessionParams;\n        }\n    ]\n];\n```\n\n\u003e [!WARNING]\n\u003e Take into account that the `sessionParams` variable contains data required to initialize a Checkout Session.\n\u003e You may change these but at your own risk.\n\n### `stripe-checkout.order.create:before`\n\nTriggered before creating an Order page in the Panel.\nUseful to set additional Order data in case you add additional fields in the blueprint or want to change existing ones.\n\n```php\n// config.php\n\nuse Stripe\\Checkout\\Session;\nuse Stripe\\Event;\n\nreturn [\n    'hooks' =\u003e [\n        'stripe-checkout.order.create:before' =\u003e function (array $orderContent, Session $checkoutSession, Event $stripeEvent): array\n        {\n            // change order content\n            // ...\n\n            return $orderContent;\n        }\n    ]\n];\n```\n\n\u003e [!WARNING]\n\u003e Take into account that the `orderContent` variable contains all data required to create an Order page.\n\u003e You may change these but at your own risk.\n\n### `stripe-checkout.payment:succeeded`\n\nTriggered when a payment is completed successfully.\n\n\u003e [!IMPORTANT]\n\u003e This hook is triggered for both sync and async payments.\n\u003e An example of a sync payment is when a customer pays using a credit card as the payment method.\n\u003e An example of an async payment is when a customer wants to pay through a bank transfer.\n\u003e In this case, the hook will only be triggered when the actual bank transfer is successfully performed.\n\u003e Check the [stripe-checkout.payment:pending](#stripe-checkoutpaymentpending) hook to handle pending payments.\n\n```php\n// config.php\n\nuse Kirby\\Cms\\Page;\nuse Stripe\\Checkout\\Session;\nuse Stripe\\Event;\n\nreturn [\n    'hooks' =\u003e [\n        'stripe-checkout.payment:succeeded' =\u003e function (Page $orderPage, Session $checkoutSession, Event $stripeEvent): void\n        {\n            // email the customer when the payment succeeds\n            kirby()-\u003eemail([\n                'from' =\u003e 'orders@myshop.com',\n                'to' =\u003e $orderPage-\u003ecustomer()-\u003etoObject()-\u003eemail()-\u003evalue(),\n                'subject' =\u003e 'Thank you for your order!',\n                'body' =\u003e 'Your order will be processed soon.',\n            ]);\n        }\n    ]\n];\n```\n\n### `stripe-checkout.payment:pending`\n\nTriggered when an order is pending payment.\n\nThis happens when a customer uses an async payment method, like a bank transfer,\nwhere the Checkout form is submitted successfully, but the payment is yet to be made.\n\n```php\n// config.php\n\nuse Kirby\\Cms\\Page;\nuse Stripe\\Checkout\\Session;\nuse Stripe\\Event;\n\nreturn [\n    'hooks' =\u003e [\n        'stripe-checkout.payment:pending' =\u003e function (Page $orderPage, Session $checkoutSession, Event $stripeEvent): void\n        {\n            // email the customer when the payment is pending\n            kirby()-\u003eemail([\n                'from' =\u003e 'orders@myshop.com',\n                'to' =\u003e $orderPage-\u003ecustomer()-\u003etoObject()-\u003eemail()-\u003evalue(),\n                'subject' =\u003e 'Thank you for your order!',\n                'body' =\u003e 'Your order is pending payment.',\n            ]);\n        }\n    ]\n];\n```\n\n### `stripe-checkout.payment:failed`\n\nTriggered when a payment has failed.\n\nThis happens when a customer uses an async payment method, like a bank transfer,\nwhere the Checkout form is submitted successfully, but the payment has failed\n(for example, the deadline for the payment has expired).\n\n```php\n// config.php\n\nuse Kirby\\Cms\\Page;\nuse Stripe\\Checkout\\Session;\nuse Stripe\\Event;\n\nreturn [\n    'hooks' =\u003e [\n        'stripe-checkout.payment:failed' =\u003e function (Page $orderPage, Session $checkoutSession, Event $stripeEvent): void\n        {\n            // email the customer when the payment has failed\n            kirby()-\u003eemail([\n                'from' =\u003e 'orders@myshop.com',\n                'to' =\u003e $orderPage-\u003ecustomer()-\u003etoObject()-\u003eemail()-\u003evalue(),\n                'subject' =\u003e 'Bad news!',\n                'body' =\u003e 'Your order has been canceled because the payment has failed.',\n            ]);\n        }\n    ]\n];\n```\n\n## Cart\n\nA cart management system already exists and is required to be able to create a Checkout Session.\nThe reason for this is that the checkout line items are generated based on the current cart contents.\nThis means that the cart must have at least one added item; otherwise it will throw an error.\n\n### PHP\n\nA `cart()` function is available to manage the cart contents.\n\n```php\nuse ProgrammatorDev\\StripeCheckout\\Cart\\Cart;\n\ncart(array $options = []): Cart\n```\n\nDefault options:\n\n```php\ncart([\n    // the same as configured in the plugin options\n    'currency' =\u003e option('programmatordev.stripe-checkout.currency'),\n    'cartSnippet' =\u003e option('programmatordev.stripe-checkout.cartSnippet')\n]);\n```\n\nAvailable methods:\n\n- [addItem](#additem)\n- [updateItem](#updateitem)\n- [removeItem](#removeitem)\n- [items](#items)\n- [totalQuantity](#totalquantity)\n- [totalAmount](#totalamount)\n- [currency](#currency-1)\n- [currencySymbol](#currencysymbol)\n- [cartSnippet](#getcartsnippet)\n- [destroy](#destroy)\n- [toArray](#toarray)\n\n#### `addItem`\n\n```php\naddItem(string $id, int $quantity, ?array $options = null): string\n```\n\nAdds an item to the cart.\n\nThe `id` and `quantity` values are required.\nAn additional `options` value is available to set the options of a product (color, size, etc.).\n\nImportant to note that the `id` must be a valid Kirby page id and the page must include a valid `price` field.\nOtherwise, an exception will be thrown.\nCheck the [Setup](#setup) section for more information.\n\nInformation related to the `price`, `name` and `thumbnail` are added to the item based on the given `id` (and related Kirby page).\n\nIf the item that is being added already exists in the cart, the sum of its quantities will be made into a single item.\n\nIf the same item is added but with different options, it will be considered different items in the cart.\nFor example, a t-shirt with the color blue and the same t-shirt with the color red will be different items.\n\nA `key` is returned that uniquely identifies the item in the cart.\n\n```php\n$cart = cart();\n\n// a key is returned and uniquely identifies that item in the cart\n$key = $cart-\u003eaddItem(id: 'products/cd', quantity: 1);\n\n// you can add options per item\n$key = $cart-\u003eaddItem(\n    id: 'products/t-shirt',\n    quantity: 1,\n    options: ['Color' =\u003e 'Green', 'Size' =\u003e 'Medium']\n);\n```\n\n#### `updateItem`\n\n```php\nupdateItem(string $key, int $quantity): void\n```\n\nUpdates the `quantity` of an item in the cart.\n\n```php\n$cart = cart();\n\n$key = $cart-\u003eaddItem(id: 'products/cd', quantity: 1);\n\n$cart-\u003eupdateItem(key: $key, quantity: 3);\n```\n\n#### `removeItem`\n\n```php\nremoveItem(string $key): void\n```\n\nRemoves an item from the cart.\n\n```php\n$cart = cart();\n\n$key = $cart-\u003eaddItem(id: 'products/cd', quantity: 1);\n\n$cart-\u003eremoveItem($key);\n```\n\n#### `items`\n\n```php\nuse Kirby\\Toolkit\\Collection;\nuse ProgrammatorDev\\StripeCheckout\\Cart\\Item\n\n/** @return Collection\u003cstring, Item\u003e */\nitems(): Collection\n```\n\nCollection with all items in the cart.\n\n```php\nuse ProgrammatorDev\\StripeCheckout\\Cart\\Item;\n\n$cart = cart();\n$items = $cart-\u003eitems();\n\n/** @var Item $item */\nforeach ($items as $key =\u003e $item) {\n    $item-\u003eid();\n    $item-\u003equantity()\n    $item-\u003eoptions();\n    $item-\u003eproductPage();\n    $item-\u003ename();\n    $item-\u003eprice();\n    $item-\u003etotalAmount();\n    $item-\u003ethumbnail();\n}\n```\n\n#### `totalQuantity`\n\n```php\ntotalQuantity(): int\n```\n\nGet the total quantity of items in the cart.\n\n```php\n$cart = cart();\necho $cart-\u003etotalQuantity(); // 3\n```\n\n#### `totalAmount`\n\n```php\ntotalAmount(): int|float\n```\n\nGet the total amount in the cart.\n\n```php\n$cart = cart();\necho $cart-\u003etotalAmount(); // 100\n```\n\n#### `currency`\n\n```php\ncurrency(): string\n```\n\nGet currency.\n\n```php\n$cart = cart();\necho $cart-\u003ecurrency(); // EUR\n```\n\n#### `currencySymbol`\n\n```php\ncurrencySymbol(): string\n```\n\nGet currency symbol.\n\n```php\n$cart = cart();\necho $cart-\u003ecurrencySymbol(); // €\n```\n\n#### `cartSnippet`\n\n```php\ncartSnippet(bool $render = false): ?string\n```\n\nGet cart snippet if set in the [`cartSnippet`](#cartsnippet) option.\n\nif `render` is set to `true` it will return the rendered HTML snippet\n\n```php\n$cart = cart();\necho $cart-\u003ecartSnippet(render: false); // snippet name or null\necho $cart-\u003ecartSnippet(render: true); // rendered snippet HTML\n```\n\n#### `destroy`\n\n```php\ndestroy(): void\n```\n\nDestroy all contents and reset the cart to the initial state.\n\n```php\n$cart = cart();\n$cart-\u003edestroy();\n```\n\n#### `toArray`\n\n```php\ntoArray(bool $includeCurrency = true): array\n```\n\nConverts all cart contents into an array.\n\n\n```php\n$cart = cart();\n$cart-\u003etoArray();\n```\n\n### JavaScript\n\nA JavaScript library is currently being developed.\nMeanwhile, check the [API endpoints](#api-endpoints) section below for examples on how to use with JavaScript.\n\n### API endpoints\n\nEndpoints are available to help manage the cart system in the frontend.\nYou can make requests to these to add, update and remove items, get the cart contents or its snippet.\n\nAll successful responses will have the following structure:\n\n```json\n{\n  \"status\": \"ok\",\n  \"data\": {\n    \"items\": [\n      {\n        \"key\": \"key1\",\n        \"id\": \"products/item-1\",\n        \"name\": \"Item 1\",\n        \"price\": 10,\n        \"quantity\": 2,\n        \"totalAmount\": 20,\n        \"options\": null,\n        \"thumbnail\": null\n      },\n      {\n        \"key\": \"key2\",\n        \"id\": \"products/item-2\",\n        \"name\": \"Item 2\",\n        \"price\": 10,\n        \"quantity\": 1,\n        \"subtotal\": 10,\n        \"options\": {\n          \"name\": \"value\"\n        },\n        \"thumbnail\": \"https://path.com/to/image.jpg\"\n      }\n    ],\n    \"totalAmount\": 30,\n    \"totalQuantity\": 3,\n    \"currency\": \"EUR\",\n    \"currencySymbol\": \"€\"\n  },\n  \"snippet\": null\n}\n```\n\nIn case of error:\n\n```json\n{\n  \"status\": \"error\",\n  \"message\": \"Product does not exist.\"\n}\n```\n\n### `GET /api/cart`\n\nGet cart contents.\n\n```js\nconst response = await fetch('api/cart', {\n  method: \"GET\"\n});\n```\n\n### `POST /api/cart/items`\n\nAdds item to the cart.\n\n```js\nconst response = await fetch('/api/cart/items', {\n  method: 'POST',\n  body: JSON.stringify({\n    id: 'products/item',\n    quantity: 1,\n    // optional\n    options: {\n      'Size': 'Medium'\n    }\n  })\n});\n```\n\n### `PATCH /api/cart/items/:key`\n\nUpdates item in the cart.\n\n```js\nconst key = 'key-hash';\nconst response = await fetch(`/api/cart/items/${key}`, {\n  method: 'PATCH',\n  body: JSON.stringify({\n    quantity: 1\n  })\n});\n```\n\n### `DELETE /api/cart/items/:key`\n\nRemoves item from the cart.\n\n```js\nconst key = 'key-hash';\nconst response = await fetch(`/api/cart/items/${key}`, {\n  method: 'DELETE'\n});\n```\n\n### `GET /api/cart/snippet`\n\nGet cart snippet.\n\n```js\nconst response = await fetch('/api/cart/snippet', {\n  method: 'GET'\n});\n```\n\nResponse:\n\n```json\n{\n  \"status\": \"ok\",\n  \"snippet\": \"\u003cdiv\u003e \u003c!-- HTML content --\u003e \u003c/div\u003e\"\n}\n```\n\n## Translations\n\nCurrently, this plugin is only available in English and Portuguese (Portugal).\n\nIf you want to add a new translation, check the [`translations`](#translations) option in the [`Options`](#options) section.\n\nIf you want to contribute with a translation (to be bundled with the plugin), go to the `translations` directory and create a new YAML file named with the locale that you wish to translate.\nFor example, if you want to add the German translation, create a `de.yml` file.\n\nIt will be very appreciated if you can contribute by making a pull request with the translation you wish to add.\n\n## Setup\n\nBelow are the steps required to set up a Stripe Checkout online shop, both in `hosted` and `embedded` mode.\n\n\u003e [!TIP]\n\u003e It is recommended that you use a library that enables environment variables\n\u003e to store your project credentials in a separate place from your code\n\u003e and to have separate development and production access keys.\n\nConsidering that you already have a Stripe account:\n\n### Step 1.\n\nGrab your public and secret keys from the Stripe Dashboard\nand add them to the [`stripePublicKey`](#stripepublickey) and [`stripeSecretKey`](#stripesecretkey) options.\n\n\u003e [!IMPORTANT]\n\u003e Make sure to grab the test keys when in development mode,\n\u003e and only use the production keys when the website is live.\n\n### Step 2.\n\nCreate a webhook to listen to Stripe Checkout events.\n\nWhen creating a webhook in the Stripe Dashboard (should be in the Developers page),\nmake sure to select the following Checkout events; otherwise it will not work correctly:\n- `checkout.session.completed`\n- `checkout.session.async_payment_succeeded`\n- `checkout.session.async_payment_failed`\n\nThe endpoint URL must be set to the following: `https://yourdomain.com/stripe/checkout/webhook`.\nThis is, your base URL followed by `/stripe/checkout/webhook`.\n\nWhen the webhook is created, grab its secret key and add it to the [`stripeWebhookSecret`](#stripewebhooksecret) option.\n\n\u003e [!IMPORTANT]\n\u003e The webhook will not work properly when developing locally,\n\u003e since the request cannot reach a local endpoint that only exists on your computer.\n\u003e Check the [Development](#development) section for more information on how to work with webhooks in development.\n\n### Step 3.\n\nFor the panel, you need to create a `orders` and a `order` blueprint.\nYou can change the `orders` name with the [`ordersPage`](#orderspage) option.\n\n```yaml\n# blueprints/pages/orders.yml\n\nextends: stripe-checkout.pages/orders\n```\n\n```yaml\n# blueprints/pages/order.yml\n\nextends: stripe-checkout.pages/order\n```\n\n\u003e [!NOTE]\n\u003e Remember to create a `orders` directory at `/content` with a `orders.txt` file.\n\u003e Otherwise, the page will not be found.\n\n### Step 4 (optional).\n\nSimilar to the previous step, create a `checkout-settings` blueprint.\nYou can change the `checkout-settings` name with the [`settingsPage`](#settingspage) option.\n\nCurrently, the only existing settings are to manage shipping data, like allowed countries and shipping rates.\nIf you don't need this information for your website (for example, if you are selling digital assets, where shipping information is not needed),\nyou can skip this step.\n\n```yaml\n# blueprints/pages/checkout-settings.yml\n\nextends: stripe-checkout.pages/checkout-settings\n```\n\n### Step 5.\n\nYou can create a product blueprint with any name.\n\nMake sure that you have a `price` field (it is required).\nTo add an image, add a `thumbnail` field (it is optional).\n\nThe plugin already comes with both blueprints fields, in case you want to use them:\n\n```yaml\n# blueprints/pages/product.yml\n\ntitle: Product\n\nfields:\n  price: stripe-checkout.fields/price\n  thumbnail: stripe-checkout.fields/thumbnail # optional\n```\n\n### `hosted` versus `embedded` mode\n\nDepending on the mode you are using, jump to the respective step below:\n- [Step 6: `hosted` mode](#step-6-hosted-mode)\n- [Step 6: `embedded` mode](#step-6-embedded-mode)\n\nFor more information about the difference between both modes, check the [`uiMode`](#uimode) option.\n\n### Step 6: `hosted` mode.\n\nWhen in `hosted` mode, you need to add a link to the website\nwith the URL generated by the following method `stripeCheckout()-\u003echeckoutUrl()`.\n\nThis link usually exists in the cart component or when reviewing the order before proceeding to the checkout.\n\nSomething like:\n\n```html\n\u003cdiv\u003e\n  \u003c!-- content with the order review and/or cart items --\u003e\n  \u003c!-- ... --\u003e\n\n  \u003ca href=\"/shop\"\u003eContinue shopping\u003c/a\u003e\n  \u003ca href=\"\u003c?= stripeCheckout()-\u003echeckoutUrl() ?\u003e\"\u003eProceed to checkout\u003c/a\u003e\n\u003c/div\u003e\n```\n\nMake sure to have at least one item added to the cart (check the [`Cart`](#cart) section) or it will throw an error.\n\nIt is also required to set the [`successPage`](#successpage) and the [`cancelPage`](#cancelpage) options.\n\n### Step 6: `embedded` mode.\n\nWhen in `embedded` mode, you need to use the [Stripe.js](https://docs.stripe.com/js) library\nas well as the following method `stripeCheckout()-\u003echeckoutEmbeddedUrl()`.\n\nYou have to create your own checkout page.\n\nSomething like:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003ctitle\u003eCheckout Page\u003c/title\u003e\n\n    \u003c!-- it is recommended by Stripe to include the script on all website pages to improve fraud detection --\u003e\n    \u003c!-- https://docs.stripe.com/js/including --\u003e\n    \u003cscript src=\"https://js.stripe.com/v3/\"\u003e\u003c/script\u003e\n\n    \u003cscript defer\u003e\n      // to initialize Stripe using the stripeCheckout()-\u003estripePublicKey() method\n      // you can also use option('programmatordev.stripe-checkout.stripePublicKey')\n      const stripe = Stripe('\u003c?= stripeCheckout()-\u003estripePublicKey() ?\u003e');\n\n      async function initialize() {\n        const fetchClientSecret = async () =\u003e {\n          // use the stripeCheckout()-\u003echeckoutEmbeddedUrl() method to fetch the client secret\n          // make sure it is a POST request\n          const response = await fetch('\u003c?= stripeCheckout()-\u003echeckoutEmbeddedUrl() ?\u003e', { method: 'POST' });\n          const { clientSecret } = await response.json();\n\n          return clientSecret;\n        };\n\n        const checkout = await stripe.initEmbeddedCheckout({ fetchClientSecret });\n\n        checkout.mount('#checkout-form');\n      }\n\n      initialize();\n    \u003c/script\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n    \u003cdiv id=\"checkout-form\"\u003e\u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nMake sure to have at least one item added to the cart (check the [`Cart`](#cart) section) or it will throw an error.\n\nIt is also required to set the [`returnPage`](#returnpage) option.\n\n## Development\n\n### Webhook\n\n#### Listen to events\n\nStripe webhooks will not work properly when developing locally,\nsince the request cannot reach a local endpoint that only exists on your computer.\n\nTo solve this, Stripe has a [CLI](https://docs.stripe.com/stripe-cli) that you can install on your computer.\nFollow the instructions in their [Stripe CLI](https://docs.stripe.com/stripe-cli) documentation page before proceeding.\n\nTo forward the events to a local endpoint, use the following command\n(you can also check their [documentation](https://docs.stripe.com/webhooks#test-webhook) for more information):\n\n```bash\nstripe listen --forward-to https://yourlocaldomain.com/stripe/checkout/webhook \\\n  --events checkout.session.completed,checkout.session.async_payment_succeeded,checkout.session.async_payment_failed\n```\n\nThis command will forward the events `checkout.session.completed`, `checkout.session.async_payment_succeeded`\nand `checkout.session.async_payment_failed` to the `https://yourlocaldomain.com/stripe/checkout/webhook` endpoint.\n\nThe endpoint must always be your local base URL followed by `/stripe/checkout/webhook`.\n\nAfter running the command, it will show you the webhook secret.\nAdd this secret to the [`stripeWebhookSecret`](#stripewebhooksecret) option.\n\nNow, if you submit the Stripe Checkout form (in `hosted` or `embedded` mode), it will be able to listen to the events.\n\n#### Trigger events\n\nIf you want to trigger the events without the need to submit the form every time, you can use the following command\n(make sure to open another terminal window, do not close the window where you ran the `listen` command):\n\n```bash\nstripe trigger checkout.session.async_payment_succeeded --add checkout_session:metadata.order_id=xxxxxx\n```\n\nThis command will trigger the `checkout.session.async_payment_succeeded` event (you can trigger any event).\nMake sure to always include the `--add checkout_session:metadata.order_id=xxxxxx`.\n\nThis is required because the plugin needs to share the Kirby order id across all events (to be in sync).\nYou can set any `order_id` value, as long as it is alphanumeric.\n\n## Production\n\nMake sure to change the [`stripePublicKey`](#stripepublickey), [`stripeSecretKey`](#stripesecretkey)\nand [`stripeWebhookSecret`](#stripewebhooksecret) options for their respective live values.\n\n\u003e [!TIP]\n\u003e It is recommended that you use a library that enables environment variables\n\u003e to store your project credentials in a separate place from your code\n\u003e and to have separate development and production access keys.\n\n## Contributing\n\nAny form of contribution to improve this library (including requests) will be welcome and appreciated.\nMake sure to open a pull request or issue.\n\n## License\n\nThis project is licensed under the MIT license.\nPlease see the [LICENSE](LICENSE) file distributed with this source code for further information regarding copyright and licensing.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrammatordev%2Fkirby-stripe-checkout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprogrammatordev%2Fkirby-stripe-checkout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprogrammatordev%2Fkirby-stripe-checkout/lists"}