Conversion currency
ISO 4217 allowlist, error codes, Stripe normalization, and the home-currency settings endpoint.
Every conversion ingested by Rekomi carries a currency field. The full list of supported codes is below, plus the error response shape when an unsupported code is sent and the developer-side surface for reading or changing the org's home (display) currency.
For the brand-facing concept page (when to change HomeCurrency, how FX normalization works, how payouts are split per currency, how the 1099-NEC handles non-USD earnings), see Multi-currency.
Supported currencies (v1)
Rekomi supports 31 ISO 4217 codes, validated server-side on every ingest path.
USD EUR GBP CAD AUD JPY CHF SEK NOK DKK
NZD SGD HKD MXN BRL INR ZAR PLN CZK HUF
RON ILS TRY KRW PHP THB MYR IDR AED SAR
CNYCodes are normalized to uppercase server-side, so usd and USD are equivalent on the wire. Anything else (lowercase still-not-in-list codes, crypto tickers, currency-substitute tokens like XBT, retired codes) is rejected.
Ingest paths that carry a currency
Conversions carry a currency on two ingest paths: the server-to-server postback and the payment-processor webhooks.
POST /api/tracking/s2s
Server-to-server, HMAC-signed. See S2S tracking for auth + signing.
{
"externalEventId": "purchase_abc123",
"affiliateSlug": "jane-recommends",
"amountCents": 9900,
"currency": "EUR",
"customerId": "cus_external_xyz"
}currency is optional. Omit to default to "USD".
Currency handling on the S2S postback
On the postback, a currency value that is not exactly 3 characters after trimming (empty, or a longer value like EURO) is treated as absent, and the conversion defaults to USD. Any 3-character value outside the supported list, including ones with digits like US1, is rejected:
HTTP/1.1 400 Bad Request
Content-Type: application/json{
"error": "unsupported_currency",
"currency": "XYZ"
}unsupported_currency means "we recognize this is a real 3-letter code, we just do not carry an FX rate for it." Handle it by mapping to a supported code on your side, or contact support if you need the allowlist extended. The uppercased code you sent is echoed back in currency.
Curl examples
USD conversion (S2S)
BODY='{"externalEventId":"order_001","affiliateSlug":"jane","amountCents":9900,"currency":"USD"}'
T=$(date +%s)
SIG=$(printf "%s.%s" "$T" "$BODY" | openssl dgst -sha256 -hmac "$REKOMI_SIGNING_SECRET" -hex | awk '{print $2}')
curl -sS https://api.rekomi.com/api/tracking/s2s \
-H "Authorization: Bearer $REKOMI_API_KEY" \
-H "X-Rekomi-Signature: t=$T,sig=$SIG" \
-H "Content-Type: application/json" \
-d "$BODY"EUR conversion (S2S)
BODY='{"externalEventId":"order_002","affiliateSlug":"jane","amountCents":8900,"currency":"EUR"}'
T=$(date +%s)
SIG=$(printf "%s.%s" "$T" "$BODY" | openssl dgst -sha256 -hmac "$REKOMI_SIGNING_SECRET" -hex | awk '{print $2}')
curl -sS https://api.rekomi.com/api/tracking/s2s \
-H "Authorization: Bearer $REKOMI_API_KEY" \
-H "X-Rekomi-Signature: t=$T,sig=$SIG" \
-H "Content-Type: application/json" \
-d "$BODY"JPY conversion (S2S)
JPY has no minor unit. amountCents is still required, but Rekomi treats the integer as whole yen on display. A 12,000 JPY sale is "amountCents": 12000.
BODY='{"externalEventId":"order_003","affiliateSlug":"jane","amountCents":12000,"currency":"JPY"}'
T=$(date +%s)
SIG=$(printf "%s.%s" "$T" "$BODY" | openssl dgst -sha256 -hmac "$REKOMI_SIGNING_SECRET" -hex | awk '{print $2}')
curl -sS https://api.rekomi.com/api/tracking/s2s \
-H "Authorization: Bearer $REKOMI_API_KEY" \
-H "X-Rekomi-Signature: t=$T,sig=$SIG" \
-H "Content-Type: application/json" \
-d "$BODY"Stripe-webhook currency handling
For brands using the Stripe integration, conversion currency comes from the currency field on the Stripe subscription-created and invoice-paid events. Stripe lowercases everything ("usd", "eur"). Rekomi:
- Uppercases the code (
"usd"→"USD"). - Checks it against the same 31-code allowlist used by the S2S postback.
- If supported, stores it on the conversion row.
- If unsupported (rare; Stripe supports more currencies than the ECB publishes daily rates for), the conversion is still recorded so payouts can run, but an internal alert fires with the offending code so Rekomi can decide whether to extend the allowlist.
This means: Stripe brands cannot accidentally drop conversions by selling in a non-allowlisted currency. The S2S postback is stricter because the caller controls the field and can validate before sending.
Reading / updating the home currency
Your application can read or set the org's HomeCurrency through a settings endpoint, using the same Authorization: Bearer rk_live_* auth as the rest of the API.
GET /api/v1/settings/home-currency
{
"homeCurrency": "USD",
"changedAt": null,
"canChange": true,
"supportedCurrencies": [
"AED", "AUD", "BRL", "CAD", "CHF", "CNY", "CZK", "DKK", "EUR", "GBP",
"HKD", "HUF", "IDR", "ILS", "INR", "JPY", "KRW", "MXN", "MYR", "NOK",
"NZD", "PHP", "PLN", "RON", "SAR", "SEK", "SGD", "THB", "TRY", "USD",
"ZAR"
]
}homeCurrency: current setting."USD"for any org that never explicitly changed it.changedAt: ISO-8601 timestamp of the most recent change, ornullif never changed.canChange:truewhen your plan includes home-currency changes (Pro tier).falseotherwise. Trials grant the features of the trialed tier only, with no separate trial bypass. Use this to gate UI without making a failing PUT.supportedCurrencies: the 31-code allowlist, returned in alphabetical order. Provided so clients don't have to hard-code the list.
PUT /api/v1/settings/home-currency
{ "homeCurrency": "EUR" }Requires:
- The Owner role on the org (Admin / Manager / Viewer return 403).
- A verified email on the calling account.
- A plan tier that includes home-currency changes (Pro tier). A trial grants the features of the trialed tier only; it is not a bypass.
- For API-key callers, a key with read and write access.
- A supported currency code.
Response on success:
{
"homeCurrency": "EUR",
"changed": true,
"changedAt": "2026-05-18T14:22:01Z"
}changed is false when the value was already set (an idempotent repeat).
Error responses:
| HTTP | error | Cause |
|---|---|---|
| 400 | unsupported_currency | Code not in the 31-code allowlist. The response includes a supplied field with the code you sent. |
| 402 | plan_tier_required | Plan tier does not include home-currency changes |
| 403 | insufficient_role | Caller is not the Owner of the org. The body includes required ("Owner") and actual (the caller's role). |
Unsupported-currency shape on this settings PUT:
{ "error": "unsupported_currency", "supplied": "XYZ" }Note this differs from the S2S postback, which returns the offending code under a currency key (uppercased) rather than supplied.
PUTs are idempotent: setting the same currency twice returns 200 both times, and only the first call writes a changedAt + audit-log entry.
See also
- Multi-currency for brands: concept page, payout splitting, tax-form handling.
- S2S tracking: server-side ingestion + refund endpoint.
- Webhooks:
payout.created/payout.paidpayloads always carry the per-payoutcurrency. - Sub-affiliate API: override conversion rows carry the same
currencyfield as the parent sale.