Prerequisites
export LONGSHOT_WALLET_PRIVATE_KEY=0x...
Make sure to keep your bearer tokens and wallet private keys safe!
Runnable Example
# pip install eth-account
import base64
import json
import os
import time
import urllib.parse
import urllib.request
from typing import Optional
from eth_account import Account
from eth_account.messages import encode_defunct
BASE_URL = "https://api.longshot.xyz"
PRIVATE_KEY = os.environ["LONGSHOT_WALLET_PRIVATE_KEY"]
def request_json(method: str, path: str, body: Optional[dict] = None, bearer: Optional[str] = None) -> dict:
data = None if body is None else json.dumps(body).encode()
headers = {"accept": "application/json"}
if body is not None:
headers["content-type"] = "application/json"
if bearer:
headers["authorization"] = f"Bearer {bearer}"
req = urllib.request.Request(BASE_URL + path, data=data, method=method, headers=headers)
with urllib.request.urlopen(req, timeout=15) as res:
raw = res.read().decode()
return json.loads(raw) if raw else {}
def authenticate() -> tuple[str, str]:
account = Account.from_key(PRIVATE_KEY)
timestamp_ms = int(time.time() * 1000)
message = f"Sign in to longshot.xyz\n\nAddress: {account.address}\nTimestamp: {timestamp_ms}"
signed = Account.sign_message(encode_defunct(text=message), PRIVATE_KEY)
session = request_json("POST", "/v1/auth/wallet", {
"address": account.address,
"message": message,
"signature": base64.b64encode(signed.signature).decode(),
})
return account.address, session["session_token"]
def current_market_id(asset: str, duration_secs: int, bearer: str) -> int:
path = f"/v1/markets/current?asset={asset}&duration_secs={duration_secs}"
market = request_json("GET", path, bearer=bearer)["market"]
return int(market["market_id"])
def write_u64_le(buf: bytearray, offset: int, value: int) -> None:
buf[offset:offset + 8] = int(value).to_bytes(8, "little")
def sign_order(address: str, market_id: int, direction: str) -> dict:
order = {
"user": address,
"wager_micros": 1_000_000,
"min_odds": 1.01,
"legs": [{"market_id": market_id, "direction": direction}],
"nonce": int.from_bytes(os.urandom(6), "big"),
"expires_at_ms": int(time.time() * 1000) + 60_000,
"order_type": 2,
"shield_on": False,
}
legs = order["legs"]
buf = bytearray(51 + len(legs) * 9)
user_hex = address.removeprefix("0x")
for i in range(20):
buf[i] = int(user_hex[i * 2:i * 2 + 2], 16)
write_u64_le(buf, 20, order["wager_micros"])
buf[28:32] = round(order["min_odds"] * 10_000).to_bytes(4, "little")
write_u64_le(buf, 32, order["nonce"])
write_u64_le(buf, 40, order["expires_at_ms"])
buf[48] = order["order_type"]
buf[49] = 1 if order["shield_on"] else 0
buf[50] = len(legs)
for i, leg in enumerate(legs):
offset = 51 + i * 9
write_u64_le(buf, offset, leg["market_id"])
buf[offset + 8] = 0 if leg["direction"] == "up" else 1
signed = Account.sign_message(encode_defunct(primitive=bytes(buf)), PRIVATE_KEY)
order["signature"] = base64.b64encode(signed.signature).decode()
return order
address, bearer = authenticate()
market_id = current_market_id("BTC", 300, bearer)
order = sign_order(address, market_id, "up")
rfq = request_json("POST", "/v1/rfq", {"order": order}, bearer=bearer)
print(rfq)
if rfq.get("odds"):
print("implied_price_cents", round(100 / float(rfq["odds"]), 4))
Next Steps
Markets
Resolve the current or exact
market_id for an RFQ leg.RFQ Status
Track the RFQ lifecycle after submission.