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

# Create a trade breakdown

POST https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns
Content-Type: application/json

Create a trade breakdown.

**Credential:** Customer session

**Before you call**

- A customer session for the same partner, integration, customer, wallet and chain.
- An active saved account matching the catalog payment method.
- A registered customer wallet and supported chain.
- Set an Idempotency-Key and reuse it for an identical retry.

Creates a priced, time-limited breakdown for the customer to review and sign. Send the selected offer's `breakdownInput` unchanged, including its normalized `amount`, `paymentMethodId` and `savedPaymentMethodId`. For a new FIAT search, `amount` is a USDT quantity: keep it rather than substituting the original fiat input. Selections issued earlier with a FIAT amount keep their original meaning: a spending cap on a BUY, or a receiving floor on a SELL.

If you change the selection, the call returns `409 CONFLICT`. A selection that no longer exists can return `404`. Sinbad rechecks the current price, fees, inventory and eligibility. Show the returned `tradeDetails` to the customer before they sign.

One open trade per side. A breakdown holds the customer's open trade on its side, for your partner and that customer, without creating a funded trade. A request with a new `Idempotency-Key` replaces the customer's earlier breakdown on that side if no escrow transaction was submitted for it, and the response includes a fresh `escrowTransaction`. Sign from the latest response. Repeating the key of a replaced breakdown returns `409 CONFLICT`. If the earlier breakdown was submitted, funded or is under review, the request fails with `409 CONFLICT` and `details.reason: ACTIVE_TRADE_EXISTS`. Funding carries the customer's open trade into the funded trade. A final trade status or a customer-opened dispute releases it. A merchant-opened dispute does not.

Replacing a breakdown does not cancel an escrow transaction that the wallet already sent. That transaction can still fund escrow until its original signing deadline, and it creates its own trade with its original pricing. Keep reporting the hashes of transactions you already sent through `POST /v1/transactions`. Do not request a replacement while a wallet send is pending or its outcome is unknown, including before you have reported its hash.

The response includes `escrowTransaction` and the current `approvalRequired` and `approval` values. Use `to`, `data`, `value`, `chainId` and `from` unchanged. Required approvals must succeed before the escrow transaction, and a wallet that supports batching can run them in order in one batch. Preparing needs no gas balance. With an ordinary signed transaction, the customer's wallet pays gas in POL. Partners that execute through smart accounts arrange signing, execution and any gas sponsorship themselves.

Submit the signed transaction, or report the included blockchain transaction hash, with the `preparationId` through `POST /v1/transactions`. A trade exists only after an escrow transaction is confirmed successfully, and it starts as `CREATED`. After an uncertain send or an expired signing window, track the breakdown. Do not start another transaction while the outcome is unknown.

Offer searches and breakdown creation share 60 requests per minute for each customer and integration. Requests that pass validation count, including idempotent replays and requests with no key. A `429` response includes `Retry-After`. A BUY whose merchant no longer has enough liquidity returns `409 INSUFFICIENT_LIQUIDITY`. A SELL with too little token balance returns `400 INSUFFICIENT_BALANCE` and can leave the customer's open SELL held: top up, then repeat the identical body and key while the breakdown is live. An identical retry returns the original breakdown and deadline.

Sinbad keeps unused offer selections for 30 days, and consumed selections and breakdown idempotency keys for one day. Request a fresh offer after that. To correct an escrow hash that was reported wrongly, see `POST /v1/transactions`.



> Confirm with Sinbad that this endpoint is enabled in your environment.

**Errors**

| Status | Code | What to do |
| --- | --- | --- |
| 400 | `VALIDATION_ERROR` | Correct the fields reported in details before retrying. |
| 401 | `UNAUTHENTICATED` | Create a new customer session or use a valid server credential. |
| 403 | `FORBIDDEN` | Check credential ownership, integration and the supplied Origin. |
| 404 | `NOT_FOUND` | Check the resource ID. A resource that belongs to someone else also returns 404. |
| 409 | `CONFLICT` | Read the current state again before you prepare or retry. |
| 429 | `RATE_LIMITED` | Wait for Retry-After before retrying. |
| 503 | `UPSTREAM_ERROR` | Retry with backoff; preserve the same idempotency key for a repeated mutation. |
| 400 | `INSUFFICIENT_BALANCE` | The SELL token balance is too low. Top up, then repeat the identical request with the same key while the breakdown is live. The customer's open SELL can already be held. |
| 409 | `INSUFFICIENT_LIQUIDITY` | The BUY merchant no longer has enough liquidity. Recover any transaction you already submitted before you ask for a new offer. |
| 409 | `CONFLICT` | details.reason ACTIVE_TRADE_EXISTS means the customer already has a trade, or a breakdown with a submitted escrow transaction, on that side. Show the existing trade, or wait for it to finish. A breakdown with no submitted escrow transaction does not cause this: a new idempotency key replaces it. |

