Rekomi Docs
For developers
Developers

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 settle in USD, how the 1099-NEC handles non-USD earnings), see Multi-currency.

Supported currencies

Rekomi supports 135+ ISO 4217 codes, validated server-side on every ingest path: every currency Stripe can present a price in, plus the three-decimal Gulf currencies (BHD, JOD, KWD, OMR, TND) common on other gateways.

AED AFN ALL AMD AOA ARS AUD AWG AZN BAM
BBD BDT BHD BIF BMD BND BOB BRL BSD BWP
BYN BZD CAD CDF CHF CLP CNY COP CRC CVE
CZK DJF DKK DOP DZD EGP ETB EUR FJD FKP
GBP GEL GIP GMD GNF GTQ GYD HKD HNL HTG
HUF IDR ILS INR ISK JMD JOD JPY KES KGS
KHR KMF KRW KWD KYD KZT LAK LBP LKR LRD
LSL MAD MDL MGA MKD MMK MNT MOP MUR MVR
MWK MXN MYR MZN NAD NGN NIO NOK NPR NZD
OMR PAB PEN PGK PHP PKR PLN PYG QAR RON
RSD RUB RWF SAR SBD SCR SEK SGD SHP SLE
SOS SRD SZL THB TJS TND TOP TRY TTD TWD
TZS UAH UGX USD UYU UZS VND VUV WST XAF
XCD XCG XOF XPF YER ZAR ZMW

Codes are normalized to uppercase server-side, so usd and USD are equivalent on the wire. One transitional alias: amounts arriving as ANG (the retiring Netherlands Antillean guilder) are recorded as XCG, its one-to-one successor. Anything else (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, an absent or blank currency defaults to USD. Any other value must be a supported 3-letter code: a malformed value such as EURO or US$, and any 3-character value outside the supported list (including ones with digits like US1), is rejected with the same error (the trimmed, uppercased value you sent is echoed back). Since 2026-09-15 a malformed value is never silently treated as USD, so a typo in your integration surfaces as a 400 instead of recording the sale in the wrong currency:

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "error": "unsupported_currency",
  "currency": "XYZ"
}

unsupported_currency means either "this is not a 3-letter code" or "we recognize the code, we just do not carry an FX rate for it." Handle it by sending a supported code from your side, or contact support if you need the allowlist extended. The trimmed, uppercased value 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:

  1. Uppercases the code ("usd" → "USD").
  2. Checks it against the same supported allowlist used by the S2S postback.
  3. If supported, stores it on the conversion row.
  4. If unsupported (now very rare: the allowlist covers every Stripe presentment currency), the conversion is still recorded so no revenue is lost, and an internal alert fires with the offending code; the balance becomes payable once Rekomi extends the allowlist and rates exist for the code. Reference rates come from two mid-market sources: the ECB (via Frankfurter) for the majors and Xe for every other supported code.

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", "AFN", "ALL", "AMD", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM",
    "BBD", "BDT", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BWP",
    "BYN", "BZD", "CAD", "CDF", "CHF", "CLP", "CNY", "COP", "CRC", "CVE",
    "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ETB", "EUR", "FJD", "FKP",
    "GBP", "GEL", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HTG",
    "HUF", "IDR", "ILS", "INR", "ISK", "JMD", "JOD", "JPY", "KES", "KGS",
    "KHR", "KMF", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD",
    "LSL", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MUR", "MVR",
    "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD",
    "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON",
    "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SEK", "SGD", "SHP", "SLE",
    "SOS", "SRD", "SZL", "THB", "TJS", "TND", "TOP", "TRY", "TTD", "TWD",
    "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VND", "VUV", "WST", "XAF",
    "XCD", "XCG", "XOF", "XPF", "YER", "ZAR", "ZMW"
  ]
}
  • homeCurrency: current setting. "USD" for any org that never explicitly changed it.
  • changedAt: ISO-8601 timestamp of the most recent change, or null if never changed.
  • canChange: true when your plan includes home-currency changes (Pro tier). false otherwise. 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 full supported allowlist (135+ codes), 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 Admin role or above on the org (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:

HTTPerrorCause
400unsupported_currencyCode not in the supported allowlist. The response includes a supplied field with the code you sent.
402plan_tier_requiredPlan tier does not include home-currency changes
403insufficient_roleCaller is below the Admin role. The body includes required ("Admin") 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.paid payloads always carry the per-payout currency.
  • Sub-affiliate API: override conversion rows carry the same currency field as the parent sale.