# 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" } ```