Reference: https://docs.getsinbad.com/api-reference/offers-and-breakdowns/create-trade-breakdown

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Request

### Headers

- `Idempotency-Key` (string, required)

### Body (application/json)

This endpoint expects an offers_quotes__CreateBreakdown.

- `side` (enum, required)
  - Allowed values: `BUY`, `SELL`
- `tokenSymbol` (enum, required)
  - Allowed values: `USDT`
- `fiatCurrencyId` (string, required)
- `paymentMethodId` (string, required) — Required catalog method owned by the customer through an active saved account.
- `savedPaymentMethodId` (string, required)
- `amount` (OffersQuotesCreateBreakdownAmount, required) — Copy the selected breakdownInput amount unchanged. New searches use USDT, including when discovery input was FIAT. Older issued FIAT selections retain their original final-fiat semantics.
- `offerId` (string, required)
- `fingerprint` (string, required) — Opaque signed preview fingerprint
- `displayCalculationMode` (enum, optional, default: DUMMY) — Card/Sheet display only. DUMMY uses a $10 USD example; REAL uses the actual requested or suggested amount. Execution always uses actual pricing. Preserve in issued breakdownInput.
  - Allowed values: `DUMMY`, `REAL`
- `scheduled_at` (string, optional) — Optional ISO 8601 date-time, formatted YYYY-MM-DDTHH:mm[:ss[.SSS]][Z|±HH:MM]. Fractional seconds accept at most 3 digits, so truncate 6-digit values such as .190505 to milliseconds. An offset-free value uses timezone, or UTC if timezone is omitted. A value with Z or an explicit offset keeps that offset and ignores timezone. Normalized to UTC in breakdownInput. Filters merchant hours only; does not delay execution. Malformed, invalid or ambiguous local times (such as during a daylight saving change) are rejected with VALIDATION_ERROR.
- `timezone` (string, optional) — Optional IANA timezone name such as Asia/Karachi. Used only for an offset-free scheduled_at and ignored when scheduled_at has Z or an offset. Merchant hours use the merchant timezone at the scheduled instant.
- `minRatingPercent` (double, optional) — Optional minimum merchant rating; unrated merchants do not match.
- `minTradeCount` (integer, optional) — Optional minimum recorded merchant trade count.
- `ignoreMerchantOnline` (boolean, optional, default: false) — Include offline merchants. Preserve this value when creating a breakdown.
- `ignoreTradingHours` (boolean, optional, default: false) — Skip only supplied scheduled-hours filtering, including for alternatives. Preserve this value when creating a breakdown.

## Response

### 201

Financial breakdown, prepared escrow call, approval state and current submission status.

- `merchant` (offers_quotes__MerchantDisplay, required) — Offer values are current observations; breakdown POST, GET and retries return the same creation snapshot.
- `breakdownId` (string, required)
- `createdAt` (datetime, required)
- `expiresAt` (datetime, required) — Fresh breakdown creation plus 300 seconds.
- `serverTime` (datetime, required)
- `side` (enum, required)
  - Allowed values: `BUY`, `SELL`
- `status` (enum, required) — Confirmed escrow outcome, independent of optional transaction tracking.
  - Allowed values: `AWAITING_FUNDING`, `CONFIRMED`, `EXPIRED`, `REVIEW_REQUIRED`
- `tradeId` (string, required, nullable)
- `tradeDetails` (OffersQuotesTradeBreakdownTradeDetails, required) — Send exactly one of: `YouPay`, or `YouReceive`.
- `merchantRateDetails` (OffersQuotesTradeBreakdownMerchantRateDetails, required)
- `fiatCurrency` (offers_quotes__FiatCurrency, required)
- `paymentMethod` (offers_quotes__SafePaymentMethod, required)
- `submission` (OffersQuotesTradeBreakdownSubmission, required, nullable)
- `escrowTransaction` (OffersQuotesTradeBreakdownEscrowTransaction, optional) — Use this escrow call after approvals confirm. Nonce/gas/fees are populated by the signer, not pinned before approval.
- `approvalRequired` (boolean, optional) — Allowance when the breakdown was created. Sinbad rechecks it when you submit.
- `approval` (OffersQuotesTradeBreakdownApproval, optional)

