Skip to content

Powered by Grav CMS + Helios Theme

Settings reference

Every key the shipping add-on reads lives in user/config/plugins/kahunacart-shipping.yaml, and every key on this page has a field on the settings screen. The defaults are the ones the plugin ships.

Where these are edited

KahunaCart → Shipping carriers → Settings. This is Grav's own configuration form, built from this plugin's blueprint — the same form the Grav admin's Plugins → KahunaCart Shipping page draws. The Save button in the admin's header saves it.

Important

Settings save where the admin's environment picker says. With the picker on Default that is the base config; with a named environment chosen it is that environment's copy.

The master switch

Key Default What it does
enabled true Off, and every method bound to this carrier goes unavailable with a reason, with your fallback method carrying checkout. That is KahunaCart's own carrier-unavailable path, unchanged. The rows stay in the database.

General

Key Default What it does
aggregator shippo Choose shippo, easypost, shipengine or sendcloud. One driver per store. demo is the simulation below.
mode test test or live. Decides which token is used. Sendcloud has one key pair for both, so for Sendcloud it decides instead whether a label is bought as the free test label (test) or as the service you chose (live).
excluded_classes empty Shipping class codes this carrier will not take, comma separated. Empty, and nothing changes. See Carriers and services.
timeout 10 Seconds this plugin allows a label or a tracking call. Rates are not in it — those run inside shipping.carrier_rates.timeout.

Shippo

Key Default What it does
shippo.test_token empty The key beginning shippo_test_. A live key pasted here is refused before a call is made.
shippo.live_token empty The key beginning shippo_live_. Nothing uses it until mode is live.
shippo.account_currency empty The currency the Shippo account is billed in, as a three-letter code. Rates are asked for and labels are bought in it, whatever an order was sold in. Empty is the store's own (base) currency. See Selling in more than one currency.
shippo.webhook_secret empty The random part of the inbound tracking webhook's own address, and the only thing authenticating it. You make it up and register the address at Shippo yourself. See Tracking.
shippo.webhook_ips empty The only addresses a tracking webhook is accepted from. Empty accepts any, which is the default and the right one for most stores. auto uses Shippo's nine published addresses; anything else is a comma-separated list.

EasyPost

Key Default What it does
easypost.test_key empty The key beginning EZTK from EasyPost's API Keys page. A production key pasted here is refused before a call is made.
easypost.live_key empty The key beginning EZAK. Nothing spends money with it until mode is live, but paste it anyway: EasyPost only lists your carrier accounts to a production key, and Refresh carriers needs them in either mode.
easypost.account_currency empty The currency the EasyPost account is billed in. Empty is the store's own.
easypost.webhook_secret empty The random part of the inbound tracking webhook's address, and what EasyPost's signing key is worked out from. You make it up; Register webhook hands EasyPost a key derived from it, and every delivery is checked against that. Changing it means registering again.
easypost.webhook_ips empty Leave it empty. EasyPost publishes no list of the addresses it delivers from and asks you to check the signature instead, which the add-on does on every delivery. An address list you put together yourself will lock you out the first time EasyPost moves a server.

ShipEngine

Key Default What it does
shipengine.test_key empty The sandbox API key beginning TEST_. A production key here is refused before a request.
shipengine.live_key empty The production API key, which must not begin TEST_. Used only in live mode.
shipengine.account_currency empty The currency the ShipEngine account is billed in. Empty is the store's own.
shipengine.webhook_secret empty The random secret used in the tracking address and to derive its required shared-secret header. See Tracking.

The corresponding block in the plugin defaults is:

YAML
shipengine:
  test_key: ''
  live_key: ''
  account_currency: ''
  webhook_secret: ''

Sandbox and production keys access separate environments. The driver never falls back to a production key for carrier discovery. All three fields are declared for encrypted storage on save.

Sendcloud

Key Default What it does
sendcloud.public_key empty The public key of a Sendcloud API integration (Settings, Integrations in Sendcloud). One key pair serves both modes, because Sendcloud has no sandbox.
sendcloud.secret_key empty The secret key beside it. Sendcloud also signs every tracking update with it, so it is what the store checks each delivery against. The driver is not used until both keys are set.
sendcloud.account_currency empty The currency the Sendcloud account is billed in: EUR for most accounts, GBP for a UK one. Empty is the store's own.
sendcloud.webhook_secret empty The random part of the tracking address. It is not what Sendcloud signs with. Press Generate secret and then Register webhook rather than typing one.
sendcloud.vat_number empty Your VAT number with its country prefix, sent on the customs declaration of a commercial export. Sendcloud refuses one without it unless the label runs on your own carrier contract.
sendcloud.eori_number empty Your EORI number, sent beside the VAT number when it is set.

The corresponding block in the plugin defaults is:

YAML
sendcloud:
  public_key: ''
  secret_key: ''
  account_currency: ''
  webhook_secret: ''
  vat_number: ''
  eori_number: ''

The two keys and the webhook secret are declared for encrypted storage on save.

Packing

