# BitSpider REST API

Connect to BitSpider using REST API.

**Note that REST API is in BETA stage**

This document describes how to connect certain BitSpider features with your application.

## Quick start

Get the API user info
```text
GET https://api.bitspider.com/v1/user/me
Authentication: Bearer DM9gxEaiQUE5Bf3LO5GHk
```

Returns
```json
{
  "id": "86aa8be3261e426b8572cbe6add31d2a",
  "email": "test@bitspider.com",
  "registered": "2021-03-12T00:00:00Z"
}
```

cURL example:
```bash
curl -X GET -H "Authentication: Bearer DM9gxEaiQUE5Bf3LO5GHk" https://api.bitspider.com/v1/user/me
```

where `DM9gxEaiQUE5Bf3LO5GHk` is the API key for this short example.

## API basics

### Routing

Base URL for all routes
```text
https://api.bitspider.com/v1
```

### Authentication

Set the HTTP request header as
```text
Authentication: Bearer <token>
```
where the `<token>` is your API key.

Some security-critical actions require additional signature. The signature is based on a secret token known only by the client and the server and thus omitted in the transport layer.

The `X-Api-Signature` value is calculated by the following algorithm:
```text
Signature = BASE64( SHA256( requestBody + apiSecret ) )
```
where the `<requestBody>` is raw JSON string to be sent to the server and `<apiSecret>` your API secret.

