Skip to content

Powered by Grav CMS + Helios Theme

Exchange rates and currencies

The exchange rates between your currencies, converted-price settings, the currency a report is shown in, and the gateway account behind a payment method.

Everything the Currencies screen and the report currency picker read and write, and the two routes that check and register a payment method's own gateway account. See Currencies and Selling through more than one company.

List the exchange rates

GET /api/v1/kahunacart/currencies/rates Permission kahunacart.settings

The exchange rates between the store's base currency and each currency it sells in. Answers the rate source (source, and every source the store knows in sources), the fallback asked for what the source does not answer (null for none), how many working days old a fetched rate may get before it counts as old (max_age_days), whether the store fetches rates at all (fetches: a second currency and a source other than manual), and one row per currency with its rate (a decimal string, how many of that currency one unit of the base buys, or null when there is none), its source, rate_date (the day the source says the rate is for, YYYY-MM-DD, null for a typed rate), how long since it was last checked in seconds, pinned (a person typed it, so a refresh leaves it alone), stale, missing, held (null, or a fetched rate that moved more than the store allows and waits for accept_exchange_rate or keep_old_exchange_rate: old, new, moved_percent, source, date), and on a typed rate market (null, or what the last refresh got for it: rate, source, date, away_percent). last_refresh says how the last fetch went and why, when it failed, which source answered each rate (answered_by), and in note why the source could not answer when the fallback answered for it. A store that sells in one currency answers enabled false and no rows. On a multi-currency store, pricing answers missing_price and each currency's configured mode, effective converts flag, markup and rounding.

Look up today's market exchange rates

GET /api/v1/kahunacart/currencies/rates/lookup Permission kahunacart.settings

Ask Frankfurter once for today's market rates between the store's base currency and each currency it sells in, and write nothing. Answers currency code => {rate, date, source}, each rate a decimal string, plus away_percent (a decimal string such as "5.05") for a currency whose rate was typed, saying how far that rate is from the market one. The market answer is kept for an hour, so asking again within the hour makes no request. Use it to compare a typed rate with the market, then set_exchange_rate to type one. Answers 502 with the reason when Frankfurter cannot answer, and 404 on a store that sells in one currency.

Type an exchange rate

PUT /api/v1/kahunacart/currencies/rates/{quote} Permission kahunacart.settings

Set the rate between the base currency and one of the store's other currencies by hand. It is pinned: a refresh from a rate source never overwrites it, and a typed rate never counts as old. Delete it to hand the pair back to the source. Send the rate as a string with at most twelve decimal places, how many of the currency one unit of the base buys ("0.92" for euros on a dollar store). A JSON number with a fraction is refused. Answers the same document as list_exchange_rates.

Parameters

Name Type Description
quote required string The currency code, one of the store's extra currencies (EUR)
rate required string How many of that currency one unit of the base buys, a positive decimal string like "0.92"

Remove an exchange rate

DELETE /api/v1/kahunacart/currencies/rates/{quote} Permission kahunacart.settings

Remove the stored rate for one currency, whether a person typed it or a source fetched it. The next refresh from the rate source fills it in again. Until then the store has no rate for it: nothing converts into that currency and an order in it records no rate. Answers the same document as list_exchange_rates.

Parameters

Name Type Description
quote required string The currency code (EUR)

Fetch the exchange rates now

POST /api/v1/kahunacart/currencies/rates/refresh Permission kahunacart.settings

Fetch the rates from the configured source now, instead of waiting for the daily job. The fallback is asked for whatever the source did not answer, or for everything when the source cannot be reached. A rate that moved more than currencies.rates.hold_move_percent is held instead of written and listed in result.held; the rest are written as usual. The fetch runs inside this request, so it waits for the source. A rate someone typed is left alone, a currency the source does not list keeps its old rate, and a source that cannot answer changes nothing and is answered as result.ok false with the reason in result.error. Answers 422 when the store has nothing to fetch (the manual source, or one currency). Otherwise it answers result (what was written, what changed and how far it moved, what was left alone) beside the same document as list_exchange_rates.

