Base URL:
https://www.bitstamp.net
Official docs: https://www.bitstamp.net/api/
The Bitstamp API allows clients to access and control their accounts using custom software. All responses are JSON. Private endpoints require authentication via HMAC-SHA256 signed headers.
| Limit | Value |
|---|---|
| Requests per second | 400 |
| Default threshold | 10,000 requests per 10 minutes |
Rate limits can be increased by contacting Bitstamp. For real-time data, use the WebSocket API instead of polling REST endpoints.
All private API calls require the following HTTP headers:
| Header | Value |
|---|---|
X-Auth |
"BITSTAMP " + api_key |
X-Auth-Signature |
HMAC-SHA256 signature (hex string) |
X-Auth-Nonce |
UUID4 string (lowercase, 36 chars, unique per request, valid for 150 seconds) |
X-Auth-Timestamp |
Request departure time — UTC milliseconds |
X-Auth-Version |
"v2" |
Content-Type |
"application/x-www-form-urlencoded" (omit if request body is empty) |
The string to sign is constructed by concatenating (with no separators):
"BITSTAMP " + api_key
+ HTTP_METHOD (e.g. "POST" or "GET")
+ "www.bitstamp.net"
+ URL_PATH (e.g. "/api/v2/balance/")
+ QUERY_STRING (empty string if none)
+ CONTENT_TYPE (empty string if no body)
+ NONCE
+ TIMESTAMP
+ "v2"
+ PAYLOAD_STRING (URL-encoded body, empty string if none)
Important: If the request body is empty, omit
Content-Typefrom both the headers and the signature string.
import hashlib
import hmac
import time
import uuid
import requests
from urllib.parse import urlencode
API_KEY = 'your_api_key'
API_SECRET = b'your_api_secret'
def build_headers(method, path, payload=None, query=''):
timestamp = str(int(round(time.time() * 1000)))
nonce = str(uuid.uuid4())
if payload:
payload_string = urlencode(payload)
content_type = 'application/x-www-form-urlencoded'
else:
payload_string = ''
content_type = ''
message = (
'BITSTAMP ' + API_KEY
+ method
+ 'www.bitstamp.net'
+ path
+ query
+ content_type
+ nonce
+ timestamp
+ 'v2'
+ payload_string
).encode('utf-8')
signature = hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest()
headers = {
'X-Auth': 'BITSTAMP ' + API_KEY,
'X-Auth-Signature': signature,
'X-Auth-Nonce': nonce,
'X-Auth-Timestamp': timestamp,
'X-Auth-Version': 'v2',
}
if content_type:
headers['Content-Type'] = content_type
return headers, payload_string
def private_post(path, payload=None):
headers, body = build_headers('POST', path, payload)
url = 'https://www.bitstamp.net' + path
response = requests.post(url, headers=headers, data=body)
return response.json()
def private_get(path, query=''):
headers, _ = build_headers('GET', path, query=query)
url = 'https://www.bitstamp.net' + path
if query:
url += '?' + query
response = requests.get(url, headers=headers)
return response.json()
| Code | Meaning |
|---|---|
200 |
OK |
400 |
Bad Request — invalid parameters |
401 |
Unauthorized — authentication failed |
403 |
Forbidden — insufficient permissions |
404 |
Not Found |
429 |
Too Many Requests — rate limit exceeded |
500 |
Internal Server Error |
Errors may include a response_code field (e.g. "400.001") and optional response_explanation:
| Code | Description |
|---|---|
400.001 |
Unknown validation error |
400.002 |
Rate limit exceeded |
API0020 |
Content-Type header should not be present (on empty-body requests) |
API5012 |
Returned on certain earn endpoint errors |
Public endpoints require no authentication.
GET /api/v2/currencies/Returns a list of all listed currencies with basic info, including supported blockchain networks, minimum withdrawal amounts, deposit/withdrawal status, and decimal precision per network.
import requests
response = requests.get('https://www.bitstamp.net/api/v2/currencies/')
currencies = response.json()
GET /api/v2/markets/Returns info about all available trading markets/pairs. Replaces the deprecated /api/v2/trading-pairs-info/.
response = requests.get('https://www.bitstamp.net/api/v2/markets/')
markets = response.json()
GET /api/v2/ticker/Returns ticker data for all markets. Do not pass any GET parameters.
GET /api/v2/ticker/{market_symbol}/Returns ticker data for a specific currency pair (e.g. btcusd, ethusd, ethbtc).
Response fields:
| Field | Description |
|---|---|
last |
Last traded price |
high |
24-hour high |
low |
24-hour low |
bid |
Highest buy order |
ask |
Lowest sell order |
volume |
24-hour volume |
vwap |
24-hour volume weighted average price |
open |
Opening price |
timestamp |
Unix timestamp |
response = requests.get('https://www.bitstamp.net/api/v2/ticker/btcusd/')
ticker = response.json()
print(ticker['last'], ticker['bid'], ticker['ask'])
GET /api/v2/ticker_hour/{market_symbol}/Returns hourly ticker data (values computed over the past hour) for a currency pair.
response = requests.get('https://www.bitstamp.net/api/v2/ticker_hour/btcusd/')
GET /api/v2/order_book/{market_symbol}/Returns the current order book for a market.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
group |
int | 0 = ungrouped, 1 = group by price (default), 2 = group by price, include order count |
Response fields:
| Field | Description |
|---|---|
timestamp |
Unix timestamp |
microtimestamp |
Microsecond timestamp |
bids |
List of [price, amount] arrays (descending by price) |
asks |
List of [price, amount] arrays (ascending by price) |
response = requests.get('https://www.bitstamp.net/api/v2/order_book/btcusd/')
order_book = response.json()
best_bid = order_book['bids'][0]
best_ask = order_book['asks'][0]
GET /api/v2/transactions/{market_symbol}/Returns recent public trades for a market.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
time |
string | hour |
Time window: minute, hour, or day |
Response fields (per trade):
| Field | Description |
|---|---|
date |
Unix timestamp |
tid |
Trade ID |
price |
Trade price |
amount |
Trade amount |
type |
0 = buy, 1 = sell |
response = requests.get(
'https://www.bitstamp.net/api/v2/transactions/btcusd/',
params={'time': 'hour'}
)
trades = response.json()
GET /api/v2/ohlc/{market_symbol}/Returns OHLCV candlestick data.
Query parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
step |
int | Yes | Candle duration in seconds. Valid values: 60, 180, 300, 900, 1800, 3600, 7200, 14400, 21600, 43200, 86400, 259200 |
limit |
int | Yes | Number of candles to return (1–1000) |
start |
int | No | Start Unix timestamp |
end |
int | No | End Unix timestamp |
exclude_current_candle |
bool | No | Exclude the still-open current candle |
Response structure:
{
"data": {
"pair": "BTC/USD",
"ohlc": [
{
"timestamp": "1609459200",
"open": "28999.63",
"high": "29022.01",
"low": "28999.14",
"close": "29006.31",
"volume": "0.86157958"
}
]
}
}
import requests
import pandas as pd
currency_pair = 'btcusd'
url = f'https://www.bitstamp.net/api/v2/ohlc/{currency_pair}/'
params = {
'step': 3600, # 1-hour candles
'limit': 100,
}
response = requests.get(url, params=params)
ohlc_data = response.json()['data']['ohlc']
df = pd.DataFrame(ohlc_data)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s')
df[['open', 'high', 'low', 'close', 'volume']] = df[['open', 'high', 'low', 'close', 'volume']].astype(float)
print(df.tail())
Fetching historical OHLC in date ranges:
import requests
import pandas as pd
currency_pair = 'btcusd'
url = f'https://www.bitstamp.net/api/v2/ohlc/{currency_pair}/'
start = '2021-01-01'
end = '2021-01-02'
dates = pd.date_range(start, end, freq='6H')
dates = [int(x.value / 10**9) for x in list(dates)]
master_data = []
for first, last in zip(dates, dates[1:]):
params = {'step': 60, 'limit': 1000, 'start': first, 'end': last}
data = requests.get(url, params=params).json()['data']['ohlc']
master_data += data
df = pd.DataFrame(master_data)
GET /api/v2/eur_usd/Returns the current EUR/USD conversion rate.
Response fields:
| Field | Description |
|---|---|
buy |
Conversion rate for buying |
sell |
Conversion rate for selling |
response = requests.get('https://www.bitstamp.net/api/v2/eur_usd/')
rate = response.json()
GET /api/v2/travel-rule/vasps/Returns a list of Virtual Asset Service Providers (VASPs) required for Travel Rule compliance when transferring crypto to/from other platforms.
response = requests.get('https://www.bitstamp.net/api/v2/travel-rule/vasps/')
vasps = response.json()
All private endpoints require authentication headers (see Authentication).
POST /api/v2/account_balances/Returns all account balances across all currencies.
Response fields (per currency, e.g. btc_):
| Field | Description |
|---|---|
{currency}_balance |
Total balance |
{currency}_available |
Available (not reserved) |
{currency}_reserved |
Reserved in open orders |
balances = private_post('/api/v2/account_balances/')
btc_available = balances.get('btc_available')
usd_available = balances.get('usd_available')
POST /api/v2/account_balances/{currency}/Returns balances for a specific currency.
btc_balance = private_post('/api/v2/account_balances/btc/')
POST /api/v2/fees/trading/Returns all trading fees.
POST /api/v2/fees/trading/{market_symbol}/Returns trading fees for a specific market.
POST /api/v2/fees/withdrawal/Returns all withdrawal fees.
POST /api/v2/fees/withdrawal/{currency}/Returns withdrawal fee for a specific currency.
fees = private_post('/api/v2/fees/trading/')
btcusd_fee = private_post('/api/v2/fees/trading/btcusd/')
withdrawal_fees = private_post('/api/v2/fees/withdrawal/')
POST /api/v2/order_status/Returns the status of an order. Works for the account (sub or main) the API key is bound to. For closed orders, only data from the past 30 days is available.
Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Order ID (use either this or client_order_id) |
client_order_id |
string | Client-assigned order ID |
status = private_post('/api/v2/order_status/', {'id': '1234567890'})
POST /api/v2/open_orders/all/Returns all open orders across all markets. Cached for 10 seconds.
open_orders = private_post('/api/v2/open_orders/all/')
POST /api/v2/open_orders/{market_symbol}/Returns open orders for a specific market.
open_orders = private_post('/api/v2/open_orders/btcusd/')
Open order response fields:
| Field | Description |
|---|---|
id |
Order ID |
client_order_id |
Client-specified ID (if provided) |
datetime |
Order creation datetime |
type |
0 = buy, 1 = sell |
price |
Order price |
amount |
Remaining amount |
market |
Market symbol |
POST /api/v2/cancel_order/Cancels an order.
Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Order ID to cancel |
Response: May include "status": "Canceled" or "status": "Cancel pending" (if a duplicate cancel is in progress; HTTP 200 is still returned).
result = private_post('/api/v2/cancel_order/', {'id': '1234567890'})
POST /api/v2/cancel_all_orders/Cancels all open orders.
result = private_post('/api/v2/cancel_all_orders/')
POST /api/v2/cancel_all_orders/{market_symbol}/Cancels all open orders for a specific market.
result = private_post('/api/v2/cancel_all_orders/btcusd/')
POST /api/v2/buy/{market_symbol}/Places a limit buy order.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount |
decimal string | Yes | Amount to buy |
price |
decimal string | Yes | Limit price |
limit_price |
decimal string | No | If set, order becomes a stop-limit buy |
daily_order |
bool | No | Order expires at end of day (UTC midnight) if true |
ioc_order |
bool | No | Immediate-or-cancel order |
client_order_id |
string | No | Custom order identifier |
order = private_post('/api/v2/buy/btcusd/', {
'amount': '0.001',
'price': '30000.00',
})
POST /api/v2/buy/market/{market_symbol}/Places a market buy order.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount |
decimal string | Yes | Amount of quote currency to spend |
client_order_id |
string | No | Custom order identifier |
order = private_post('/api/v2/buy/market/btcusd/', {'amount': '100.00'})
POST /api/v2/buy/instant/{market_symbol}/Places an instant buy order (fills at current market price against the order book).
Parameters: Same as market order.
POST /api/v2/sell/{market_symbol}/Places a limit sell order.
Parameters: Same as limit buy.
order = private_post('/api/v2/sell/btcusd/', {
'amount': '0.001',
'price': '50000.00',
})
POST /api/v2/sell/market/{market_symbol}/Places a market sell order.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount |
decimal string | Yes | Amount of base currency to sell |
client_order_id |
string | No | Custom order identifier |
order = private_post('/api/v2/sell/market/btcusd/', {'amount': '0.001'})
POST /api/v2/sell/instant/{market_symbol}/Places an instant sell order.
POST /api/v2/replace_order/Replaces an existing order (cancel + new order atomically).
Parameters: id of the order to replace, plus the standard order creation parameters.
POST /api/v2/order_data/Retrieves historical public order events for a market (for WebSocket gap recovery).
POST /api/v2/account_order_data/Retrieves historical order events for the authenticated user's account (for WebSocket gap recovery).
Order response fields:
| Field | Description |
|---|---|
id |
Order ID |
client_order_id |
Client-assigned ID |
datetime |
Datetime string |
type |
0 = buy, 1 = sell |
price |
Order price |
amount |
Order amount |
market |
Market symbol |
status |
Order status |
POST /api/v2/user_transactions/Returns transaction history for the account.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
offset |
int | 0 |
Number of transactions to skip |
limit |
int | 100 |
Number of transactions to return |
sort |
string | desc |
Sort order: asc or desc |
since_timestamp |
int | — | Return only transactions after this Unix timestamp |
since_id |
int | — | Return only transactions after this transaction ID |
Transaction types:
| Value | Description |
|---|---|
0 |
Deposit |
1 |
Withdrawal |
2 |
Market trade |
14 |
Sub account transfer |
25 |
Credited with staked assets |
26 |
Sent assets to staking |
27 |
Staking reward |
32 |
Referral reward |
35 |
Inter-account transfer |
transactions = private_post('/api/v2/user_transactions/', {
'offset': '0',
'limit': '100',
'sort': 'desc',
})
POST /api/v2/user_transactions/{market_symbol}/Returns transactions filtered to a specific market.
transactions = private_post('/api/v2/user_transactions/btcusd/', {
'limit': '50',
'sort': 'desc',
})
POST /api/v2/crypto-transactions/deposits/Returns crypto deposit transaction history.
POST /api/v2/crypto-transactions/deposits/{deposit_id}/reject/Rejects a specific crypto deposit.
POST /api/v2/{currency}_address/Returns (or generates) the deposit address for a given cryptocurrency.
Available address endpoints include:
POST /api/v2/btc_address/POST /api/v2/eth_address/POST /api/v2/ltc_address/POST /api/v2/xrp_address/POST /api/v2/bch_address/POST /api/v2/xlm_address/POST /api/v2/pax_address/POST /api/v2/link_address/POST /api/v2/omg_address/POST /api/v2/usdc_address/
btc_address = private_post('/api/v2/btc_address/')
eth_address = private_post('/api/v2/eth_address/')
POST /api/v2/crypto-transactions/withdrawals/Returns crypto withdrawal transaction history.
POST /api/v2/btc_withdrawal/Withdraw Bitcoin.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
amount |
decimal string | Yes | Amount in BTC |
address |
string | Yes | Bitcoin address |
instant |
int | No | 1 for instant, 0 for standard |
result = private_post('/api/v2/btc_withdrawal/', {
'amount': '0.001',
'address': 'bc1q...',
})
POST /api/v2/eth_withdrawal/Withdraw Ethereum.
Parameters: amount and address.
result = private_post('/api/v2/eth_withdrawal/', {
'amount': '0.01',
'address': '0x...',
})
Similar endpoints exist for other currencies (e.g. ltc_withdrawal, xrp_withdrawal, bch_withdrawal, xlm_withdrawal, usdc_withdrawal, etc.).
Note: Travel Rule data fields are optional now but will become mandatory in a future breaking change.
POST /api/v2/withdrawal/open/Opens a bank (fiat) withdrawal.
Common parameters (see official docs for full field list by withdrawal type):
| Parameter | Description |
|---|---|
amount |
Withdrawal amount |
account_currency |
Currency (e.g. USD, EUR) |
name |
Account holder name |
bank_name |
Receiving bank name |
iban |
IBAN (for SEPA transfers) |
bic |
BIC/SWIFT code |
address |
Account holder address |
city |
City |
country |
Country code |
result = private_post('/api/v2/withdrawal/open/', {
'amount': '100.00',
'account_currency': 'EUR',
'name': 'John Doe',
'iban': 'DE89...',
'bic': 'COBADEFFXXX',
'address': '123 Main St',
'city': 'Berlin',
'country': 'DE',
})
POST /api/v2/withdrawal/status/Returns the status of a withdrawal.
Parameters: id — withdrawal ID.
POST /api/v2/withdrawal/cancel/Cancels a pending bank withdrawal.
Parameters: id — withdrawal ID.
POST /api/v2/withdrawal-requests/Returns a list of all withdrawal requests.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
timedelta |
int | 86400 |
Return requests within this many seconds of now |
Response fields (per request):
| Field | Description |
|---|---|
id |
Withdrawal ID |
datetime |
Datetime string |
type |
Withdrawal type (0=SEPA, 1=Bitcoin, 2=Wire, etc.) |
status |
0=Open, 1=In process, 2=Finished, 3=Cancelled, 4=Failed |
amount |
Amount |
data |
Extra type-specific data |
requests_list = private_post('/api/v2/withdrawal-requests/', {'timedelta': '86400'})
POST /api/v2/api-key/revoke/all/Revokes all API keys for the account (kill switch). Use with extreme caution.
result = private_post('/api/v2/api-key/revoke/all/')
import requests
def get_ticker(pair='btcusd'):
url = f'https://www.bitstamp.net/api/v2/ticker/{pair}/'
response = requests.get(url)
response.raise_for_status()
return response.json()
ticker = get_ticker('ethusd')
print(f"ETH/USD last: {ticker['last']}, bid: {ticker['bid']}, ask: {ticker['ask']}")
import requests
def get_order_book(pair='btcusd', group=1):
url = f'https://www.bitstamp.net/api/v2/order_book/{pair}/'
response = requests.get(url, params={'group': group})
response.raise_for_status()
return response.json()
book = get_order_book('btcusd')
print("Best bid:", book['bids'][0])
print("Best ask:", book['asks'][0])
import requests
import pandas as pd
def get_ohlc(pair='btcusd', step=3600, limit=100):
url = f'https://www.bitstamp.net/api/v2/ohlc/{pair}/'
response = requests.get(url, params={'step': step, 'limit': limit})
response.raise_for_status()
data = response.json()['data']['ohlc']
df = pd.DataFrame(data)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='s')
numeric_cols = ['open', 'high', 'low', 'close', 'volume']
df[numeric_cols] = df[numeric_cols].astype(float)
return df.set_index('timestamp')
df = get_ohlc('btcusd', step=86400, limit=30) # 30 daily candles
print(df.tail())
import hashlib
import hmac
import time
import uuid
import requests
from urllib.parse import urlencode
API_KEY = 'your_api_key'
API_SECRET = b'your_api_secret'
def signed_post(path, payload=None):
timestamp = str(int(round(time.time() * 1000)))
nonce = str(uuid.uuid4())
if payload:
payload_string = urlencode(payload)
content_type = 'application/x-www-form-urlencoded'
else:
payload_string = ''
content_type = ''
message = (
'BITSTAMP ' + API_KEY
+ 'POST'
+ 'www.bitstamp.net'
+ path
+ '' # query string (empty for POST)
+ content_type
+ nonce
+ timestamp
+ 'v2'
+ payload_string
).encode('utf-8')
signature = hmac.new(API_SECRET, msg=message, digestmod=hashlib.sha256).hexdigest()
headers = {
'X-Auth': 'BITSTAMP ' + API_KEY,
'X-Auth-Signature': signature,
'X-Auth-Nonce': nonce,
'X-Auth-Timestamp': timestamp,
'X-Auth-Version': 'v2',
}
if content_type:
headers['Content-Type'] = content_type
url = 'https://www.bitstamp.net' + path
response = requests.post(url, headers=headers, data=payload_string)
response.raise_for_status()
return response.json()
# Get all balances
balances = signed_post('/api/v2/account_balances/')
print(f"BTC available: {balances.get('btc_available')}")
print(f"USD available: {balances.get('usd_available')}")
order = signed_post('/api/v2/buy/btcusd/', {
'amount': '0.0001',
'price': '25000.00',
})
print("Order placed:", order)
# List open orders
open_orders = signed_post('/api/v2/open_orders/all/')
print(f"Open orders: {len(open_orders)}")
# Cancel all open orders
result = signed_post('/api/v2/cancel_all_orders/')
print("Cancel result:", result)
transactions = signed_post('/api/v2/user_transactions/', {
'offset': '0',
'limit': '50',
'sort': 'desc',
})
for tx in transactions:
tx_type = {0: 'Deposit', 1: 'Withdrawal', 2: 'Trade'}.get(int(tx['type']), str(tx['type']))
print(f"{tx['datetime']} | {tx_type} | {tx.get('btc', '')} BTC | {tx.get('usd', '')} USD")
This document is compiled from the official Bitstamp API documentation at https://www.bitstamp.net/api/ and is Python-focused. Always refer to the official docs for the most up-to-date endpoint parameters and response schemas.