> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.walletstech.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.walletstech.com/_mcp/server.

# Quote a buy

POST https://api-demo.walletstech.com/order
Content-Type: application/json

Prices a purchase of `assetId` and opens the order as a quote. **Nothing is bought here** — the order stays `open` until you accept it with `/trade/approve`.

Give **exactly one** leg and the other is priced for you:

- `fiatAmount` — "spend this much", and the crypto you receive is derived.
- `cryptoAmount` — "buy this much", and the fiat you pay is derived.

Sending both, or neither, is a `400`.

The quote is indicative and short-lived. It lapses at `result.quote.expiresAt` — roughly a minute — and approving it after that is a `409`. **The price that binds is the one confirmed at approval**, not the one returned here, so show the user the approval price before treating the order as done.

Rounding always runs in the user's disfavour on the fiat leg and downwards on the crypto leg, so a rounded quote can never be filled short.

Every amount and price in the response is shown to **at most 6 decimal places**, cut rather than rounded, so a figure you display is never larger than the one that settles.

Reference: https://docs.walletstech.com/api-reference/trading/quote-buy

## Authentication

- `Authorization` header (bearer token, required) — A 15-minute token from `/auth`. Required on every endpoint except `/auth`.

## Servers

- `https://api-demo.walletstech.com` (Sandbox. Develop and test here. Requires its own credentials., default)
- `https://api.walletstech.com` (Production — real funds, and transfers that cannot be reversed. Requires its own credentials.)

## Request

### Headers

- `X-Request-Id` (string, optional) — Correlation id. Generated if omitted, echoed on every response, and written to the audit log. **`/send` is the exception — there it is required, and it doubles as the idempotency key.**
- `X-USER-ID` (string, optional) — Optional. When present it **overrides** any `userId` in the body.

### Body (application/json)

This endpoint expects an object.

- `userId` (string, required) — 24-character hex id, returned by `/create`.
- `assetId` (enum, required) — Primary asset selector. An all-digit string (`"21"`) is accepted and normalised to an integer. - `1` — BITCOIN BTC (native, 8 decimals) - `2` — ETHEREUM ETH (native, 18 decimals) - `21` — ETHEREUM USDT (ERC20, 6 decimals) - `22` — ETHEREUM USDC (ERC20, 6 decimals) - `3` — BSC BNB (native, 18 decimals) - `31` — BSC USDT (BEP20, 18 decimals) - `32` — BSC USDC (BEP20, 18 decimals) - `4` — TRON TRX (native, 6 decimals) - `41` — TRON USDT (TRC20, 6 decimals) - `42` — TRON USDC (TRC20, 6 decimals) — not on every endpoint - `5` — POLYGON POL (native, 18 decimals) - `51` — POLYGON USDT (ERC20, 6 decimals) — not on every endpoint - `52` — POLYGON USDC (ERC20, 6 decimals) - `6` — SOLANA SOL (native, 9 decimals) - `61` — SOLANA USDT (SPL, 6 decimals) — not on every endpoint - `62` — SOLANA USDC (SPL, 6 decimals)
  - Allowed values: `1`, `2`, `21`, `22`, `3`, `31`, `32`, `4`, `41`, `42`, `5`, `51`, `52`, `6`, `61`, `62`
- `fiat` (enum, optional) — Fiat currency the trade is priced in. Defaults to `USD` when omitted.
  - Allowed values: `USD`, `EUR`, `GBP`, `CAD`, `AUD`, `SEK`, `DKK`, `PLN`, `BRL`, `AED`
- `fiatAmount` (string, optional) — How much fiat to spend. Mutually exclusive with `cryptoAmount`.
- `cryptoAmount` (string, optional) — How much of the asset to buy. Mutually exclusive with `fiatAmount`.

## Response

### 200

OK — the quote is open.

