Getting started 

# Quickstart

Make your first cross-border payment in five minutes. You'll authenticate, lock a rate with a quote, commit it as an order, and track it to completion — all over stable JSON.

You'll need workspace credentials. Don't have them yet? Contact [integrations@virtuabroker.com](mailto:integrations@virtuabroker.com). Test everything against `https://api-stage.virtuabroker.com` first.

## 1 · Authenticate

Exchange your workspace credentials for a short-lived OAuth 2.0 bearer token using the `password` grant, then send it on every request. See the [Authentication guide](authentication.html) for the full flow.

get a token 

```bash
export VB_TOKEN=$(curl -s https://auth2.virtuabroker.com/realms/cryptobot/protocol/openid-connect/token \
  -d "grant_type=password" \
  -d "client_id=$VB_CLIENT_ID" \
  -d "username=$VB_USERNAME" \
  -d "password=$VB_PASSWORD" | jq -r .access_token)
```

```javascript
const res = await fetch("https://auth2.virtuabroker.com/realms/cryptobot/protocol/openid-connect/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "password",
    client_id: process.env.VB_CLIENT_ID,
    username: process.env.VB_USERNAME,
    password: process.env.VB_PASSWORD,
  }),
});
const { access_token } = await res.json();
```

```python
import os, requests

r = requests.post("https://auth2.virtuabroker.com/realms/cryptobot/protocol/openid-connect/token", data={
    "grant_type": "password",
    "client_id": os.environ["VB_CLIENT_ID"],
    "username": os.environ["VB_USERNAME"],
    "password": os.environ["VB_PASSWORD"],
})
access_token = r.json()["access_token"]
```

## 2 · Create a quote

A quote locks an exchange rate and fees for a currency pair. It's workspace-scoped and needs no customer identity. Quotes expire after a short window — create the order promptly.

POST /v1/quotes 

```bash
curl https://api.virtuabroker.com/v1/quotes \
  -H "Authorization: Bearer $VB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "originCurrency": "EUR",
    "destinationCurrency": "BRL",
    "originAmount": 1000
  }'
```

```javascript
const res = await fetch("https://api.virtuabroker.com/v1/quotes", {
  method: "POST",
  headers: { Authorization: `Bearer ${access_token}`, "Content-Type": "application/json" },
  body: JSON.stringify({ originCurrency: "EUR", destinationCurrency: "BRL", originAmount: 1000 }),
});
const quote = await res.json();
```

```python
quote = requests.post("https://api.virtuabroker.com/v1/quotes",
    headers={"Authorization": f"Bearer {access_token}"},
    json={"originCurrency": "EUR", "destinationCurrency": "BRL", "originAmount": 1000},
).json()
```

200 · response

```
{
  "quoteId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "originCurrency": "EUR",
  "originAmount": 1000,
  "destinationCurrency": "BRL",
  "destinationAmount": 6094.01,
  "pair": "EURBRL",
  "price": 6.094,
  "conversionRate": 6.1234,
  "fee": 4.8,
  "feeCurrency": "EUR",
  "expireAt": 1694291200
}
```

Amounts are JSON numbers, never strings. `quoteId` is a UUID, `conversionRate` is the pair rate, `price` is the effective all-in rate, and `expireAt` is a unix timestamp in seconds — create the order before it passes.

## 3 · Create an order

Commit the quote to a payout destination. The fields inside `destinationTransferData` depend on the corridor's rail — for BRL that's a PIX key. Discover the exact fields per currency with `GET /v1/currencies/{currency}/destination-schema`. Paying out over `SEPA`, `ACH_US` or `GBP_BANK_TRANSFER`? The beneficiary's `city` and `postalCode` are required — send them in either `destinationTransferData` or `destinationUserData`.

POST /v1/orders 

```bash
curl https://api.virtuabroker.com/v1/orders \
  -H "Authorization: Bearer $VB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "quoteId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
    "destinationTransferData": { "pixKey": "recipient@example.com", "holderName": "ACME LTDA" },
    "externalReference": "invoice-2043"
  }'
```

```javascript
const res = await fetch("https://api.virtuabroker.com/v1/orders", {
  method: "POST",
  headers: { Authorization: `Bearer ${access_token}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    quoteId: "d290f1ee-6c54-4b01-90e6-d701748f0851",
    destinationTransferData: { pixKey: "recipient@example.com", holderName: "ACME LTDA" },
    externalReference: "invoice-2043",
  }),
});
const order = await res.json();
```

```python
order = requests.post("https://api.virtuabroker.com/v1/orders",
    headers={"Authorization": f"Bearer {access_token}"},
    json={
        "quoteId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
        "destinationTransferData": {"pixKey": "recipient@example.com", "holderName": "ACME LTDA"},
        "externalReference": "invoice-2043",
    },
).json()
```

**Send an `Idempotency-Key` header on this call** so a timeout retry is safe: the same key with the same payload returns the original order. Without a key, reconcile with `GET /v1/orders` before resending; see [Retrying a write](conventions.html#idempotency).

## 4 · Track it to completion

An order moves through observable states. Poll `GET /v1/orders/{id}`, or — recommended — subscribe to [webhooks](webhooks.html) and react to `order_status_updated`, checking `data.status` for `Success` or `Failed`.

WaitingForFundsToExchange Exchanging Success Failed 

GET /v1/orders/{orderId} 

```
curl https://api.virtuabroker.com/v1/orders/A7K9DP2X4Q1M \
  -H "Authorization: Bearer $VB_TOKEN"
```

## Next steps

[Authentication →Token lifecycle, scopes, and refresh.](authentication.html) [Webhooks →Signature verification and safe retries.](webhooks.html) [API reference →Every endpoint, schema, and example.](reference.html)
