Pacifica
  • Getting Started
    • Closed Alpha Guide
      • Link To Guide PDF
    • Closed Alpha Trading Competition
  • Trading on Pacifica
    • Overview
    • Contract Specifications
      • Oracle Price & Mark Price
      • Settlement Mechanism
    • Order Types
      • Market Order
      • Limit Order
      • Order Rules & Constraints
    • Margin & Leverage
    • Funding Rates
    • Liquidations
  • API Documentation
    • API
      • REST API
        • Markets
          • Get market info
          • Get prices
          • Get kline (candle) data
          • Get recent trades
        • Account
          • Get account info
          • Get account settings
          • Update leverage
          • Update margin mode
          • Get positions
          • Get trade history
          • Get funding history
          • Get account equity history
          • Request withdrawal
        • Subaccounts
          • Create subaccount
          • Subaccount fund transfer
        • Orders
          • Get open orders
          • Get order history
          • Get order history by ID
          • Create order
          • Create stop order
          • Create position TP/SL
          • Cancel order
          • Cancel all orders
          • Cancel stop order
          • Batch order
      • Websocket
        • Subscriptions
          • Prices
          • Orderbook
          • Trades
          • Candle
          • Order updates
          • Account balance
          • Account margin
          • Account leverage
          • Account positions
          • Account orders
          • Account order updates
          • Account trades
        • Trading operations
          • Create order
          • Cancel order
          • Cancel all orders
      • Signing
        • Implementation
        • Operation Types
        • Error Handling
      • Rate limits
      • Tick and lot size
    • Specification
  • Other
    • Audits
    • Brand Assets
    • Contact Us
    • Glossary of Terms
Powered by GitBook
On this page
  • 1. Setup and Initialization:
  • 2. Choose Endpoint and Define Operation Type
  • 3. Create Signature Header
  • 4. Combine Header and Payload
  • 5. Recursively Sort JSON Keys
  • 6. Create Compact JSON
  • 7. Convert to Bytes and Generate Signature
  • 8. Build Final Request
  1. API Documentation
  2. API
  3. Signing

Implementation

The following guide provides a steps-by-step breakdown of Pacifica's signing implementation

PreviousSigningNextOperation Types

Last updated 1 day ago

1. Setup and Initialization:

import time
import base58
import requests
from solders.keypair import Keypair

PRIVATE_KEY = "your_private_key_here"

# Generate keypair from private key
keypair = Keypair.from_bytes(base58.b58decode(PRIVATE_KEY))
public_key = str(keypair.pubkey())

2. Choose Endpoint and Define Operation Type

For this example, we use the order creation endpoint. Refer to for a list of all types and corresponding API endpoints.

API_URL = "https://api.pacifica.fi/api/v1/orders/create"
operation_type = "create_order"
operation_data = {
    "symbol": "BTC",
    "price": "100000",
    "amount": "0.1",
    "side": "bid",
    "tif": "GTC",
    "reduce_only": False,
    "client_order_id": str(uuid.uuid4()),
}

3. Create Signature Header

Note that all times specified are denoted in milliseconds. The "expiry_window" field is optional, and defaults to 30_000 (30 seconds) if not specified in the header.

# Get current timestamp in milliseconds
timestamp = int(time.time() * 1_000)

signature_header = {
    "timestamp": timestamp,
    "expiry_window": 5_000,  
    "type": "create_order",
}

4. Combine Header and Payload

data_to_sign = {
    **signature_header,
    "data": operation_data,
}

In the case of our example, this creates:

 {
     "timestamp": 1748970123456,
     "expiry_window": 5000,
     "type": "create_order",
     "data": {
         "symbol": "BTC",
         "price": "100000",
         "amount": "0.1",
         "side": "bid",
         "tif": "GTC",
         "reduce_only": False,
         "client_order_id": "12345678-1234-1234-1234-123456789abc"
     }
 }

Note that data must be in same level as other headers.

5. Recursively Sort JSON Keys

def sort_json_keys(value):
    if isinstance(value, dict):
        sorted_dict = {}
        for key in sorted(value.keys()):
            sorted_dict[key] = sort_json_keys(value[key])
        return sorted_dict
    elif isinstance(value, list):
        return [sort_json_keys(item) for item in value]
    else:
        return value

sorted_message = sort_json_keys(data_to_sign)

In the case of our example, this creates:

{
     "data": {
         "amount": "0.1",
         "client_order_id": "12345678-1234-1234-1234-123456789abc",
         "price": "100000",
         "reduce_only": false,
         "side": "bid",
         "symbol": "BTC",
         "tif": "GTC"
     },
     "expiry_window": 5000,
     "timestamp": 1748970123456,
     "type": "create_order"
 }

Note that the recursive sorting alphabetically sorts *all* levels

6. Create Compact JSON

Compact JSON string with no whitespace and standardized seperators

import json

compact_json = json.dumps(sorted_message, separators=(",", ":"))

In the case of our example, this creates:

{"data":{"amount":"0.1","client_order_id":"12345678-1234-1234-1234-123456789abc","price":"100000","reduce_only":false,"side":"bid","symbol":"BTC","tif":"GTC"},"expiry_window":5000,"timestamp":1748970123456,"type":"create_order"}

This ensures that all logically identical messages will always produce *identical* signatures

7. Convert to Bytes and Generate Signature

Messages are converted to UTF-8 bytes for signing. The signature generated is then converted to Base58 string for transmission.

# Convert to UTF-8 bytes
message_bytes = compact_json.encode("utf-8")

# Sign message bytes using your private key
signature = keypair.sign_message(message_bytes)

# Convert signature to Base58 string
signature_b58 = base58.b58encode(bytes(signature)).decode("ascii")

# Expect an output similar to:
# "5j1Vy9UqYUF2jKD9r2Lv5AoMWHJuW5a1mqVzEhC9SJL5GqbPkGEQKpW3UZmKXr4UWrHMJ5xHQFMJkZWE8J5VyA"

8. Build Final Request

Build the header with generated authentication info and combine with operation data (NOT the "data" wrapper!)

request_header = {
    "account": public_key,
    "agent_wallet": None,
    "signature": signature_b58,
    "timestamp": signature_header["timestamp"],
    "expiry_window": signature_header["expiry_window"],
}

final_request = {
    **request_header,
    **operation_data,  # Use the ORIGINAL create order fields
}

In the case of our example, the final request looks like:

 {
     "account": "6ETnufiec2CxVWTS4u5Wiq33Zh5Y3Qm6Pkdpi375fuxP",
     "agent_wallet": null,
     "signature": "5j1Vy9UqYUF2jKD9r2Lv5AoMWHJuW5a1mqVzEhC9SJL5GqbPkGEQKpW3UZmKXr4UWrHMJ",
     "timestamp": 1748970123456,
     "expiry_window": 5000,
     "symbol": "BTC",
     "price": "100000",
     "amount": "0.1",
     "side": "bid",
     "tif": "GTC",
     "reduce_only": false,
     "client_order_id": "12345678-1234-1234-1234-123456789abc"
 }
Operation Types