Skip to content

Powered by Grav

Coming soon — KahunaCart is in final testing. Join the list and be first to know. Join the list

Configuration

This page lists every KahunaCart config key, its default, and what it does. All of them live in user/config/plugins/kahunacart.yaml.

Most keys also have a field on the plugin's settings page in the admin. Keys marked YAML-only have no admin field.

Clear the route cache after a plugin update

The API plugin caches its route table on disk under cache://api/. Installing, enabling, disabling, or removing a plugin invalidates that cache automatically. Updating an already-enabled plugin does not, so its new API endpoints return 404 while the admin screens that call them look installed.

After updating KahunaCart or any provider plugin, clear the cache:

BASH
bin/grav clear-cache

To drop only the route table, delete the directory:

BASH
rm -rf cache/api

Note

Route caching is skipped while system.debugger.enabled is true. This is why the problem appears in production and not in development.

Store

Key Default Effect
enabled true Master switch. Off means no storefront routes, no admin screen, no API endpoints.
route /shop Base route for the storefront. Every other storefront route lives under it: /shop/cart, /shop/product/{slug}, /shop/webhook/{slug}. Changing it changes your webhook URLs, so update them at every provider.
currency USD ISO 4217 code, exactly 3 characters. Stored once per order, so changing it does not rewrite history.
order_number_start 1000 First sequential order number. Numbers come from an atomic database sequence, so they never collide or repeat.
builtin_css true Enqueues the shipped storefront stylesheet on KahunaCart routes. Set to false when your theme owns all storefront styling. See Storefront → Styling and Theming.

Product images

Product images live in user/images/kahunacart/products/{productId}, which the web server serves directly. KahunaCart decides an upload's format by reading the file, never by its extension.

Key Default Effect
images.max_upload_mb 8 Largest single product image the admin upload endpoint accepts.
images.derivatives true Lets Grav generate resized copies for cards and thumbnails. false serves the originals.

Storefront SEO

These apply to product and category pages, and nowhere else.

Key Default Effect
seo.enabled true Emits JSON-LD, meta description, Open Graph, and Twitter cards.
seo.canonical false Emits <link rel="canonical">. Kahuna and Quark2 emit their own, so enable this only for a theme that does not.
seo.sitemap true Contributes product and category URLs to the Sitemap plugin when it is installed.
Key Default Effect
search.limit 50 Most results one search page shows at {route}/search?q=.

Tax

The flat rate below is a fallback engine. As soon as one tax zone exists, the zone engine takes over, and tax.rate, tax.apply_to_shipping, and tax.label stop being read. See Tax.

Key Default Effect
tax.rate '0' Flat percent as a string, such as '20' or '8.25'. Ignored once tax zones exist.
tax.included false Catalog prices already contain tax. Applies to both engines. The contained amount is back-calculated and shown on the receipt as an included adjustment that does not move the total.
tax.apply_to_shipping false Whether the flat rate taxes shipping too. Ignored by the zone engine, which decides this per rate.
tax.label 'Tax' Label on the flat-rate adjustment. Ignored by the zone engine, which uses each rate's own label.
tax.basis shipping Which address decides the zone: shipping or billing. The other address is the fallback when the chosen one has no country. This governs shipping zone matching too.

Shipping

The flat rate applies until the first shipping zone exists. See Shipping.

Key Default Effect
shipping.flat_rate '0' Decimal string in the store currency, such as '5.99'. 0 means no shipping charge. Applied to any order containing a physical item. Ignored once shipping zones exist.
shipping.label 'Shipping' Label on the flat-rate adjustment.

Stock

Key Default Effect
stock.hold_minutes 15 How long a stock hold keeps stock reserved while a customer is away at a redirect payment provider. Holds expire on their own, so an abandoned payment never strands stock. 0 reserves nothing.

Cart

Key Default Effect
cart.purge_days 90 Days of inactivity before an unfinished cart, its items, and its adjustments are deleted. 0 keeps carts forever. Runs on every worker tick.
cart.abandoned_enabled false Sends a one-time reminder email to customers who left something in their cart. Requires the Email plugin.
cart.abandoned_hours 24 Hours a cart must sit untouched before it earns its reminder. Each cart is mailed once, ever.

