Subscribe to Price Channel

Subscribe request for two-way Crypto and FX pricing

Price Streams

Subscribe to real-time two-way prices (bid and offer) for trading. Price streams continuously update with live market prices for your specified quantity and currency pair.

What You'll Receive

  • Two-way prices - Both bid (buy from Zodia) and offer (sell to Zodia) prices
  • Tradeable quotes - Each price includes a unique quote ID for order execution
  • Continuous updates - New prices automatically replace previous ones
  • Quantity-specific - Prices tailored to your requested trade size
📘

Important Notes

  • Partial fills are available - order request can be less than or equal to quoted amount
  • Full order book depth is not provided - only your requested size
  • If connection is lost, download transactions via REST API for reconciliation, or subscribe to transactions via the Webhook.

Subscribe to Price Stream

Request a continuous stream of prices for a specific currency pair and quantity.

{
    "messageType": "subscribe",
    "instrument": "USDC.AED",
    "quantity": "100000",
    "currency": "AED",
    "accountGrpUuid": "a6898bdd-856b-4259-b6e2-6ef66f2282e1",
    "tenor": "T"
}

Request Fields

FieldRequiredTypeDescription
messageTypeYesStringMust be subscribe
instrumentYesStringCurrency pair (e.g., USDC.AED, BTC.USD)
quantityYesStringAmount to quote in the specified currency
currencyYesStringCurrency for quantity - must be either base or quote currency of the pair
accountGrpUuidYesStringAccount group UUID (from Account Groups message).
tenorYesStringSettlement date: T (closest available day) or T1 (closest available day + 1 day)
tagNoStringReserved for future use

Understanding Currency Pairs

Currency pairs are formatted as BASE.QUOTE:

  • USDC.AED - Base currency: USDC, Quote currency: AED
  • When you specify currency: "AED" with quantity: "100000", you're requesting a price for 100,000 AED worth of USDC
  • When you specify currency: "USDC" with quantity: "1000", you're requesting a price for 1,000 USDC

Settlement Tenors

TenorDescriptionUse Case
TToday settlementPrice for closest available value date to today
T1Tomorrow settlementPrice for closest available value date to tomorrow

The actual settlement date is returned in the settleDate field of price updates. Contact your Relationship Manager for custom value date pricing.


Subscribe Response

Confirms your subscription was successful and provides a subscription ID.

{
    "chanId": "",
    "timestamp": 1718110925811,
    "messageType": "subscribe",
    "success": true,
    "message": "Subscribed",
    "subscriptionId": "13f07bc9-055f-4054-bb78-73fe9f325ee6",
    "tag": "test-tag",
    "instrument": "USDC.AED",
    "quantity": "10000.000000",
    "code": "",
    "tenor": "T",
    "settleDate": ""
}

Response Fields

FieldRequiredTypeDescription
chanIdNoStringReserved for future use (currently empty)
timestampYesLongUnix timestamp in milliseconds
messageTypeYesStringAlways subscribe
successYesBooleantrue if subscription succeeded, false if failed
messageYesStringConfirmation message or error description
subscriptionIdYesStringUnique ID for this subscription - save this for unsubscribing
instrumentYesStringConfirmed currency pair
quantityYesStringConfirmed quantity in base currency terms
quoteAmountYesStringConfirmed quantity in quote currency terms
codeNoStringError code (empty on success)
tenorNoStringConfirmed tenor
settleDateNoStringReserved for future use (currently empty)
tagNoStringYour tag if provided

Store the subscriptionId - you'll need it to unsubscribe later.


Receiving Price Updates

After successful subscription, you'll receive continuous price updates.

{
    "chanId": "",
    "timestamp": 1729156597244,
    "messageType": "pricestream",
    "instrument": "USDC.AED",
    "quoteId": "cmEK+SwelROidy4Sn63WoWU2UJSAFOPy9Xi5UDpnCJPG5oH8ABAFv6fB...",
    "tag": "a5cf32f7-ae66-4edc-8538-f015020d1952",
    "offer": {
        "price": "3.673050",
        "quantity": "2722.533045",
        "quoteAmount": "2722.533045"
    },
    "bid": {
        "price": "3.672950",
        "quantity": "2722.607169",
        "quoteAmount": "2722.533045"
    },
    "tenor": "T",
    "settleDate": "20251021"
}

Price Stream Fields

FieldRequiredTypeDescription
chanIdNoStringClient identifier (can be ignored)
timestampYesLongUnix timestamp in milliseconds
messageTypeYesStringAlways pricestream
instrumentYesStringCurrency pair
quoteIdYesStringUnique quote identifier - use this to execute orders
offerYesObjectSell side (you sell base currency to Zodia)
offer.priceYesStringOffer price
offer.quantityYesStringOffer quantity in base currency
offer.quoteAmountYesStringOffer quantity in quote currency
bidYesObjectBuy side (you buy base currency from Zodia)
bid.priceYesStringBid price
bid.quantityYesStringBid quantity in base currency
bid.quoteAmountYesStringBid quantity in quote currency
tenorYesStringSettlement tenor for this quote
settleDateNoStringActual settlement date in YYYYMMDD format
tagNoStringYour tag if provided

Understanding Bid and Offer

For currency pair USDC.AED:

  • Bid (3.672950) - Price at which Zodia will buy USDC from you (you receive AED)

    • You're selling USDC, buying AED
  • Offer (3.673050) - Price at which Zodia will sell USDC to you (you pay AED)

    • You're buying USDC, selling AED

