This page is written so that an AI coding agent (or a human engineer using one) can build a production-quality Vortex integration in any language or stack. It also explains how to keep these docs themselves useful when retrieved into a coding agent's context.
When you point an AI coding agent at Vortex:
@vortexfi/sdk you are mirroring. The SDK's behavior is the reference implementation; if your integration disagrees with it, the SDK wins.chainId, verifyingContract, to, value, data, and ramp/phase identifiers must match what your application requested for the current rampId.| Your runtime | Path |
|---|---|
| Node.js (server-side, trusted) | Use @vortexfi/sdk. |
| Python (server-side, trusted) | Use vortex-sdk-python. |
| Browser, mobile, WebView | Use the Vortex Widget. |
| Anything else (Go, Rust, Elixir, Java, Ruby, PHP, .NET, Deno, edge runtimes, …) | Reimplement the SDK behavior against the raw API as described in Section D below. |
Do not call the raw ramp API from a browser. Browsers cannot safely hold sk_* keys or ephemeral secrets. Use the Widget or proxy through a trusted backend.
vortex-sdk-python)vortex-sdk-python is a process-bridge wrapper around the native Node.js SDK. It spawns the Node SDK and exposes a Python-friendly surface, so the behavior, custody model, and supported flows match @vortexfi/sdk exactly.
pip install vortex-sdk-python
from vortex_sdk import VortexSdk, RampDirection, FiatToken, EvmToken, Networks
sdk = VortexSdk(
api_base_url="https://api.vortexfinance.co",
public_key="pk_live_...",
secret_key="sk_live_...",
store_ephemeral_keys=True,
)
quote = sdk.create_quote(
ramp_type=RampDirection.BUY,
from_="pix",
to=Networks.Polygon,
input_amount="150",
input_currency=FiatToken.BRL,
output_currency=EvmToken.USDC,
)
ramp = sdk.register_ramp(quote, destination_address="0x...", tax_id="12345678900")
print(ramp.deposit_qr_code)
sdk.start_ramp(ramp.id)
Operational notes specific to the Python wrapper:
ephemerals_{rampId}.json is written unencrypted in the working directory.VortexSdk(...) instance for the lifetime of your service.Refer to the PyPI page for the latest version, function names, and breaking-change notes: https://pypi.org/project/vortex-sdk-python.
If your stack is neither Node nor Python, build a thin client that mirrors what @vortexfi/sdk does. The contract has six parts; implement them in this order.
Your client needs:
apiBaseUrl — https://api.vortexfinance.co (prod) or https://api-sandbox.vortexfinance.co (sandbox).publicKey — pk_live_* / pk_test_*. Sent in request bodies as apiKey for attribution.secretKey — sk_live_* / sk_test_*. Sent as X-API-Key header. Server-side only.Reject startup if a sk_live_* key is detected in a browser-shaped runtime.
POST /v1/quotes
Request body: see 6. Quotes And Pricing. Treat monetary fields as strings end-to-end; never parse them into floats. Store id, expiresAt, fee, and the resolved route. Surface expiry to the caller as a domain error.
POST /v1/ramp/register
X-API-Key: sk_*
Before calling register, generate per-chain ephemeral accounts for the chains involved in the route:
Send only the public addresses in the register request. Persist the secret keys to your secure store, keyed by the not-yet-issued ramp; once the response returns a rampId, rekey the store entry. Never log the secrets.
The response contains:
rampIdunsignedTxs — an ordered list of transactions to signEach unsigned transaction declares its network, signer address, transaction format (evm-transaction, evm-typed-data, substrate-extrinsic, stellar-transaction), and the payload bytes or fields to sign.
For each unsigned transaction:
tx.signer equals an ephemeral address you control → sign with the matching ephemeral key.tx.signer equals the user's wallet address → return the payload to the user's wallet for signing (EIP-712 typed data, EVM transaction, or Substrate extrinsic). Never sign user-controlled transactions on the server.chainId matches the network the SDK config declared.to / verifyingContract is one of the Vortex-published contracts for that network.value, asset, and amount match the current ramp quote.NUMBER_OF_PRESIGNED_TXS = 5).maxPriorityFeePerGas and maxFeePerGas returned by the node by 3× before signing.POST /v1/ramp/update
X-API-Key: sk_*
Body includes the rampId, the transaction reference, and either the signed payload or the broadcast transaction hash. The exact shape is defined in the OpenAPI file; do not guess fields.
depositQrCode (PIX). Show it; wait for the user to pay. Then call POST /v1/ramp/start.POST /v1/ramp/start
X-API-Key: sk_*
POST /v1/webhook against quoteId or sessionId. Verify every delivery using RSA-PSS / SHA-256 against GET /v1/public-key. See 7. Webhooks.GET /v1/ramp/{id} for live user-facing UI.GET /v1/ramp/{id}/errors for support.These are not optional. The SDK handles them for you; a custom client must implement them explicitly.
rampId. Keep them until the ramp is COMPLETE or FAILED and any recovery window has passed. Never transmit secrets to Vortex, support, logs, or analytics. See 5. Ephemeral Key Custody.register, update, and start with idempotency keys at your layer. Retries must not produce duplicate ramps.register. Create a fresh quote and re-prompt the user.X-Vortex-Timestamp is outside an acceptable window (300s is a reasonable default).quoteId, rampId, sessionId, partner order ID, user identifier, webhook IDs, and a reference to the ephemeral-key backup. Without these you cannot support users or reconcile.BigDecimal, decimal.Decimal).pk_test_* / sk_test_* against api-sandbox.vortexfinance.co. Never mix test keys with the live base URL or vice versa."Euro onramp handler not implemented yet").Mirror those gaps deliberately. If your integration adds behavior the SDK lacks (encryption at rest, backup rotation, idempotency keys, retries), document it for your operators.
Before going live without the SDK:
sk_* keys never reach a browser.POST /v1/ramp/update called with the exact transaction reference returned by register.rampId and ephemeral backup.See also 11. Production Checklist.