Skip to main content
Wallet credentials can accept deposits in a currency that differs from the wallet’s own — every arriving deposit is automatically converted into the wallet’s currency at the FX rate live at deposit time. Two directions:
  • Auto-onramp — a fiat credential on a crypto wallet. The payer sends fiat; the wallet is credited in crypto.
  • Auto-offramp — a crypto credential on a fiat wallet. The payer sends crypto; the wallet is credited in fiat.
Same-currency credentials — where the credential currency matches the wallet’s currency — remain the default and credit the wallet balance directly, with no conversion.

Create a cross-currency credential

Pass an explicit currency on POST /v1/wallets/:id/credentials that is different from the wallet’s currency. Currency codes are uppercase (NGN, USDC, GHS, USDT, KES, …).
network is validated against the credential’s own currency, not the wallet’s. So an NGN credential uses bank; a USDC credential uses base / ethereum / solana.

Eligibility

Cross-currency is admitted only when every condition below holds. Any failure returns a 400 with invalid_input.
  • The pair must be crypto ↔ fiat. Crypto ↔ crypto and fiat ↔ fiat are rejected.
  • Both currencies must advertise the matching direction capability:
    • Auto-onramp requires canOnramp on the credential currency AND on the wallet currency.
    • Auto-offramp requires canOfframp on both.
  • The credential currency must resolve to a supported currency row. An unknown code returns 404 not_found.
The set of currencies that support canOnramp / canOfframp is fixed by GlobalStack. If your wallet’s currency isn’t eligible for a given direction, cross-currency provisioning will fail — reach out to support to confirm coverage.

Deposit lifecycle

A cross-currency deposit tells you twice: once when the money arrives, and again as the conversion moves. The arrival event waits for the FX quote, so it can tell you what the deposit is worth in your wallet’s currency — the number you actually care about.

What deposit.received carries

The event body is the transaction resource — the same shape as GET /v1/transactions/{transactionId} — with source_* in the credential’s currency and destination_* in your wallet’s currency:
The wallet, customer and credential blocks tell you which credential was funded without a second API call — useful when you hand out one virtual account per customer. They appear only on cross-currency deposit events.
destination_amount is the quoted amount, not the settled one. It reflects the rate at deposit time; the amount that actually lands is actual_destination_amount on conversion.success. Reconcile against the conversion, not the deposit.
A cross-currency deposit never reaches a terminal deposit.* state. It stays at received for its whole life, and the conversion.* topics carry the outcome — do not wait for deposit.confirmed or deposit.failed on this path. Subscribe to both the deposit and conversion categories to see the full lifecycle.

Held deposits

If an arriving deposit breaches the customer’s rolling money-in limit, you get deposit.held instead, with metadata.hold_reason set to tier_limit and a null destination_amount — no conversion is quoted while the deposit is under review. When GlobalStack releases it, the conversion runs at the then-current rate and you receive deposit.received carrying the quoted amount, followed by the usual conversion.* sequence.

Same-currency credentials

Same-currency credentials keep the original lifecycle: deposit.received on arrival, deposit.held if a tier gate applies, then deposit.confirmed when the credit settles (or deposit.failed if it does not). Their payloads do not carry the wallet, customer and credential blocks, and their destination_amount equals source_amount — there is no conversion.

Fees

Auto-conversion fees follow the FX conversion contract: the destination amount is net of fees, and the fee breakdown is on the conversion.* webhook payloads. See failure reasons for the codes surfaced on a failed conversion.

Recovery on failure

If conversion.failed (or conversion.returned) fires, funds stay on the credential’s own balance — no auto-retry (FX failures are typically structural, not transient). Contact GlobalStack support to drain the parked funds; ops will run a fresh conversion at the then-current rate. Once the drain lands, the wallet balance is credited and the credential balance clears.
There is no merchant-facing “retry” or “refund” endpoint in v1. Recovery goes through GlobalStack support.

When to use auto-conversion

Reach for auto-conversion when your payers want to pay in a familiar local currency but your treasury runs in a different one — the classic example is accepting NGN bank deposits into a USDC treasury without a manual conversion step per deposit. If your payers already hold funds in the same currency as your wallet, stick with same-currency credentials: they credit the wallet directly with no FX exposure.