## Errors

### 400 Bad Request Error

The request is invalid.

- `error` (V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError, required)

### 401 Unauthorized Error

Authentication is required.

- `error` (V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError, required)

### 403 Forbidden Error

You do not have permission to perform this action.

- `error` (V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError, required)

### 404 Not Found Error

The requested resource was not found.

- `error` (V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError, required)

### 409 Conflict Error

The request conflicts with the current state of the resource.

- `error` (V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError, required)

### 429 Too Many Requests Error

Too many requests. Please try again later.

- `error` (V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError, required)

### 503 Service Unavailable Error

Service temporarily unavailable.

- `error` (V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError, required)

## Types

### OffersQuotesCreateBreakdownAmount

Copy the selected breakdownInput amount unchanged. New searches use USDT, including when discovery input was FIAT. Older issued FIAT selections retain their original final-fiat semantics.

- `mode` (enum, required)
  - Allowed values: `FIAT`, `USDT`
- `value` (string, required) — Exact nonnegative decimal string. USDT has at most 6 places; fiat uses currency decimals.

### offers_quotes__MerchantDisplay

Offer values are current observations; breakdown POST, GET and retries return the same creation snapshot.

- `fullName` (string, required, nullable)
- `avatarUrl` (string, required, nullable)
- `username` (string, required, nullable)
- `ratingPercent` (double, required, nullable) — Null when no valid rating is available.
- `tradeCount` (integer, required)
- `isSuperMerchant` (boolean, required)
- `experienceYears` (integer, required) — Native display parity; floor of experienceDays divided by 365 with a minimum and fallback of one.

### OffersQuotesTradeBreakdownTradeDetails

Send exactly one of: `YouPay`, or `YouReceive`.

- `Amount` (offers_quotes__DisplayValue, required)
- `MerchantRate` (offers_quotes__DisplayValue, required)
- `Subtotal` (offers_quotes__DisplayValue, required)
- `ServiceFee` (offers_quotes__DisplayValue, required)
- `YouPay` (offers_quotes__DisplayValue, optional)
- `YouReceive` (offers_quotes__DisplayValue, optional)

### OffersQuotesTradeBreakdownMerchantRateDetails

- `MarketRate` (offers_quotes__DisplayValue, required)
- `MerchantMargin` (offers_quotes__DisplayValue, required)
- `MerchantRate` (offers_quotes__DisplayValue, required)

### offers_quotes__FiatCurrency

- `id` (string, required)
- `code` (string, required)
- `name` (string, required)
- `symbol` (string, required)
- `decimals` (integer, required)

### offers_quotes__SafePaymentMethod

- `paymentMethodId` (string, required)
- `displayLabel` (string, required) — Catalog-provided name, never a private account label.
- `isActive` (boolean, required)
- `_logoURL` (string, required)
- `id` (string, optional) — Customer saved account ID; omitted for catalog summaries.

### OffersQuotesTradeBreakdownSubmission

- `status` (string, required)
- `transactionHash` (string, required)
- `purpose` (string, required)
- `confirmations` (integer, required)
- `requiredConfirmations` (integer, required)

### OffersQuotesTradeBreakdownEscrowTransaction

Use this escrow call after approvals confirm. Nonce/gas/fees are populated by the signer, not pinned before approval.

- OffersQuotesTradeBreakdownEscrowTransaction0
- map from string to any

### OffersQuotesTradeBreakdownApproval

- OffersQuotesTradeBreakdownApproval0
- map from string to any

### V1TradeBreakdownsPostResponsesContentApplicationJsonSchemaError

- `code` (string, required)
- `numericId` (integer, required)
- `message` (string, required)
- `requestId` (string, optional)
- `details` (map from string to any, optional)

### offers_quotes__DisplayValue

- `value` (double, required) — Display only; exact pricing strings govern execution.
- `type` (enum, required)
  - Allowed values: `fiat`, `crypto`, `percentage`

### OffersQuotesTradeBreakdownEscrowTransaction0

- `preparationId` (string, required)
- `purpose` (enum, required)
  - Allowed values: `approval`, `approvalReset`, `createEscrow`, `markPaid`, `release`, `cancelPrePaid`, `openDispute`, `mutualResolveDispute`
