Last updated

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:

  1. Public part. Starts with bb/public/. This should be included in the x-bb-api-key header. The API key is confidential, but it's not the end of the world if it gets leaked.
  2. 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:

  1. API key (x-bb-api-key): the public part of your API key.
  2. 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.
  3. 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.

FieldValue
Secretbb/apisecret/ZZavHDgVRyGowg8blKfPDDRlN3+6h0/vOUA
Nonce1733314678
Body{"type": "ORDER_TYPE_MARKET", "direction": "DIRECTION_BUY", "amount": 100}
URI/v1/orders
MethodGET

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)
}