Quote Expiry

Quote expiry is not published on the stream. The default quote expiry time is 3 seconds.

Handling Price Updates - Example

import json

# Store active subscriptions
active_subscriptions = {}

def handle_websocket_message(message):
    """Process incoming WebSocket messages"""
    msg = json.loads(message)
    
    if msg['messageType'] == 'subscribe':
        # Store subscription ID
        if msg['success']:
            subscription_id = msg['subscriptionId']
            active_subscriptions[msg['instrument']] = subscription_id
            print(f"✅ Subscribed to {msg['instrument']}: {subscription_id}")
        else:
            print(f"❌ Subscription failed: {msg['message']}")
    
    elif msg['messageType'] == 'pricestream':
        # Process price update
        instrument = msg['instrument']
        bid_price = float(msg['bid']['price'])
        offer_price = float(msg['offer']['price'])
        quote_id = msg['quoteId']
        
        print(f"Price Update - {instrument}")
        print(f"  Bid:   {bid_price} (qty: {msg['bid']['quantity']})")
        print(f"  Offer: {offer_price} (qty: {msg['offer']['quantity']})")
        print(f"  Spread: {(offer_price - bid_price):.6f}")
        print(f"  Quote ID: {quote_id}")
        print(f"  Settle: {msg.get('settleDate', 'N/A')}")
        
        # Check if price meets your trading criteria
        if should_trade(bid_price, offer_price):
            execute_order(quote_id, 'BUY', msg['offer']['quantity'])
// Store active subscriptions
const activeSubscriptions = {};

function handleWebSocketMessage(message) {
    const msg = JSON.parse(message);
    
    if (msg.messageType === 'subscribe') {
        // Store subscription ID
        if (msg.success) {
            const subscriptionId = msg.subscriptionId;
            activeSubscriptions[msg.instrument] = subscriptionId;
            console.log(`✅ Subscribed to ${msg.instrument}: ${subscriptionId}`);
        } else {
            console.error(`❌ Subscription failed: ${msg.message}`);
        }
    }
    else if (msg.messageType === 'pricestream') {
        // Process price update
        const instrument = msg.instrument;
        const bidPrice = parseFloat(msg.bid.price);
        const offerPrice = parseFloat(msg.offer.price);
        const quoteId = msg.quoteId;
        
        console.log(`Price Update - ${instrument}`);
        console.log(`  Bid:   ${bidPrice} (qty: ${msg.bid.quantity})`);
        console.log(`  Offer: ${offerPrice} (qty: ${msg.offer.quantity})`);
        console.log(`  Spread: ${(offerPrice - bidPrice).toFixed(6)}`);
        console.log(`  Quote ID: ${quoteId}`);
        console.log(`  Settle: ${msg.settleDate || 'N/A'}`);
        
        // Check if price meets your trading criteria
        if (shouldTrade(bidPrice, offerPrice)) {
            executeOrder(quoteId, 'BUY', msg.offer.quantity);
        }
    }
}

Unsubscribe from Price Stream

Stop receiving price updates by unsubscribing using the subscription ID.

{
    "messageType": "unsubscribe",
    "subscriptionId": "13f07bc9-055f-4054-bb78-73fe9f325ee6"
}

Request Fields

FieldRequiredTypeDescription
messageTypeYesStringMust be unsubscribe
subscriptionIdYesStringSubscription ID received in subscribe response

Unsubscribe Response

{
    "timestamp": 1718111157195,
    "messageType": "unsubscribe",
    "success": true,
    "subscriptionId": "2ffc8d0c-21f5-4364-b2a6-4007218e57ee",
    "message": "Cancelled subscription 2ffc8d0c-21f5-4364-b2a6-4007218e57ee...",
    "instrument": "USDC.AED",
    "quantity": "100000.000000",
    "tenor": "T"
}

Response Fields

FieldRequiredTypeDescription
timestampYesLongUnix timestamp in milliseconds
messageTypeYesStringAlways unsubscribe
successYesBooleantrue if unsubscribe succeeded
subscriptionIdYesStringThe subscription ID that was unsubscribed
messageYesStringConfirmation message
instrumentYesStringCurrency pair that was unsubscribed
quantityYesDoubleQuantity that was unsubscribed
tenorYesStringTenor that was unsubscribed

Stream Stop Message (TOD Tenor Only)

When using the TOD tenor, if the currency pair reaches its daily cut-off time, you'll receive a stream stop message.

📘

Note

This only applies to TOD tenor. T and T1 tenors are not affected.

{
    "instrument": "USDC.GBP",
    "tenor": "TOD",
    "chanId": "bd00d714-f1bd-49c2-970d-91791b4243ee",
    "tag": "c8c423ff-6c6c-4cc0-a63d-a2a1251d0bbe",
    "timestamp": 1747916826063,
    "messageType": "streamStop"
}

Stream Stop Fields

FieldRequiredTypeDescription
chanIdNoStringClient identifier (can be ignored)
timestampYesLongUnix timestamp in milliseconds
messageTypeYesStringAlways streamStop
instrumentYesStringCurrency pair that stopped streaming
tenorYesStringThe tenor that reached cut-off
tagNoStringYour tag if provided

When you receive this message, the price stream for that tenor is no longer available. You can subscribe to a different tenor if needed.