- `chainId` (integer, required)
- `from` (string, required)
- `to` (string, required)
- `data` (string, required)
- `value` (enum, required)
  - Allowed values: `0`
- `expiresAt` (datetime, required, nullable) — Null for lifecycle actions; checkout calls retain their fixed funding deadline.

### OffersQuotesTradeBreakdownApproval0

- `required` (boolean, required)
- `tokenAddress` (string, required)
- `spender` (string, required)
- `requiredAmount` (string, required) — Required allowance in atomic token units (USDT has 6 decimals).
- `allowance` (string, required) — Observed allowance in atomic token units.

## Examples

**Request**

```json
{
  "side": "BUY",
  "tokenSymbol": "USDT",
  "fiatCurrencyId": "usd",
  "paymentMethodId": "bank_transfer",
  "savedPaymentMethodId": "account_demo",
  "amount": {
    "mode": "USDT",
    "value": "100"
  },
  "offerId": "offer_demo",
  "fingerprint": "preview_fingerprint_from_offer_search"
}
```

**Response**

```json
{
  "merchant": {
    "fullName": "Demo merchant",
    "avatarUrl": "https://example.com/avatar.png",
    "username": "demo_merchant",
    "ratingPercent": 98,
    "tradeCount": 1240,
    "isSuperMerchant": true,
    "experienceYears": 3
  },
  "breakdownId": "breakdown_demo",
  "createdAt": "2026-10-23T10:00:00.000Z",
  "expiresAt": "2026-10-23T10:05:00.000Z",
  "serverTime": "2026-10-23T10:00:00.000Z",
  "side": "BUY",
  "status": "AWAITING_FUNDING",
  "tradeId": null,
  "tradeDetails": {
    "Amount": {
      "value": 100,
      "type": "crypto"
    },
    "MerchantRate": {
      "value": 1,
      "type": "fiat"
    },
    "Subtotal": {
      "value": 100,
      "type": "fiat"
    },
    "ServiceFee": {
      "value": 0,
      "type": "fiat"
    },
    "YouPay": {
      "value": 100,
      "type": "fiat"
    }
  },
  "merchantRateDetails": {
    "MarketRate": {
      "value": 1,
      "type": "fiat"
    },
    "MerchantMargin": {
      "value": 0,
      "type": "percentage"
    },
    "MerchantRate": {
      "value": 1,
      "type": "fiat"
    }
  },
  "fiatCurrency": {
    "id": "usd",
    "code": "USD",
    "name": "US Dollar",
    "symbol": "$",
    "decimals": 2
  },
  "paymentMethod": {
    "paymentMethodId": "bank_transfer",
    "displayLabel": "Bank transfer",
    "isActive": true,
    "_logoURL": "",
    "id": "account_demo"
  },
  "submission": null,
  "escrowTransaction": {
    "chainId": 80002,
    "data": "0x96f5f7d4cd8bdc71c97deb8b806e60f4592418d63f87a7d064f8a848e1cac1012c43280ffdf1c2b36f2ea80f9cc1a9bb5aed70dbd50cba3db1f3d9e742e5687cb228970b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000222222222222222222222222222222222222222200000000000000000000000019e7e376e7c213b7e7e7e46cc70a5dd086daff2a00000000000000000000000044444444444444444444444444444444444444440000000000000000000000000000000000000000000000000000000005f5e100000000000000000000000000000000000000000000000000000000006adb314c00000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000041111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000",
    "expiresAt": "2026-10-23T10:05:00.000Z",
    "from": "0x19e7e376e7c213b7e7e7e46cc70a5dd086daff2a",
    "preparationId": "preparation_escrow",
    "purpose": "createEscrow",
    "to": "0x3333333333333333333333333333333333333333",
    "value": "0"
  },
  "approvalRequired": false,
  "approval": {
    "allowance": "0",
    "required": false,
    "requiredAmount": "0",
    "spender": "0x3333333333333333333333333333333333333333",
    "tokenAddress": "0x4444444444444444444444444444444444444444"
  }
}
```

**SDK Code**

```python Default
import requests

url = "https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns"

payload = {
    "side": "BUY",
    "tokenSymbol": "USDT",
    "fiatCurrencyId": "usd",
    "paymentMethodId": "bank_transfer",
    "savedPaymentMethodId": "account_demo",
    "amount": {
        "mode": "USDT",
        "value": "100"
    },
    "offerId": "offer_demo",
    "fingerprint": "preview_fingerprint_from_offer_search"
}
headers = {
    "Idempotency-Key": "request_demo_001",
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

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

print(response.json())
```