A cart qualifies for a reminder only if it has an email address on it. In practice that means the customer submitted the checkout form and then did not pay.

Emails

Both emails render from templates/emails/*.twig and are overridable in your theme like any other Grav template.

Key Default Effect
emails.store_copy_to '' BCC address for every order confirmation. Empty sends no copy.
emails.abandoned_subject '' Subject line for the abandoned-cart reminder. Empty uses the translated default, "You left something in your cart".

Checkout

Key Default Effect
checkout.require_terms false Shows a terms checkbox on the checkout form and refuses the submit without it.
checkout.default_country '' ISO 3166-1 alpha-2 code the country select starts on, such as US. Empty means the customer chooses.

Address validation

Optional delivery-address checking through a third-party geocoder, billed to your own account with that provider. It stays off until you set both a provider and a key. See Address validation.

Key Default Effect
checkout.address_validation.provider none none, mapbox, or google.
checkout.address_validation.api_key '' Your own key. Server-side only, never sent to the browser.
checkout.address_validation.mode suggest suggest offers corrections at checkout. off checks and stamps the order silently.

Note

Address validation never blocks a sale. A service that is down, slow, or out of quota is logged and waved through.

Customer accounts

The account area needs the Login plugin, which owns the sign-in form, forgot password, magic links, two-factor, and remember-me. KahunaCart never authenticates anybody itself and never writes to a user account YAML. account.db_identity decides only where a customer's credentials are kept. See Customer accounts.

Key Default Effect
account.db_identity true Storefront customers sign in against KahunaCart's own database instead of user/accounts/*.yaml. Admin accounts are unaffected and always win a lookup. Read Store accounts before changing it.
account.checkout_registration true Offers guests an opt-in account at checkout. The account is opened at order completion and the customer gets an emailed link to set a password. Requires account.db_identity.
account.invite_expiry_days 7 How long a set-password link stays clickable. After that the ordinary forgot-password form works for them.
account.claim_by_email true When someone logs in with no order history, matches them to a guest customer record with the same email address and hands them that history. A record another account already holds is never reassigned.

Warning

Turn account.claim_by_email off if anyone can register with an email address they do not own. See the trade-off.

Invoices

Invoices print at {route}/order/{hash}/invoice. No PDF is generated; the browser's print dialog is the export.

Key Default Effect
invoice.store_name '' Printed at the top of every invoice. Empty falls back to the site title.
invoice.store_address '' Your business address, one line per line.
invoice.tax_id '' VAT or tax registration number. Omitted from the invoice when empty.
invoice.footer '' Markdown printed at the foot of every invoice.

Offline payments

All three keys are on the plugin settings page, under Commerce → Offline Payment.

Key Default Effect
offline.enabled true Registers the built-in offline provider as a payment option.
offline.label 'Bank Transfer' What the customer sees at checkout.
offline.instructions '' Markdown shown on the confirmation page for offline orders, such as where to send the money.

Digital delivery

See Digital products for the full picture, including the nginx and Apache configuration the non-PHP delivery methods need.

Key Default Effect
downloads.grant_on paid When download grants are created. paid waits for funds to be captured. completed grants as soon as the order is placed, which is what offline methods need.
downloads.default_limit ~ (unlimited) Downloads allowed per grant when the file itself sets no limit.
downloads.default_expiry_days ~ (never) Grant lifetime in days when the file itself sets none.
downloads.method php php, xaccel, or xsendfile. Anything unrecognized falls back to php.
downloads.xaccel_prefix /kahunacart-files/ Internal nginx location that maps to the files directory. Used only by the xaccel method.
downloads.path '' Where downloadable files live. Empty means user-data://kahunacart/files. Absolute paths and Grav stream URIs both work. An absolute path outside the document root is the safest setup.
downloads.max_upload_mb 512 Largest single file the admin upload endpoint accepts. PHP's upload_max_filesize and post_max_size still apply and are usually the lower limit.

default_limit and default_expiry_days read as unset when empty, non-numeric, or zero or below. Clearing the admin field means unlimited or never, not zero.

Merchant notifications

Outbound notifications to Slack, Discord, or an endpoint of your own. No channel is configured by default. See Notifications for payload details and the signing contract.

Key Default Effect
notifications.enabled true Master switch. false silences every channel without deleting them.
notifications.low_stock_threshold 5 Stock at or below this earns a stock.low event. 0 reports only when an item has run out.
notifications.timeout 5 Seconds allowed per channel per POST. Capped at 15.
notifications.channels [] The list of channels.

Each entry in notifications.channels takes these keys.

Key Effect
label Name shown in the admin, such as Sales.
type slack, discord, or webhook.
url The endpoint you paste from the service.
enabled Whether this channel sends.
events List of event names, such as [order.completed, payment.received], or all.
secret Signs the request body. Webhook channels only.

Webhook log and job warnings

Key Default Effect
payments.webhook_log_days 30 Webhook delivery rows older than this are swept by the worker. 0 keeps them forever.
jobs.stale_after_minutes 15 The admin warns when the oldest waiting job is older than this. 0 disables the warning.

Important

Background work is queued and drained by Grav's scheduler. If the scheduler is not running, the queue piles up and customers who paid for a download never get one. See Troubleshooting.

Catalog sync

YAML-only. The keys are provider slugs the base plugin cannot know in advance, so there is no admin field for them. See Sync.

YAML
sync:
  polar:
    direction: remote
Direction Meaning
local The local catalog is master. Admin product writes queue a push job per local-master provider.
remote The provider is master. Its catalog webhooks apply locally, and pull jobs re-pull it.
off Default. Nothing runs automatically. Anything unrecognized reads as off.

Direction governs automatic work only. A manual bin/plugin kahunacart sync --push --provider=<slug> or --pull --provider=<slug> always does what you asked.

Database

Key Default Effect
database.type sqlite sqlite, mysql, pgsql, or connection.
database.auto_migrate sqlite When schema updates are applied automatically. See The auto_migrate policy.
database.sqlite.path '' Empty means user-data://kahunacart/db/kahunacart.sqlite.
database.mysql.host localhost MySQL or MariaDB host.
database.mysql.port 3306 MySQL or MariaDB port.
database.mysql.dbname '' Database name.
database.mysql.username '' Database user.
database.mysql.password '' Database password.
database.pgsql.host localhost PostgreSQL host.
database.pgsql.port 5432 PostgreSQL port.
database.pgsql.dbname '' Database name.
database.pgsql.username '' Database user.
database.pgsql.password '' Database password.
database.connection '' Name of a connection defined in the Database plugin. Read only when database.type is connection.

SQLite

The zero-configuration default. KahunaCart creates the directory, writes deny-all protection files into it, chmods the database file to 0640, and opens it with journal_mode=WAL, foreign_keys=ON, busy_timeout=5000, synchronous=NORMAL, and temp_store=MEMORY.

MySQL / MariaDB

KahunaCart connects with charset=utf8mb4 and assumes the server runs in strict mode. bin/plugin kahunacart status warns you when it does not, because a non-strict MySQL truncates data silently instead of refusing it.

PostgreSQL

A standard connection. There is nothing extra to configure.

Named connections

Set database.type to connection to hand connection management to the Database plugin. Put the connection name in database.connection:

YAML
database:
  type: connection
  connection: commerce

KahunaCart pulls the PDO handle from that connection and wraps it in the matching dialect. Two errors are possible:

  • database.type is "connection" but database.connection is empty — set database.connection.
  • named connections require the "database" plugin — install the Database plugin.

The auto_migrate policy

Value Behaviour
sqlite (default) Auto-migrates only when the engine is SQLite. Server databases are left alone.
auto Always auto-migrates, on every engine.
manual Never auto-migrates. bin/plugin kahunacart migrate is the only way schema changes get applied.

When auto-migration is active, the check runs on every non-admin frontend request and on every KahunaCart admin API request. It is a single "is anything pending" query, and it applies migrations only when something is.

Warning

Migrations are up-only. There are no down migrations, so the recovery model is to restore from backup. Applies run under a database run-lock, so two concurrent requests, or a request racing a CLI run, cannot interleave DDL.