Key Default What it does
packing.default_box empty The code of the box anything that fits nothing else goes in. Empty means the built-in fallback, and those parcels are marked as estimates.
packing.dim_divisor 5000 Length × width × height in centimetres over this is the parcel's weight in kilograms as the courier bills it.
packing.dim_divisors {} Per-carrier overrides, keyed by the courier's own token: { ups: 4000 }.
packing.padding_mm 10 Millimetres kept free on each side of a box for packing material.

Labels

Key Default What it does
labels.format pdf_4x6 pdf_4x6, pdf, png or zpl. Chosen before a label is bought, because no courier converts one afterwards.
labels.open_after_buy true Open a label in a new tab the moment it is bought.
labels.auto_buy_on_paid false Buy a label once an order is paid in full: straight away for a card payment, and when the money arrives for a bank transfer, an authorised card or a deposit's balance. Worth leaving off until the packing looks right. See Buy a label automatically.
labels.retain_days 0 Days a label file is kept on disk. 0 keeps every one for ever, which is what most stores want, because a courier's own link to the file expires.

Tracking

Key Default What it does
tracking.poll_hours 6 How often a parcel with no webhook news is asked about directly. The poll is what makes tracking correct on a store whose webhook never arrives.
tracking.poll_until_days 45 How long a parcel is polled before it is given up on.

Customs

Only ever used when the destination country differs from the ship-from country. See Customs.

Key Default What it does
customs.certify_signer empty The name of the person certifying a declaration. A courier refuses an international parcel without one.
customs.origin_country empty Where your goods are made, for every product that does not say otherwise. Two letters, such as US.
customs.contents_type MERCHANDISE DOCUMENTS, GIFT, SAMPLE, MERCHANDISE, HUMANITARIAN_DONATION, RETURN_MERCHANDISE or OTHER.
customs.contents_explanation empty Required, and only used, when the contents type is OTHER. Checked before anything is sent.
customs.non_delivery RETURN RETURN or ABANDON: what the courier does with a parcel nobody accepts.
customs.eel_pfc NOEEI_30_37_a The US export exemption. The default covers a shipment under $2,500 per commodity.
customs.aes_itn empty Required when the exemption is AES_ITN, ignored otherwise. Checked before anything is sent.
customs.incoterm empty DDP, DDU, FCA, DAP or eDAP. DDP means you pay the duty and the customer gets no bill at the door.

The demo carrier

A driver that quotes, prints labels, tracks parcels and refunds postage without opening a socket. It is what the demo store runs on, and it is how you walk these screens before you have an account anywhere.

Key Default What it does
demo_carrier.enabled false Allow the simulation. Both this and aggregator: demo have to be set before anything is registered. With this off, aggregator: demo registers nothing, exactly as shippo with no token does.
demo_carrier.account_currency empty The currency the demo quotes in. Empty, and it quotes in whatever currency the cart is in, so a demo store can show carrier rates in every currency it sells in. It quotes the same minor units in each and never converts.
demo_carrier.transit_minutes 36 How long a demo parcel's whole journey takes, from label to doorstep. Clamped to between 1 and 1440.

Warning

Never run this on a store that posts things. Every price it quotes is invented, and every label it prints says SIMULATION — NOT VALID FOR POSTAGE across the top. A store running it charges customers for postage nobody will carry.

It is not keyed off KahunaCart's demo.readonly, because those two switches mean different things. A staging box wants a read-only admin and still wants its real carrier.

Switch it on, then seed it:

BASH
bin/plugin kahunacart-shipping seed

That writes a ship-from address, four boxes, both invented carrier accounts, sizes onto the seeded catalogue, an oversized product, methods bound to the demo services, and eleven orders covering every state a label and a parcel can be in. It is idempotent, and --purge takes back exactly what it wrote.

Settings that belong to KahunaCart, not here

Four things this add-on depends on and does not own. All four are on KahunaCart's own Shipping screen, and the Shipping carriers screen complains about the first two with a button rather than writing them itself.

Key Default What it does
shipping.carrier_rates.enabled false Until this is on, no courier is asked anything and every bound method is shown unavailable.
shipping.carrier_rates.fallback_method_id null The ordinary flat-rate method that carries checkout whenever a courier is down. Nominate one.
shipping.carrier_rates.timeout 5 Seconds a driver gets to answer a quote. A driver that comes back late has its answer discarded.
shipping.carrier_rates.cache_ttl 900 How long a quote is kept. 0 asks the courier every time.

Secrets at rest

Every key that can spend money or prove a tracking update is stored encrypted in user/config/plugins/kahunacart-shipping.yaml: each driver's API keys or tokens and its webhook secret. The add-on declares them on onKahunaCartCollectEncryptedSettings, the same way a payment provider declares its own, and KahunaCart encrypts them whenever the file is saved. In the file each one reads enc:v1: followed by the ciphertext.

The encryption key is your store's site secret, which lives in the database rather than in any file, so a copy of the settings file on its own does not give the keys away. KahunaCart decrypts them in memory at the start of each request. A value that cannot be decrypted, for example in a settings file copied to a store with a different database, reads as empty and is logged, and the driver then reports that it has no key.

A key typed into the file by hand stays in plain text until the next time the file is saved, which encrypts it along with everything else. Saving any setting on the add-on's tabs is enough.