Bare Bitcoin public API
Welcome to the Bare Bitcoin API documentation! Bare Bitcoin is a Bitcoin brokerage service available in Norway. This API is allows you to place orders, fetch price information, initiate bitcoin withdrawals as well as read out transaction data from your user.
Proceed to the endpoint explorer if you want to dig into the meat of the API!
Features
- Price data: Monitor current trading prices at the brokerage.
- Trading: Execute market and limit orders with low latency.
- Withdrawals: Initiate Bitcoin withdrawals securely to any onchain or Lightning destination.
- Ledger (Coming very soon): Access detailed transaction histories and balances via the Ledger API (documentation available).
- Deposits (Coming soon-ish): Receive bitcoin deposits to your Bare Bitcoin account
Stay tuned for updates as we expand our API capabilities to include comprehensive ledger support. For now, you can start building with trading and withdrawals to leverage Bare Bitcoin's core functionality.
Authentication
All authenticated endpoints utilize API keys. These can be created from within your profile settings on the signed-in section of our web platform.
API keys have two distinct parts:
- Public part. Starts with
bb/public/
. This should be included in thex-bb-api-key
header. The API key is confidential, but it's not the end of the world if it gets leaked. - Secret part. Starts with
bb/apisecret/
. This is very sensitive! It is critical that this value stays secret. The secret should be used to construct a so called HMAC. Other crypto exchanges typically refers to this as the signature.
Each request needs three different headers, that together form the authentication:
- API key (
x-bb-api-key
): the public part of your API key. - Nonce (
x-bb-api-nonce
): a positive integer you choose yourself. It has to increase for every request you make. You can typically set this to the current epoch UNIX timestamp. The purpose of this value is to make all API requests single-use. This makes it so you don't submit the same order twice by accident, for example. - HMAC (
x-bb-api-hmac
): an HMAC (or signature, as some people call it!), constructed using the secret part of your API key.
HMAC details
The HMAC you need to generate is defined the following way:
HMAC-SHA256 of (URI path + SHA256(nonce + request body)) and base64 decoded secret API key
Examples
The following is a specific example of a signature generated with a specific key, nonce, and request body corresponding to a new market order for 100 NOK. If your code produces a different HMAC (x-bb-api-hmac
) you have a bug in your code.
Field | Value |
---|---|
Secret | bb/apisecret/ZZavHDgVRyGowg8blKfPDDRlN3+6h0/vOUA |
Nonce | 1733314678 |
Body | {"type": "ORDER_TYPE_MARKET", "direction": "DIRECTION_BUY", "amount": 100} |
URI | /v1/orders |
Method | GET |
JavaScript (Node.js)
const crypto = require('crypto');
function createHmac(secret, { method, path, nonce, data }) {
// Encode data: nonce and raw data
const encodedData = `${nonce}${data.toString()}`;
// SHA-256 hash of the encoded data
const hashedData = crypto.createHash('sha256').update(encodedData).digest();
// Concatenate method, path, and hashed data
const message = Buffer.concat([
Buffer.from(method),
Buffer.from(path),
hashedData
]);
const decodedSecret = Buffer.from(secret, 'base64');
// Generate HMAC
const hmac = crypto.createHmac('sha256', decodedSecret);
hmac.update(message);
const macsum = hmac.digest();
// Return base64-encoded HMAC
return macsum.toString('base64');
}
const components = {
method: 'POST',
path: '/v1/orders',
nonce: 1733314678,
data: '{"type": "ORDER_TYPE_MARKET", "direction": "DIRECTION_BUY", "amount": 100}'
};
const secret = 'bb/apisecret/ZZavHDgVRyGowg8blKfPDDRlN3+6h0/vOUA';
const hmac = createHmac(secret, components);
console.log(`x-bb-api-hmac: ${hmac}`);
Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"slices"
)
type Components struct {
Method string // HTTP method
// URI path. If the request is for https://api.bb.no/v1/orders, this is "/v1/orders".
Path string
Nonce uint64
Data []byte // raw request data
}
func createHmac(secret string, components Components) (string, error) {
encodedData := fmt.Sprintf("%d%s", components.Nonce, string(components.Data))
summed := sha256.Sum256([]byte(encodedData))
message := slices.Concat([]byte(components.Method), []byte(components.Path), summed[:])
// The secret is actually a base64-encoded byte slice!
decodedSecret, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
return "", fmt.Errorf("invalid HMAC secret: %w", err)
}
mac := hmac.New(sha256.New, decodedSecret)
mac.Write(message)
macsum := mac.Sum(nil)
digest := base64.StdEncoding.EncodeToString(macsum)
return digest, nil
}
func main() {
components := Components{
Method: "POST",
Path: "/v1/orders",
Nonce: 1733314678,
Data: []byte(`{"type": "ORDER_TYPE_MARKET", "direction": "DIRECTION_BUY", "amount": 100}`),
}
secret := "bb/apisecret/ZZavHDgVRyGowg8blKfPDDRlN3+6h0/vOUA"
hmac, err := createHmac(secret, components)
if err != nil {
panic(err)
}
fmt.Printf("x-bb-api-hmac: %s\n", hmac)
}