Accept a held exchange rate

POST /api/v1/kahunacart/currencies/rates/{quote}/accept Permission kahunacart.settings

Accept a rate a refresh held because it moved more than currencies.rates.hold_move_percent from the rate in use. Send the held rate you saw (held.new from list_exchange_rates) as new. It is written with the source and day it came with and is not pinned, so it keeps updating from the source, and the catalog index is told the way a refresh tells it. Answers 409 when the hold is gone or now holds a different rate, and writes nothing. Answers the same document as list_exchange_rates.

Parameters

Name Type Description
quote required string The currency code of the held rate (EGP)
new required string The held rate you are accepting, as a decimal string, exactly as list_exchange_rates shows it in held.new

Keep the old exchange rate

DELETE /api/v1/kahunacart/currencies/rates/{quote}/held Permission kahunacart.settings

Turn down a held rate and keep the one in use. The hold goes; the next refresh holds the rate again if the move is still there. To stop being asked, type a rate with set_exchange_rate. Answers the same document as list_exchange_rates.

Parameters

Name Type Description
quote required string The currency code of the held rate (EGP)

Set pricing in each currency

PUT /api/v1/kahunacart/currencies/pricing Permission kahunacart.settings

Save manual or converted pricing per enabled currency, with markup and rounding. Typed amounts always win. missing_price convert makes every enabled currency with a rate convert, keeping its markup and rounding. No rate means no conversion. Answers list_exchange_rates with pricing beside rates and queues the catalog index update. Open carts keep their quoted prices.

Parameters

Name Type Description
missing_price optional string
One of: unavailable, convert
pricing required object Currency code to pricing choices; currencies omitted stay as they were. Only enabled extra currencies are accepted.

Read this admin's report currency

GET /api/v1/kahunacart/reports/currency Permission kahunacart.reports

Read the saved currency selection and available completed-order currencies, base first. HTTP also permits customer or order readers. Single-currency stores return an empty currency list.

Remember this admin's report currency

PUT /api/v1/kahunacart/reports/currency Permission kahunacart.reports

Remember a known currency code or all for exact frozen-rate totals in base currency. Only this calling admin's preference changes. Explicit report queries still name their currency. HTTP also permits customer or order readers.

Parameters

Name Type Description
currency required string A known currency code or all

Check a payment method account

POST /api/v1/kahunacart/payment-methods/{id}/check-account Permission kahunacart.settings

Check the saved credentials for this method’s account without returning secrets.

Parameters

Name Type Description
id required integer Payment method ID

Set up a payment method webhook

POST /api/v1/kahunacart/payment-methods/{id}/setup-webhook Permission kahunacart.settings

Register this method’s own endpoint and store its signing secret encrypted.

Parameters

Name Type Description
id required integer Payment method ID
reset optional boolean Replace only this account revision’s endpoint

A rate is a decimal string with at most twelve decimal places, how many of the currency one unit of the base buys, and a JSON number with a fraction is refused because a rate is never a float. A rate you type is pinned, so a refresh leaves it alone. Refresh runs inside the request, because a person pressing the button is waiting for the answer, and it answers 422 when there is nothing to fetch (the manual source). A refresh asks the source first and then the fallback for what it didn't answer. A fetched rate that moved more than currencies.rates.hold_move_percent is held and not written, and accept and held answer it. Look up asks Frankfurter once and writes nothing. See A big move is held for you to check. A single-currency store answers enabled false and no rows. On a converting store the rates read also carries pricing, and product and variant reads carry converted_amounts, which are editor hints and never typed prices.

Saving pricing needs all three of mode, markup_percent and rounding for each currency you send, and a currency you leave out is left alone. The base currency and disabled currencies are refused, and a JSON float markup is refused. See Converted prices.

The report currency is a code the store knows, or all for everything in the base currency. A bad code or a value that isn't a string is a 422. A report call that names a currency always wins, and the API never applies the saved choice on its own. See Reports and totals.

The two payment method routes contact the gateway only when someone runs them on purpose, and neither answers with a secret. See Give each payment method its own Stripe account.