- `result` (object, required) — One trade, whichever side it is. `cryptoAmount`, `fiatAmount` and `price` are the **best known** figures: what executed if it has, else what you approved, else what was quoted. `quote` always holds the original quoted leg, so you can show both. Every amount and price is cut — not rounded — to at most 6 decimal places, with trailing zeros trimmed, so `100.00` is returned as `100`.
  - `tradeId` (string, required) — 24-character hex id of a trade, returned by `/order` and `/sell`.
  - `side` (enum, required)
    - Allowed values: `buy`, `sell`
  - `status` (enum, required) — Where the trade is in its lifecycle. `open` is the only status you can approve or cancel. `executing` is in flight — poll, never approve again. `completed`, `failed`, `expired` and `cancelled` are terminal.
    - Allowed values: `open`, `approved`, `executing`, `completed`, `failed`, `expired`, `cancelled`
  - `assetId` (enum, required) — Primary asset selector. An all-digit string (`"21"`) is accepted and normalised to an integer. - `1` — BITCOIN BTC (native, 8 decimals) - `2` — ETHEREUM ETH (native, 18 decimals) - `21` — ETHEREUM USDT (ERC20, 6 decimals) - `22` — ETHEREUM USDC (ERC20, 6 decimals) - `3` — BSC BNB (native, 18 decimals) - `31` — BSC USDT (BEP20, 18 decimals) - `32` — BSC USDC (BEP20, 18 decimals) - `4` — TRON TRX (native, 6 decimals) - `41` — TRON USDT (TRC20, 6 decimals) - `42` — TRON USDC (TRC20, 6 decimals) — not on every endpoint - `5` — POLYGON POL (native, 18 decimals) - `51` — POLYGON USDT (ERC20, 6 decimals) — not on every endpoint - `52` — POLYGON USDC (ERC20, 6 decimals) - `6` — SOLANA SOL (native, 9 decimals) - `61` — SOLANA USDT (SPL, 6 decimals) — not on every endpoint - `62` — SOLANA USDC (SPL, 6 decimals)
    - Allowed values: `1`, `2`, `21`, `22`, `3`, `31`, `32`, `4`, `41`, `42`, `5`, `51`, `52`, `6`, `61`, `62`
  - `symbol` (string, required) — Ticker of the traded asset, e.g. `BTC`.
  - `fiat` (enum, required) — Fiat currency the trade is priced in. Defaults to `USD` when omitted.
    - Allowed values: `USD`, `EUR`, `GBP`, `CAD`, `AUD`, `SEK`, `DKK`, `PLN`, `BRL`, `AED`
  - `cryptoAmount` (string, required, nullable) — Decimal string. `null` only if the stored amount could not be read.
  - `fiatAmount` (string, required, nullable) — Decimal string. `null` only if the stored amount could not be read.
  - `price` (string, required) — Unit price of one whole coin, in `fiat`.
  - `quote` (object, required) — The original quote, unchanged by approval or settlement.
    - `cryptoAmount` (string, required, nullable)
    - `fiatAmount` (string, required, nullable)
    - `price` (string, required)
    - `expiresAt` (datetime, required) — After this instant the quote has lapsed and approving it is a `409`.
  - `createdAt` (datetime, required)
  - `approvedAt` (datetime, required, nullable) — `null` until the quote is approved.
  - `completedAt` (datetime, required, nullable) — `null` until the trade reaches a terminal status.
  - `reference` (string, optional) — Present only when the fill carried one.
  - `failureReason` (string, optional) — Present only on a `failed` trade.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

## Errors

### 400 Bad Request Error

Bad Request

- `message` (string, required) — Safe, client-facing message. Internal detail never leaks here.
- `error` (string, required) — The HTTP status code, as a string.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

### 401 Unauthorized Error

Unauthorized — no bearer token, or one that does not verify. Get a fresh access token from `/refresh` (or `/auth`) and replay the request.

- `message` (string, required) — Safe, client-facing message. Internal detail never leaks here.
- `error` (string, required) — The HTTP status code, as a string.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

### 403 Forbidden Error

Forbidden — that asset is not enabled for your api client. Permanent until your operator enables it: do not retry.

- `message` (string, required) — Safe, client-facing message. Internal detail never leaks here.
- `error` (string, required) — The HTTP status code, as a string.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

### 404 Not Found Error

Not Found — no such user. Check the `userId`; retrying unchanged will not help.

- `message` (string, required) — Safe, client-facing message. Internal detail never leaks here.
- `error` (string, required) — The HTTP status code, as a string.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

### 502 Bad Gateway Error

Bad Gateway — no usable price for that asset right now. Nothing was quoted or traded. Transient: retry with backoff.

- `message` (string, required) — Safe, client-facing message. Internal detail never leaks here.
- `error` (string, required) — The HTTP status code, as a string.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

### 503 Service Unavailable Error

Service Unavailable — trading is not available for that asset right now. Do not retry in a tight loop; contact your operator if it persists.

- `message` (string, required) — Safe, client-facing message. Internal detail never leaks here.
- `error` (string, required) — The HTTP status code, as a string.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

### 504 Gateway Timeout Error

Gateway Timeout — pricing did not answer in time. Nothing was quoted; retry with backoff.

- `message` (string, required) — Safe, client-facing message. Internal detail never leaks here.
- `error` (string, required) — The HTTP status code, as a string.
- `requestId` (string, required) — Echo of the inbound `X-Request-Id`, or a generated one.

## Examples

### Buy BTC for a fixed amount of USD

**Request**

```json
{
  "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
  "assetId": 1,
  "fiat": "USD",
  "fiatAmount": "100.00"
}
```

**Response**

```json
{
  "result": {
    "tradeId": "6a1f0c2d3e4f5a6b7c8d9e0f",
    "side": "buy",
    "status": "open",
    "assetId": 1,
    "symbol": "BTC",
    "fiat": "USD",
    "cryptoAmount": "0.001546",
    "fiatAmount": "100",
    "price": "64665.47",
    "quote": {
      "cryptoAmount": "0.001546",
      "fiatAmount": "100",
      "price": "64665.47",
      "expiresAt": "2026-08-16T10:31:00.000Z"
    },
    "createdAt": "2026-08-16T10:30:00.000Z",
    "approvedAt": null,
    "completedAt": null
  },
  "requestId": "b7a1f0c2-3d4e-4a5b-9c6d-7e8f90a1b2c3"
}
```

