Bitbond Offering Manager API documentation
1.3.4

Base URL
https://client-subdomain.bitbond.net/api/v1

The Bitbond Offering Manager API provides resource endpoints for fetching projects, creating orders and payments and collecting KYC information about the investors.

The API requires a token based authentication. A bearer token will be provided by Bitbond that will need to be included in the 'Authentication' header for each request to the server, along with an HMAC 'X-Signature' header. The HMAC signature will be used to verify the authenticity of the sender and the integrity of the request in transit.

Authorization

API clients are authorized with bearer tokens. Tokens can be generated in the admin panel as a key/secret pair. Secret are used to build HMAC-SHA1 signatures on a client side.

Signature generation pseudo code

/**
 * HMAC a hashing function using SHA1 algorythm
 * @param   {String} secret     The secret used to hash the message
 * @param   {String} message    Message to be hashed
 * @return  {Bin}               Binary digest
 */
HMAC = func(secret, message)

/**
 * signatureKey returns derived key
 * @param   {String} secret     The secret from tokens key/secret pair.
 * @param   {String} date       UTC request date in YYYY-MM-DD format
 * @param   {String} method     Request method POST, GET, DELETE etc
 * @param   {String} path       Request path, e.g. /api/v1/access_tokens
 * @return  {Bin}               Derived key used to generate payload signature
 */
signatureKey = func(secret, date, method, path) {
    HMAC(HMAC(HMAC("bitbond" + secret, date), method), path)
}

/**
 * signature returns request signature
 * @param   {String} key        The secret from tokens key/secret pair.
 * @param   {String} payload    Raw request body
 * @return  {String}            Request signature
 */
signature = func(key, payload) {
    HMAC(key, payload).toString()
}

Example in JavaScript

import hmacSHA1 from 'crypto-js/hmac-sha1';

let generateSigningKey = (secret, dateStamp, method, path) => {
  let key = hmacSHA1(dateStamp, `bitbond${secret}`)
  key = hmac(method, key)
  key = hmac(path, key)
  return key
}

let dateStamp = (new Date()).toISOString().substring(0, 10)
let method = request.method
let path = request.url.getPathWithQuery()
let body = request.body && request.body.raw || ''
let signingKey = generateSigningKey(secret, dateStamp, method, path)
let signature = hmacSHA1(body, signingKey).toString()
Headers

To authorize API access this header needs to be added to the request.

Authorization: Bearer [token]
X-Signature: [signature]

Creating orders

To create an order the following necessities need to be met:
  • The current user needs to be approved. A user is approved automatically when they go through a successful video identification session. When a user is approved the approved_at is set to a non-null value and the approved attribute is set to true.
  • An order can only be created for a live project. A live project has its start_date before now and its end_date after.
  • The investment terms need to be accepted by a user for the project they want to invest into. The investment terms are accepted by user for a project by successfully creating terms through the investment_terms endpoint.
  • The order amount must be greater than the project minimum required investment amount.

Creating users The locale attribute takes en or de as values, with en being set by default when no value is specified.

When an order is created it will have status new and a unique order code will be generated. The order code will be used as a reference code when sending payments. Once a new payment is created, the details of the payment are analysed and the order status changes accordingly to paid, if the amount sent matches the order, underpaid, if the amount sent is lower than the order and overpaid if the amount sent is larger than the order. An order can also have status cancelled, either by admin action or by user action. When an order distribution on the blockchain is initiated the order status changes to settled.

Creating identities

An identity contains personal data about a user. Identities are of many types ranging from individuals, legal representatives, and business owners. They share common attributes described in the Identity model. Generally an individual investor will have one identity that collects information regarding contact details, citizenship and taxes. A business investor will hold one legal representative, that will need to be kyc-ed via video identification, and multiple business owners.

VIDEO IDENTIFICATION FLOW

The video identification process is handled through IDnow, as the video identification provider.

