Options
All
  • Public
  • Public/Protected
  • All
Menu

@bity/api

A simple to use interface to Bity's services.

Installation

npm install @bity/api

Profit sharing

Interested in profit sharing? To participate please read our guide.

NOTE: If an invalid client id is given, requests to create orders will be treated as if no client id was given at all.

Setup

Importing the library

The library can be used in TypeScript with:

import { BityApiClient } from "@bity/api";

The library can be used in JavaScript meant for NodeJS, Browserify, Webpack, etc. with:

const bityApi = require("@bity/api");
const BityApiClient = bityApi.BityApiClient;

You can also use the index.umd.js file standalone on a page. The following will add BityApi to the window object. Which for instance enables BityApiClient to be available via window.BityApi.BityApiClient.

<script src="path/to/bity-api/index.umd.js"></script>

Instantiating the client

The first step is to create an instance of the BityApiClient:

const bity = new BityApiClient({
  exchangeApiUrl: 'https://exchange.api.bity.com/v2/',
  clientId: 'my-client-id'
});

Now we're all ready to interact with Bity services!

Authentication

In @bity/api we introduce OAuth 2.0 - specifically, the authentication grant code part of the specification (RFC 6749), with the addition of the PKCE (RFC 7636) for safe client-side usage.

@bity/api tries its best to be extremely easy in regards to OAuth usage.

There are two typical use cases we expect:

  1. Authorizing and immediately using API calls without having to check they are returning from the service.
  2. Checking to see if a user is returning from the Bity OAuth2.0 service

The following code blocks are commented to better explain what is happening.

Use case 1

// Since we are passing an oauthConfig to BityApiClient, the client will now
// intelligently apply OAuth to all requests, auto-renew when needed, and
// on grant or refresh token expire, call onInvalidGrant which can be setup to
// auto-redirect the user to Bity's OAuth 2.0 service (by just calling the function
// passed to the event function).
const bity = new BityApiClient({
  exchangeApiUrl: 'https://exchange.api.bity.com/v2',
  clientId: 'your-client-id-if-you-have-one',
  oauthConfig: {
    authorizationUrl: 'https://connect.bity.com/oauth2/auth',
    tokenUrl: 'https://connect.bity.com/oauth2/token',
    clientId: 'your-client-id',
    scopes: ['https://auth.bity.com/scopes/exchange.place', 'https://auth.bity.com/scopes/exchange.history'],
    redirectUrl: 'http://your-redirect-url',
    onAccessTokenExpiry: (refreshAccessToken) => {
      // As a developer you don't really need to handle anything here. But don't
      // forget this section. If refreshAccessToken() is not called, tokens will
      // not auto-renew.
      console.log("Access token expired! Trying to get new token from re-using auth grant code.");
      return refreshAccessToken();
    },
    onInvalidGrant: (refreshAuthCodeOrRefreshToken) => {
      console.log("Auth grant or refresh token expired! Get a new authorization grant code.");
      // Normally call refreshAuthCodeOrRefreshToken(); which calls fetchAuthorizationCode().
      // But you can do whatever you want - maybe you want a user to press
      // a button that executes fetchAuthorizationCode() instead.
    }
  }
});

function authorize() {
  // Redirects user to Bity OAuth 2.0 service
  bity.fetchAuthorizationCode();
}

function createOrder function() {
  // Will automatically pass and renew tokens.
  bity.createOrder(...);
}

Be aware that even though @bity/api does a lot for the developer, rejected promises still need to be handled appropriately.

Use case 2

// Same as above
const bity = new BityApiClient(...);

// A function to do the initial authorization.
function authorize() { bity.fetchAuthorizationCode(); }

bity.isReturningFromAuthServer().then(hasReturned => {
    if (!hasReturned) {
      // Either we arent returning from the auth server, or there was no code
      // returned. It's probably appropriate to call bity.fetchAuthorizationCode()
      // here or tell users they need to authenticate, and have them press a
      // button.
    }

    bity.getAccessToken().then(({ token, scopes }) => {
      // Here you can check scopes. Alternatively you can call
      // bity.getGrantedScopes().
      // This contains the scopes the user has granted to the application.
      // In the case where the user has denied granting a specific scope the
      // application requires, here you would notify them. It's possible to tell if a
      // scope grant was denied by checking if the scope exists in the bity.scopes
      // array. The array's elements are just strings, which will look like:
      // https://auth.bity.com/scopes/some-scope
      location.replace('https://example.com/webapp');
    })
    .catch(error => {
      // More errors to handle.
    });
  })
  .catch(error => {
    // NOTE: Here we're just being generic about the type of authentication
    // grant error that has been returned.
    if (error instanceof ErrorAuthenticationGrant) { /* Handle it. */ }
  });

OAuth Errors list

To see a list of possible error classes that can be returned, please visit https://github.com/BitySA/oauth2-auth-code-pkce/blob/master/index.ts and search for ErrorOAuth2. The list is not included here so that this documentation doesn't need to synchronize with the @bity/oauth2-auth-code-pkce package.

Usage

The BityApiClientInterface shows all possible methods that can be run against our services. Since our API will continue to grow to support new features, such as authentication, it needs to be made clear how everything is expected to be used together.

The following are a few examples.

For most, they will want to simply make some orders against Bity's Exchange API. Before any orders can be made, the developer needs to answer some questions:

  1. How are orders created?
  2. How can I determine a possible order price (exchange rate)?
  3. How are orders placed?
  4. Where are the payment details for an order?
  5. What is the status of the order?

First we setup our client, and then we can do the following:

const mySendingAddr = 'some valid btc address';
const myReceivingAddr = 'some valid eth address';
function handleAnErrorThrownSomewhereInThisProcess(error) {
  console.error(error);
}

bity
  .then((new Order())                                              // 1
    .setInput('BTC', '0.01')
      .do((input) => input.setCryptoAddress(mySendingAddr))
    .setOutput('ETH')
      .do((output) => output.setCryptoAddress(myReceivingAddr))
    .generateObjectForOrderCreation())
  .then(preparedOrder => bity.fetchEstimateForOrder(preparedOrder) // 2
    .then(estimatedOrder => alert(estimatedOrder.output.amount))
    .then(() => bity.createOrder(preparedOrder))                   // 3
  .then(bity.fetchOrderWithUrl)                                    // 4 and 5!
  .then(createdOrder => alert(createdOrder.paymentDetails))
  .catch(handleAnErrorThrownSomewhereInThisProcess);

We can see the majority of the work is getting the information to create an order.

More information

More complex usage would be checking for pair availability with BityApiClientInterface.fetchPairs() or getting more information on a specific currency with BityApiClientInterface.fetchCurrencies(). Reading all the BityApiClientInterface methods will probably help you.

Test panel

To run the test panel, do the following:

  • make
  • make -C tests/panel serve

This will start serving a test panel, usually at http://localhost:8080/tests/panel.html . If you already have services running on this port, it will use the next available port number, and so on.

This panel allows you to quickly test authentication, order estimation, order creation and order history.

In order to test your particular setup and configuration values, modify tests/panel/test.js to fit your needs. Running make serve in the tests/panel directory will automatically re-browserify the js and serve the panel again.

Developer support

Please visit the #bity-exchange-api channel on matrix.org / riot.im. Your question will be answered within 24 hours, so please stick around. If this is not possible, please use our support chat bubble on https://bity.com.

Generated using TypeDoc