```javascript Default
const url = 'https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns';
const options = {
  method: 'POST',
  headers: {
    'Idempotency-Key': 'request_demo_001',
    Authorization: 'Bearer <token>',
    'Content-Type': 'application/json'
  },
  body: '{"side":"BUY","tokenSymbol":"USDT","fiatCurrencyId":"usd","paymentMethodId":"bank_transfer","savedPaymentMethodId":"account_demo","amount":{"mode":"USDT","value":"100"},"offerId":"offer_demo","fingerprint":"preview_fingerprint_from_offer_search"}'
};

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

```go Default
package main

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

func main() {

	url := "https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns"

	payload := strings.NewReader("{\n  \"side\": \"BUY\",\n  \"tokenSymbol\": \"USDT\",\n  \"fiatCurrencyId\": \"usd\",\n  \"paymentMethodId\": \"bank_transfer\",\n  \"savedPaymentMethodId\": \"account_demo\",\n  \"amount\": {\n    \"mode\": \"USDT\",\n    \"value\": \"100\"\n  },\n  \"offerId\": \"offer_demo\",\n  \"fingerprint\": \"preview_fingerprint_from_offer_search\"\n}")

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

	req.Header.Add("Idempotency-Key", "request_demo_001")
	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 Default
require 'uri'
require 'net/http'

url = URI("https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns")

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

request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = 'request_demo_001'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"side\": \"BUY\",\n  \"tokenSymbol\": \"USDT\",\n  \"fiatCurrencyId\": \"usd\",\n  \"paymentMethodId\": \"bank_transfer\",\n  \"savedPaymentMethodId\": \"account_demo\",\n  \"amount\": {\n    \"mode\": \"USDT\",\n    \"value\": \"100\"\n  },\n  \"offerId\": \"offer_demo\",\n  \"fingerprint\": \"preview_fingerprint_from_offer_search\"\n}"

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

```java Default
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns")
  .header("Idempotency-Key", "request_demo_001")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"side\": \"BUY\",\n  \"tokenSymbol\": \"USDT\",\n  \"fiatCurrencyId\": \"usd\",\n  \"paymentMethodId\": \"bank_transfer\",\n  \"savedPaymentMethodId\": \"account_demo\",\n  \"amount\": {\n    \"mode\": \"USDT\",\n    \"value\": \"100\"\n  },\n  \"offerId\": \"offer_demo\",\n  \"fingerprint\": \"preview_fingerprint_from_offer_search\"\n}")
  .asString();
```

```php Default
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns', [
  'body' => '{
  "side": "BUY",
  "tokenSymbol": "USDT",
  "fiatCurrencyId": "usd",
  "paymentMethodId": "bank_transfer",
  "savedPaymentMethodId": "account_demo",
  "amount": {
    "mode": "USDT",
    "value": "100"
  },
  "offerId": "offer_demo",
  "fingerprint": "preview_fingerprint_from_offer_search"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
    'Idempotency-Key' => 'request_demo_001',
  ],
]);

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

```csharp Default
using RestSharp;

var client = new RestClient("https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns");
var request = new RestRequest(Method.POST);
request.AddHeader("Idempotency-Key", "request_demo_001");
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"side\": \"BUY\",\n  \"tokenSymbol\": \"USDT\",\n  \"fiatCurrencyId\": \"usd\",\n  \"paymentMethodId\": \"bank_transfer\",\n  \"savedPaymentMethodId\": \"account_demo\",\n  \"amount\": {\n    \"mode\": \"USDT\",\n    \"value\": \"100\"\n  },\n  \"offerId\": \"offer_demo\",\n  \"fingerprint\": \"preview_fingerprint_from_offer_search\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Default
import Foundation

let headers = [
  "Idempotency-Key": "request_demo_001",
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "side": "BUY",
  "tokenSymbol": "USDT",
  "fiatCurrencyId": "usd",
  "paymentMethodId": "bank_transfer",
  "savedPaymentMethodId": "account_demo",
  "amount": [
    "mode": "USDT",
    "value": "100"
  ],
  "offerId": "offer_demo",
  "fingerprint": "preview_fingerprint_from_offer_search"
] as [String : Any]

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

let request = NSMutableURLRequest(url: NSURL(string: "https://us-central1-sinbad-staging-env.cloudfunctions.net/b2b-v1/v1/trade-breakdowns")! 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()
```