Skip to main content

Embed: Your First Trade

This guide walks you through executing your first trade using the Kraken Embed API.

Prerequisites

Before you begin, make sure you have:

  • Kraken Embed API credentials (see Authentication Guide)
  • A verified user with an IIBAN (Internet International Bank Account Number)
  • Sufficient balance in the user's account

Trading Workflow

The Embed API uses a quote-based trading model:

┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│ Request Quote │ ───▶ │ Execute Quote │ ───▶ │ Monitor Status │
└─────────────────┘ └─────────────────┘ └─────────────────┘
POST /quotes PUT /quotes/{id} GET /quotes/{id}
  1. Request Quote: Get a price quote for your desired trade
  2. Execute Quote: Confirm and execute the quoted trade
  3. Monitor Status: Poll until the trade completes or listen for the quote.executed webhook

Step 1: Request a Quote

Request a quote to buy cryptocurrency with fiat currency. The quote locks in a price for a short period.

Quote Types

TypeDescriptionUse Case
spendSpecify amount to spend"I want to spend €50 on BTC"
receiveSpecify amount to receive"I want to receive 0.001 BTC"

Examples

import os
import json
import time
import hashlib
import hmac
import base64
import urllib.parse
import requests

API_KEY = os.environ.get("KRAKEN_API_KEY")
API_SECRET = os.environ.get("KRAKEN_API_SECRET")
BASE_URL = "https://embed.kraken.com"


def get_kraken_signature(urlpath, data, secret, nonce, params=None):
if data is None:
encoded = str(nonce).encode("utf-8")
else:
encoded = (str(nonce) + json.dumps(data)).encode("utf-8")

sign_path = urlpath
if params:
query = urllib.parse.urlencode(params)
sign_path += f"?{query}"

message = sign_path.encode() + hashlib.sha256(encoded).digest()
mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
return base64.b64encode(mac.digest()).decode()


def request_quote(user_id):
endpoint = "/b2b/quotes"
nonce = int(time.time() * 1000000000) # Nanoseconds

body = {
"type": "spend", # 'spend' fiat to buy crypto
"amount": {
"asset": "EUR", # Currency to spend
"amount": "50.00", # Amount to spend
},
"fee_bps": "100", # Fee in basis points (1%)
"spread_bps": "100", # Spread in basis points (1%)
"quote": {
"asset": "BTC", # Cryptocurrency to receive
},
}

params = {"user": user_id}
signature = get_kraken_signature(endpoint, body, API_SECRET, nonce, params)

headers = {
"API-Key": API_KEY,
"API-Sign": signature,
"API-Nonce": str(nonce),
"Content-Type": "application/json",
}

response = requests.post(
f"{BASE_URL}{endpoint}",
headers=headers,
params=params,
json=body,
)
return response.json()


user_id = "YOUR_USER_IIBAN"
quote = request_quote(user_id)
print(f"Quote ID: {quote['result']['quote_id']}")
print(f"You spend: {quote['result']['spend']['total']} {quote['result']['spend']['asset']}")
print(f"You receive: {quote['result']['receive']['total']} {quote['result']['receive']['asset']}")

Response Example

{
"result": {
"quote_id": "BQEXAMP-LE123-ABCDEF",
"type": "spend",
"status": "new",
"expires": "2026-01-26T12:00:30Z",
"spend": {
"asset": "EUR",
"total": "50.00",
"fee": "0.50",
"subtotal": "49.50"
},
"receive": {
"asset": "BTC",
"total": "0.00052341",
"fee": "0.00000000",
"subtotal": "0.00052341"
},
"unit_price": {
"asset": "BTC",
"unit_price": "94567.50",
"denomination_asset": "EUR"
}
}
}
caution

Quotes expire after 120 seconds (2 minutes). Execute the quote promptly or request a new one if it expires. The exact expiration time is returned in the expires field of the quote response.

Step 2: Execute the Quote

Once you have a quote, execute it by making a PUT request with the quote ID.

def execute_quote(user_id, quote_id):
endpoint = f"/b2b/quotes/{quote_id}"
nonce = int(time.time() * 1000000000) # Nanoseconds

params = {"user": user_id}
signature = get_kraken_signature(endpoint, None, API_SECRET, nonce, params)

headers = {
"API-Key": API_KEY,
"API-Sign": signature,
"API-Nonce": str(nonce),
}

response = requests.put(
f"{BASE_URL}{endpoint}",
headers=headers,
params=params,
)
return response.json()


result = execute_quote(user_id, quote["result"]["quote_id"])
print(f"Status: {result['result']['status']}")

Step 3: Monitor Trade Status

After execution, poll the quote status until the trade completes.

Status Values

StatusDescription
newQuote created, awaiting execution
acceptedQuote has been accepted for execution
order_completeTrade order has been completed
credit_transfer_completeTrade fully completed, funds transferred
quote_cancelledQuote was cancelled or expired
quote_execution_failedTrade execution failed

Examples

import time

def get_quote_status(user_id, quote_id):
endpoint = f"/b2b/quotes/{quote_id}"
nonce = int(time.time() * 1000000000) # Nanoseconds

params = {"user": user_id}
signature = get_kraken_signature(endpoint, None, API_SECRET, nonce, params)

headers = {
"API-Key": API_KEY,
"API-Sign": signature,
"API-Nonce": str(nonce),
}

response = requests.get(
f"{BASE_URL}{endpoint}",
headers=headers,
params=params,
)
return response.json()


def wait_for_completion(user_id, quote_id, max_attempts=60):
terminal_statuses = ["credit_transfer_complete", "quote_cancelled", "quote_execution_failed"]

for i in range(max_attempts):
status = get_quote_status(user_id, quote_id)
current_status = status["result"]["status"]
print(f"Status: {current_status}")

if current_status == "credit_transfer_complete":
print("✓ Trade completed!")
return status

if current_status in terminal_statuses:
raise Exception(f"Trade ended with status: {current_status}")

time.sleep(1)

raise Exception("Trade did not complete in time")


final = wait_for_completion(user_id, quote["result"]["quote_id"])

Error Handling

Common Errors

ErrorCauseSolution
quote_expiredQuote timeout exceededRequest a new quote and execute faster
insufficient_balanceUser lacks fundsCheck user balance before trading
invalid_amountAmount too small/largeCheck min/max limits for the asset
asset_disabledAsset not tradableUse List Assets to check availability

Best Practices

  1. Handle quote expiration: Always be prepared to request a new quote
  2. Check asset availability: Call List Assets before trading
  3. Verify user balance: Ensure sufficient funds before requesting quotes
  4. Implement retry logic: Network issues can cause temporary failures
  5. Log trace IDs: Store the x-trace-id header for debugging