Note that the [webhooks](#webhooks) are using another secret token.

To get your API key, API secret and webhook secret:
1. **Log in** with your credentials.
2. Go to the [User Profile](/user/profile) page.
3. Scroll down to the **API credentials** and copy-paste the **API key** and **API secret** to your application.

### Rate limit

API routes have predefined rate limit. Default is 1 request per second unless otherwise noted.

### Error handling

Response HTTP status codes:
* **400 Bad Request** - user should verify the input, usually due to input validation
* **401 Unauthorized** - user is not authenticated, either API key is missing or a register user not yet approved
* **403 Forbidden** - user has no access to the route, restricted permissions for the user
* **404 Not Found** - API route not found, please verify the route
* **409 Conflict** - server cannot handle the request due the current state of the resource
* **429 Too Many Requests** - number of requests exceeded the rate limit
* **500 Server Error** - generic server-side error

Response body properties:
* **error** - error message

Example of an error response:
```text
401 Unauthorized
```

```json
{
  "status": "error",
  "error": "API key is missing!"
}
```

## API routes

### Get payment requests

Get a list of payment requests:
```text
GET /merchant/payment
```

Authentication is required

Query string:
* **skip** - optional, number of records to skip, default: 0
* **take** - optional, maximum number of records to return, default: 100

Response body:
* **skip** - number of records to skip
* **take** - maximum number of records to return
* **count** - number of records returned in this response
* **total** - total number of available records in the database
* **items** - list of payment requests
* **items[n].id** - payment request id
* **items[n].userId** - id of the user who created the payment request
* **items[n].orderNumber** - sequential order number
* **items[n].publicAddress** - Bitcoin or Ethereum public address, depending on the `intermediatePlatform`
* **items[n].requestedCurrency** - currency of the requested amount, only `EUR` is possible at the moment
* **items[n].requestedAmount** - requested amount, decimal number
* **items[n].intermediatePlatform** - cryptocurrency platform, possible values are `bitcoin` or `ethereum`
* **items[n].intermediateCurrency** - currency for the transfer, possible values are `BTC`, `ETH`, `USDT`, `UNI`, `GALA`, `HT`
* **items[n].intermediateAmount** - amount to transfer, decimal number
* **items[n].offerExpires** - UTC date and time when the payment request expires
* **items[n].status** - payment request status: `pending`, `paid`, `completed`
* **items[n].created** - UTC date and time the payment request has been created
* **items[n].updated** - UTC date and time the payment request has been updated (status change)

Example of response body:
```json
{
  "skip": 0,
  "take": 100,
  "count": 2,
  "total": 2,
  "items": [
    {
      "id": "jNn848X3j9Xsofkki5phKpvXo9DraoM6eEibxD6eOf8qXMwJ",
      "userId": "86aa8be3261e426b8572cbe6add31d2a",
      "orderNumber": "2021-000002",
      "publicAddress": "tb1RasKESsuLxhHxDM36gaWkJeySAJelmp3fubj2LV",
      "requestedCurrency": "EUR",
      "requestedAmount": 120.0,
      "intermediatePlatform": "BTC",
      "intermediateCurrency": "BTC",
      "intermediateAmount": 0.0030802622339442605876325029,
      "offerExpires": "2021-03-15T22:26:20.709Z",
      "status": "pending",
      "created": "2021-03-15T22:11:20.709Z"
    },
    {
      "id": "grZGOciEJvefUQq078Y92OsCPDh8c1dwt8DUrs81EO0K",
      "userId": "86aa8be3261e426b8572cbe6add31d2a",
      "orderNumber": "2021-000001",
      "publicAddress": "0x4ae629865fda4325a14543069c280aa4da5d52df",
      "requestedCurrency": "EUR",
      "requestedAmount": 10.0,
      "intermediatePlatform": "ETH",
      "intermediateCurrency": "USDT",
      "intermediateAmount": 11.890606420927467300832342449,
      "intermediateCurrency": "ETH",
      "intermediateAmount": 0.1241591988794428340758321499,
      "offerExpires": "2021-01-21T13:47:11.306Z",
      "status": "completed",
      "created": "2021-01-21T13:17:11.306Z"
    }
  ]
}
```

### Get a specific payment request

Get a payment request by id:
```text
GET /merchant/payment/{id}
```

Authentication is required

Request parameter:
* **id** - payment request id

Response body:
* **id** - payment request id
* **userId** - id of the user who created the payment request
* **orderNumber** - sequential order number
* **publicAddress** - Bitcoin or Ethereum public address, depending on the `intermediatePlatform`
* **requestedCurrency** - currency of the requested amount, only `EUR` is possible at the moment
* **requestedAmount** - requested amount, decimal number
* **intermediatePlatform** - cryptocurrency platform, possible values are `bitcoin` or ˙ethereum˙
* **intermediateCurrency** - currency for the transfer, possible values are `BTC`, `ETH`, `USDT`, `UNI`, `GALA`, `HT`
* **intermediateAmount** - amount to transfer, decimal number
* **offerExpires** - UTC date and time when the payment request expires
* **status** - payment request status: `pending`, `paid`, `completed`
* **created** - UTC date and time the payment request has been created
* **updated** - UTC date and time the payment request has been updated (status change)

Example of response body:
```json
{
  "id": "jNn848X3j9Xsofkki5phKpvXo9DraoM6eEibxD6eOf8qXMwJ",
  "userId": "86aa8be3261e426b8572cbe6add31d2a",
  "orderNumber": "2021-000002",
  "publicAddress": "tb1RasKESsuLxhHxDM36gaWkJeySAJelmp3fubj2LV",
  "requestedCurrency": "EUR",
  "requestedAmount": 120.0,
  "intermediatePlatform": "bitcoin",
  "intermediateCurrency": "BTC",
  "intermediateAmount": 0.0030802622339442605876325029,
  "offerExpires": "2021-03-15T22:26:20.709Z",
  "status": "pending",
  "created": "2021-03-15T22:11:20.709Z"
}
```

### Estimate the price

Estimate the price in cryptocurrency before creating a new payment request:
```text
POST /merchant/estimate
```

Authentication is required

Request body:
* **requestedCurrency** - currency of the requested amount, only `EUR` is possible at the moment
* **requestedAmount** - requested amount, decimal number
* **intermediateCurrency** - currency for the transfer, possible values are `BTC`, `ETH`, `USDT`, `UNI`, `GALA`, `HT`

Example of request body:
```json
{
  "requestedCurrency": "EUR",
  "requestedAmount": 120.0,
  "intermediateCurrency": "BTC"
}
```

Example of response body:
```json
{
  "requestedCurrency": "EUR",
  "requestedAmount": 120.0,
  "intermediatePlatform": "bitcoin",
  "intermediateCurrency": "BTC",
  "intermediateAmount": 0.0030802622339442605876325029,
  "created": "2021-03-15T22:11:20.709Z"
}
```

### Create a new payment request

Create a payment request:
```text
POST /merchant/payment
```

Authentication is required

Limited to 30 requests per day

Request body:
* **requestedCurrency** - currency of the requested amount, only `EUR` is possible at the moment
* **requestedAmount** - requested amount, decimal number
* **intermediateCurrency** - currency for the transfer, possible values are `BTC`, `ETH`, `USDT`, `UNI`, `GALA`, `HT`

Example of request body:
```json
{
  "requestedCurrency": "EUR",
  "requestedAmount": 120.0,
  "intermediateCurrency": "BTC"
}
```

Example of response body:
```json
{
  "id": "jNn848X3j9Xsofkki5phKpvXo9DraoM6eEibxD6eOf8qXMwJ",
  "userId": "86aa8be3261e426b8572cbe6add31d2a",
  "orderNumber": "2021-000002",
  "publicAddress": "tb1RasKESsuLxhHxDM36gaWkJeySAJelmp3fubj2LV",
  "requestedCurrency": "EUR",
  "requestedAmount": 120.0,
  "intermediatePlatform": "bitcoin",
  "intermediateCurrency": "BTC",
  "intermediateAmount": 0.0030802622339442605876325029,
  "offerExpires": "2021-03-15T22:26:20.709Z",
  "status": "pending",
  "created": "2021-03-15T22:11:20.709Z"
}
```

### Cancel a payment request

Cancel a pending or expired payment request by id:
```text
DELETE /merchant/payment/{id}
```

Authentication is required

Request parameter:
* **id** - payment request id; note that the payment request must be in `pending` or `expired` state

Response body:
* **status** - success

Example of response body:
```json
{
  "status": "success"
}
```

### Get withdrawal requests

Get a list of payment requests:
```text
GET /merchant/withdrawal
```

Authentication is required

Query string:
* **skip** - optional, number of records to skip, default: 0
* **take** - optional, maximum number of records to return, default: 100

Response body:
* **skip** - number of records to skip
* **take** - maximum number of records to return
* **count** - number of records returned in this response
* **total** - total number of available records in the database
* **items** - list of withdrawal requests
* **items[n].amount** - requested amount, decimal number
* **items[n].currency** - currency of the requested amount, only `EUR` is possible at the moment
* **items[n].iban** - beneficiary IBAN number
* **items[n].bic** - beneficiary SWIFT/BIC code
* **items[n].status** - withdrawal request status: `pending`, `completed`
* **items[n].created** - UTC date and time the withdrawal request has been created
* **items[n].updated** - UTC date and time the withdrawal request has been updated (status change)

Example of response body:
```json
{
  "skip": 0,
  "take": 100,
  "count": 1,
  "total": 1,
  "items": [
    {
      "id": "602cd6c0f9fe3010777f587c",
      "iban": "EE461274176113655587",
      "bic": " ESTIXX1XXXX",
      "amount": 50.0,
      "currency": "EUR",
      "status": "completed",
      "created": "2021-02-17T08:41:36.702Z",
      "updated": "2021-02-17T08:41:46.643Z"
    }
  ]
}
```

### Get a specific withdrawal request

Get a withdrawal request by id:
```text
GET /merchant/withdrawal/{id}
```

Authentication is required

Request parameter:
* **id** - withdrawal request id

Response body:
* **id** - payment request id
* **amount** - requested amount, decimal number
* **currency** - currency of the requested amount, only `EUR` is possible at the moment
* **iban** - beneficiary IBAN number
* **bic** - beneficiary SWIFT/BIC code
* **status** - withdrawal request status: `pending`, `completed`
* **created** - UTC date and time the withdrawal request has been created

Example of response body:
```json
{
  "id": "602cd6c0f9fe3010777f587c",
  "iban": "EE461274176113655587",
  "bic": " ESTIXX1XXXX",
  "amount": 50.0,
  "currency": "EUR",
  "status": "completed",
  "created": "2021-02-17T08:41:36.702Z",
  "updated": "2021-02-17T08:41:46.643Z"
}
```

### Create a withdrawal request

Create a payment request:
```text
POST /merchant/withdrawal
```

Authentication is required

Beneficiary IBAN and SWIFT/BIC need be pre-configured on the [User Profile](/user/profile) page.

Request header:
* **X-Api-Signature** - required to be generated by client and sent to server for validation

Request body:
* **amount** - requested amount, decimal number
* **currency** - currency of the requested amount, only `EUR` is possible at the moment

Response body:
* **id** - withdrawal request id
* **status** - payment request status: `pending`, `paid`, `completed`
* **created** - UTC date and time the payment request has been created


Example of response body:
```json
{
  "amount": 50.0,
  "currency": "EUR"
}
```

```json
{
  "id": "60508612b3776a33c0d995cc",
  "status": "pending",
  "created": "2021-03-16T10:18:43.770118Z"
}
```

### Cancel a withdrawal request

Cancel a peding withdrawal request by id:
```text
DELETE /merchant/withdrawal/{id}
```

Authentication is required

Request parameter:
* **id** - withdrawal request id; note that the withdrawal request must be in `pending` state

Response body:
* **status** - success

Example of response body:
```json
{
  "status": "success"
}
```

### Get balance

Get user's balance
```text
GET /merchant/balance
```

Authentication is required

Response body:
* **balance** - available balance, i.e. how much is available for a user to withdraw
* **pending** - reserved funds, i.e. total amount of pending withdrawal requests
* **currency** - three-letter currency code corresponding to the balance, e.g. EUR

Example of response body:
```json
{
  "balance": 175.25,
  "pending": 50.0,
  "currency": "EUR"
}
```

### Get user info

Get user's profile
```text
GET /user/me
```

Authentication is required

Response body:
* **id** - id of the user
* **email** - user's e-mail address
* **registered** - UTC date and time the user has been registered, ISO 8601 format

Example of response body:
```json
{
  "id": "86aa8be3261e426b8572cbe6add31d2a",
  "email": "test@bitspider.com",
  "registered": "2021-03-12T00:00:00Z"
}
```

## Webhooks

Webhooks are used to report events and notifications to external applications. Unlike the REST API where client needs to ask the server for changes, webhooks on the other side trigger a HTTP request when an event occurs.

To register a webhook URL **log in** to BitSpider and open the **Profile** page. Scroll down to the **Webhooks** and set your webhook URL to receive events and notifications.

For example, if you set `https://www.example.com/webhook` the notification will be sent as
```text
POST https://www.example.com/webhook
User-Agent: BitSpiderWebhook/1.0
X-Webhook-Request: ...
X-Webhook-Signature: ...
```

The HTTP method will always be `POST` with the following payload structure:
* **requestId** - unique HTTP request id
* **event** - event name
* **stage** - current stage: `pending`, `running` or `completed`
* **status** - current status of the stage, e.g. `success`
* **message** - optional, message to the user as a string
* **data** - optional, additional data as an object
* **created** - UTC date and time the notification has been sent, ISO 8601 format

Including HTTP request headers:
* **User-Agent** - name of the notification service, e.g. `BitSpiderWebhook/1.0`
* **X-Webhook-Request** - request id
* **X-Webhook-Signature** - signature to verify authenticity of the sender; discard the request if signature is not matching

The `X-Webhook-Signature` value is calculated by the following algorithm:
```text
Signature = BASE64( SHA256( requestId + webhookSecret + webhookUrl ) )
```

Node.js example on how to generate a signature:
```js
//Parameters to build a signature
var webhookUrl = "https://www.example.com/webhook";
var webhookSecret = "oJEZUByXufera4yg6lZIm2edihdc11NV";
var requestId = "d1f131e43e914f1b8b714d02bd257204"; //X-Webhook-Request
var concatenated = requestId + webhookSecret + webhookUrl;

//Generate a SHA256 signature encoded as BASE64
var signature = require('crypto').createHash('sha256').update(concatenated).digest('base64');

//Expected signature: UCIQeNVGpvNG0BaAFKAtB8CKTRbom1f6loRNUD5aK9s=
console.log("X-Webhook-Signature: " + signature);
```

The complete webhook request should look like
```text
POST https://www.example.com/webhook
User-Agent: BitSpiderWebhook/1.0
X-Webhook-Request: d1f131e43e914f1b8b714d02bd257204
X-Webhook-Signature: UCIQeNVGpvNG0BaAFKAtB8CKTRbom1f6loRNUD5aK9s=
```

```json
{
  "requestId": "d1f131e43e914f1b8b714d02bd257204",
  "event": "test",
  "stage": "completed",
  "status": "success",
  "message": "This is a test webhook trigger.",
  "created": "2021-03-16T20:17:01.2855682Z"
}
```