**SDK Code**

```python Buy BTC for a fixed amount of USD
import requests

url = "https://api-demo.walletstech.com/order"

payload = {
    "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
    "assetId": 1,
    "fiat": "USD",
    "fiatAmount": "100.00"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Buy BTC for a fixed amount of USD
const url = 'https://api-demo.walletstech.com/order';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"userId":"60f7c2d3e4f5a6b7c8d9e0f1","assetId":1,"fiat":"USD","fiatAmount":"100.00"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Buy BTC for a fixed amount of USD
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api-demo.walletstech.com/order"

	payload := strings.NewReader("{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 1,\n  \"fiat\": \"USD\",\n  \"fiatAmount\": \"100.00\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Buy BTC for a fixed amount of USD
require 'uri'
require 'net/http'

url = URI("https://api-demo.walletstech.com/order")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 1,\n  \"fiat\": \"USD\",\n  \"fiatAmount\": \"100.00\"\n}"

response = http.request(request)
puts response.read_body
```

```java Buy BTC for a fixed amount of USD
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api-demo.walletstech.com/order")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 1,\n  \"fiat\": \"USD\",\n  \"fiatAmount\": \"100.00\"\n}")
  .asString();
```

```php Buy BTC for a fixed amount of USD
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api-demo.walletstech.com/order', [
  'body' => '{
  "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
  "assetId": 1,
  "fiat": "USD",
  "fiatAmount": "100.00"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Buy BTC for a fixed amount of USD
using RestSharp;

var client = new RestClient("https://api-demo.walletstech.com/order");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 1,\n  \"fiat\": \"USD\",\n  \"fiatAmount\": \"100.00\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Buy BTC for a fixed amount of USD
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
  "assetId": 1,
  "fiat": "USD",
  "fiatAmount": "100.00"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-demo.walletstech.com/order")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Buy a fixed amount of ETH

**Request**

```json
{
  "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
  "assetId": 2,
  "fiat": "EUR",
  "cryptoAmount": "0.5"
}
```

**Response**

```json
{
  "result": {
    "tradeId": "6a1f0c2d3e4f5a6b7c8d9e10",
    "side": "buy",
    "status": "open",
    "assetId": 2,
    "symbol": "ETH",
    "fiat": "EUR",
    "cryptoAmount": "0.5",
    "fiatAmount": "1284.61",
    "price": "2569.22",
    "quote": {
      "cryptoAmount": "0.5",
      "fiatAmount": "1284.61",
      "price": "2569.22",
      "expiresAt": "2026-08-16T10:31:00.000Z"
    },
    "createdAt": "2026-08-16T10:30:00.000Z",
    "approvedAt": null,
    "completedAt": null
  },
  "requestId": "b7a1f0c2-3d4e-4a5b-9c6d-7e8f90a1b2c3"
}
```

**SDK Code**

```python Buy a fixed amount of ETH
import requests

url = "https://api-demo.walletstech.com/order"

payload = {
    "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
    "assetId": 2,
    "fiat": "EUR",
    "cryptoAmount": "0.5"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Buy a fixed amount of ETH
const url = 'https://api-demo.walletstech.com/order';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"userId":"60f7c2d3e4f5a6b7c8d9e0f1","assetId":2,"fiat":"EUR","cryptoAmount":"0.5"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Buy a fixed amount of ETH
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api-demo.walletstech.com/order"

	payload := strings.NewReader("{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 2,\n  \"fiat\": \"EUR\",\n  \"cryptoAmount\": \"0.5\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Buy a fixed amount of ETH
require 'uri'
require 'net/http'

url = URI("https://api-demo.walletstech.com/order")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 2,\n  \"fiat\": \"EUR\",\n  \"cryptoAmount\": \"0.5\"\n}"

response = http.request(request)
puts response.read_body
```

```java Buy a fixed amount of ETH
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api-demo.walletstech.com/order")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 2,\n  \"fiat\": \"EUR\",\n  \"cryptoAmount\": \"0.5\"\n}")
  .asString();
```

```php Buy a fixed amount of ETH
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api-demo.walletstech.com/order', [
  'body' => '{
  "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
  "assetId": 2,
  "fiat": "EUR",
  "cryptoAmount": "0.5"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Buy a fixed amount of ETH
using RestSharp;

var client = new RestClient("https://api-demo.walletstech.com/order");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"userId\": \"60f7c2d3e4f5a6b7c8d9e0f1\",\n  \"assetId\": 2,\n  \"fiat\": \"EUR\",\n  \"cryptoAmount\": \"0.5\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Buy a fixed amount of ETH
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "userId": "60f7c2d3e4f5a6b7c8d9e0f1",
  "assetId": 2,
  "fiat": "EUR",
  "cryptoAmount": "0.5"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api-demo.walletstech.com/order")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```