There are a few requirements to be able to start a video identification process:

  • an identity needs to be created with contact data and financial information POST /users/{user_id}/identities
  • an address needs to be added for the identity POST /users/{user_id}/identities/{identity_id}/addresses
  • the bank account details need to be filled in for the user POST /users/{user_id}/bank_accounts
  • the identity terms need to be create for the identity POST /users/{user_id}/identities/{identity_id}/identity_terms

If a video identification session is attempted without the above requirements to be met, an error will be thrown.

There are two steps to perform a video identification session:

  • Initiate the session by making a POST request to the /kyc/identities/{identity_id}/video_identifications endpoint
  • Make a GET request to the /kyc/identities/{identity_id}/video_identifications/{id} endpoint to verify the video_identifications object has the idnow_id and the redirect_url attributes filled in. A polling mechanism might be needed to fetch the latest data.

When the redirect_url attribute is present, the user can be redirected to their video provider (IDnow) session. Once the user goes through the video identification session, a webhook is triggered to synchronize data from the video provider (IDnow) to Bitbond. In order to check the status of the video session make a GET request to the /kyc/identities/{identity_id}/video_identifications/{id} endpoints to verify the object has the status attribute filled in.

The video_identifications object can be accessed through the /identities/{id} endpoint as well.

IMPORTANT NOTE: On staging, the video identification provider (IDnow) does not automatically trigger the webhook to synchronize data on Bitbond's side, therefore the video_identification object status attribute will never be updated.

At the moment, upon going through the video identification session, the user is not redirected back into the investor application. This feature is work in progress.

Webhooks

Webhook URLs can be added through Admin frontend application. API will automatically retry a webhook if the response status code will be anything other than 200. Webhooks are called with payload in POST request body when the following events happen:

  • distribution_created
    • Is triggered when distribution to Blockchain was processed.
  • kyc_approved
    • Is triggered after successfull auto-approval process when investor finishes the KYC process.
  • kyc_rejected
    • Is triggered when admin user rejects the investor in Asset Manager
  • kyc_video_identification_success
    • Is triggered after the investor goes through a successful IDNOW KYC process.
    • Is tiggered when KYC process is mocked using Asset Manager Labs section (does not apply to production)
  • order_created
    • Is triggered when the endpoint POST /users/:user_id/projects/:project_id/orders is used and after a new order is successfully created.
  • order_status_changed
    • Is triggered when status of an order is updated manually
    • Is triggered when payment is created and order status is changed
  • project_prepared_for_distribution
    • Is triggered when project has done a preparation for distribution cycle.
  • transaction_created (WIP)
Webhook payloads
  • distribution_created
{
  event: 'distribution_created',
  order_id: {String} UUID,
  user_id: {String} UUID,
  project_id: {String} UUID,
}
  • kyc_approved
{
  event: 'kyc_approved',
  user_id: {String} UUID
}
  • kyc_rejected
{
  event: 'kyc_rejected',
  user_id: {String} UUID
}
  • kyc_video_identification_success
{
  event: 'kyc_video_identification_success',
  user_id: {String} UUID
}
  • order_created
{
  event: 'order_created',
  order_id: {String} UUID,
  user_id: {String} UUID,
  project_id: {String} UUID,
}
  • order_status_changed
{
  event: 'order_status_changed',
  order_id: {String} UUID,
  user_id: {String} UUID,
  project_id: {String} UUID,
  status: {String},
}
  • project_prepared_for_distribution
{
  event: 'project_prepared_for_distribution',
  project_id: {String} UUID,
  code: {String},
  percentage: {Number}
}
  • transaction_created (WIP)
{
  event: 'transaction_created',
  transaction_id: {String} UUID,
  custody_account_holder_id: {String} UUID,
  custody_account_id: {String} UUID,
  user_id: {String} UUID
}

This is the documentation for version 1.3.4 of the API. Last update on Jan 23, 2023.