diff --git a/README.md b/README.md
index 26396865..910a1206 100644
--- a/README.md
+++ b/README.md
@@ -1,160 +1,113 @@
-
+
-This document describes the API calls available as part of the Paytunia v1 API.
-The API is shared by both [Bitcoin-Central.net](https://bitcoin-central.net) and [Paytunia.com](https://paytunia.com). Both apps run against the same database, therefore using the API against one of them is equivalent to using the API against the other.
+**NEW: Our sandbox environment is now available, visit [sandbox.paymium.com](https://sandbox.paymium.com) (you may have to add a security exception for the SSL certificate to validate).**
-If your language of choice is Ruby we recommend using the [Paytunia gem](https://github.com/paytunia/paytunia) instead of writing your own client.
+The Paymium API allows developers to extend the capabilities of the Paymium platform, from reading the latest ticker to automating trades with bots.
-## Table of contents
-
-- [**General API description**](#general-api-description)
-
- - [Authentication](#authentication)
- - [Base URL](#base-url)
- - [Formats and required HTTP request headers](#formats-and-required-http-request-headers)
- - [Rate-limiting](#rate-limiting)
- - [Pagination](#pagination)
- - [HTTP response header](#http-response-header)
- - [Controlling pagination](#controlling-pagination)
- - [Localization](#localization)
- - [Error handling](#error-handling)
- - [Successful calls](#successful-calls)
-
-
-
-- [**API Calls**](#api-calls)
-
- - [Account](#account)
- - [Get balances (A)](#get-balances-a)
-
- - [Account operations](#account-operations)
- - [Get the detail of an account operation (A)](#get-the-details-of-an-account-operation-a)
- - [Get a list of account operations (A,P)](#get-a-list-of-account-operations-ap)
-
- - [Send money](#send-money)
- - [Send Bitcoins (A)](#send-bitcoins-a)
- - [Send money to an e-mail address (A)](#send-money-to-an-e-mail-address-a)
-
- - [Quotes](#quotes)
- - [Create a quote (A)](#create-a-quote-a)
- - [View a quote (A)](#view-a-quote-a)
- - [List quotes (A,P)](#list-quotes)
- - [Pay a quote (A)](#pay-a-quote-a)
- - [Execute a quote (A)](#execute-a-quote-a)
-
- - [Invoices](#invoices)
- - [View an invoice (A)](#view-an-invoice-a)
- - [View an invoice (Public)](#view-an-invoice-public)
- - [List invoices (A,P)](#list-invoices-ap)
- - [Create an invoice (A)](#create-an-invoice-a)
- - [Payment buttons and creation through signed GET request](#payment-buttons-and-creation-through-signed-get-request)
- - [Payment callbacks](#payment-callbacks)
-
- - [Trading](#trading)
- - [Place an order (A)](#place-an-order-a)
- - [Cancel an order (A)](#cancel-an-order-a)
- - [View trades for an order (A)](#view-trades-for-an-order-a)
- - [View an order (A)](#view-an-order-a)
- - [List active orders (A,P)](#list-active-orders-ap)
- - [List all orders (A,P)](#list-all-orders-ap)
- - [Read the ticker](#read-the-ticker)
- - [Read the market depth](#read-the-market-depth)
- - [Read historical trades](#read-historical-trades-p)
-
- - [Coupons](#coupons)
- - [Create a coupon (A)](#create-a-coupon-a)
- - [View a coupon](#view-a-coupon)
- - [Redeem a coupon (A)](#redeem-a-coupon-a)
-
-
-
- - [**Appendix**](#appendix)
- - [Codes and types tables](#codes-and-types-tables)
- - [Currencies](#currencies)
- - [Operation types](#operation-types)
-
- - [States](#states)
- - [Transfer (Bitcoin transfer, Wire transfers) statuses](#transfer-bitcoin-transfer-wire-transfer-statuses)
- - [Coupon statuses](#coupon-statuses)
- - [E-mail transfer statuses](#e-mail-transfer-statuses)
- - [Invoice statuses](#invoice-statuses)
- - [Trade order statuses](#trade-order-statuses)
-
-
-# General API description
-
-## Authentication
-
-Calls that require authentication are marked with "A" in the call description title.
-
-Authentication and authorization may be done with :
-
- - HTTP Basic
- - [OAuth2](http://oauth.net/2/)
-
-OAuth2 is useful when it is not desirable for client apps to handle the user's credentials directly or when it is necessary to have access to an account with limited privileges.
+**IMPORTANT NOTE**: Your API client must support [SNI](http://en.wikipedia.org/wiki/Server_Name_Indication) in order to not receive certificate name mismatch warnings.
-Each API call description mentions the OAuth2 scope required to use it.
+Is is possible to, among other things:
-The available OAuth2 scopes are :
+* Access public data (ticker, asks, bids, trades, etc...)
+* Authenticate users with their permission using OAuth2 *
+* Access authenticated user balances, trades, and other data *
+* Automate trading *
-| Scope | Description |
-|----------|------------------------------------------------------------------------------------|
-| read | Read transaction history, balances and profile information |
-| withdraw | Perform API calls that result in money being sent or withdrawn from the account |
-| trade | Manage trade orders (create, read, cancel) |
-| merchant | Manage invoices, read merchant dashboard and data |
-| devices | Manage devices |
+_* Authenticating users is only available to developers that have a fully verified and approved Paymium account. On the other hand, public data is available to everyone_
-In order to test OAuth2 integration a test app is available.
-
-| Application parameter | Value |
-|-----------------------|--------------------------------------------------------------------|
-| Application ID | `6fcf1c32f6e14cd773a7a6640832bdbf83a5b2b8d4382e839c6aff83a8f1bb3b` |
-| Application secret | `55554ecad5627f0465034c4a116e59a38d9c3ab272487a18404078ccc0b64798` |
-| Callback URL | `urn:ietf:wg:oauth:2.0:oob` |
+## Table of contents
-After authorization the authorization token will be directly displayed in your browser (that's what the special test callback URL is for).
+* [**General information**](#general-information)
+ * [Formats and required HTTP request headers](#formats-and-required-http-request-headers)
+ * [Localization](#localization)
+ * [Error handling](#error-handling)
+ * [Successful calls](#successful-calls)
+ * [Rate-limiting](#rate-limiting)
+
+* [**Authentication**](#authentication)
+ * [Permissions](#permissions)
+ * [OAuth2 authentication](#oauth2-authentication)
+ * [Token authentication](#token-authentication)
+
+* [**Public data**](#public-data)
+ * [Countries](#countries)
+ * [Ticker](#ticker)
+ * [Latest trades](#latest-trades)
+ * [Market depth](#market-depth)
+ * [Bitcoin-Charts endpoints](#bitcoin-charts-endpoints)
+ * [WebSocket](#websocket)
+ * [FIX streaming API](#fix-streaming-api)
+
+* [**User data**](#user-data)
+ * [User info](#user-info)
+ * [User activity](#user-activity)
+ * [Order details](#order-details)
+ * [Trading](#trading)
+ * [Withdrawing](#withdrawing)
+ * [Sending money](#sending-money)
+ * [Requesting money by e-mail](#requesting-money-by-e-mail)
+ * [Canceling orders](#canceling-orders)
+ * [Bitcoin addresses](#bitcoin-addresses)
+ * [Price alerts](#price-alerts)
+
+* [**Merchant API**](#merchant-api)
+ * [Payment creation](#payment-creation)
+ * [Payment callbacks](#payment-callbacks)
+ * [Get payment information](#get-payment-information)
+ * [E-commerce frameworks plugins](#e-commerce-frameworks-plugins)
+
+* [**Appendix**](#appendix)
+ * [Currencies](#currencies)
+ * [Order types](#order-types)
+ * [Order properties](#order-properties)
+ * [Order states](#order-states)
+ * [Payment states](#payment-states)
+ * [Account operation properties](#account-operation-properties)
+ * [Ruby example](#ruby-example)
+
+## General information
+
+### Formats and required HTTP request headers
-**Example authorization link :** [https://bitcoin-central.net/oauth/authorize?client_id=6...pe=code](https://bitcoin-central.net/oauth/authorize?client_id=6fcf1c32f6e14cd773a7a6640832bdbf83a5b2b8d4382e839c6aff83a8f1bb3b&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code)
+The API will only answer with JSON or empty responses. It expects parameters to be passed in JSON with the correct `Content-Type: application/json` being set.
-**Full usage example :**
+## Localization
-This example uses the OAuth2 Ruby gem.
+The relevant results and error messages will be localized to the language associated to the user, currently English and French are supported.
-```
-require 'oauth2'
+## Datetime formats
-client = OAuth2::Client.new('6fcf1c32f6e14cd773a7a6640832bdbf83a5b2b8d4382e839c6aff83a8f1bb3b', '55554ecad5627f0465034c4a116e59a38d9c3ab272487a18404078ccc0b64798', site: 'https://bitcoin-central.net')
-
-client.auth_code.authorize_url(redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', scope: 'read trade')
- => "https://bitcoin-central.net/oauth/authorize?response_type=code&client_id=6fcf1c32f6e14cd773a7a6640832bdbf83a5b2b8d4382e839c6aff83a8f1bb3b&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=read+trade"
+Datetime values will be returned as regular JSON format and Unix timestamps, the timestamps are suffixed with `_int`.
-# Visit this URL in your browser, approve the request and copy the authorization code
+## Error handling
-authorization_code = '...'
+Whenever an error is encountered, the answer to a JSON API call will have:
-token = client.auth_code.get_token(authorization_code, redirect_uri: 'urn:ietf:wg:oauth:2.0:oob')
+ * An HTTP 422 status (Unprocessable entity) or HTTP 400 (Bad request)
+ * A JSON array of localized error messages in the `errors` attribute of the response body
-token.get('/api/v1/trade_orders/active').body
+##### Example:
-=> [{"uuid":"148ab996-ab63-45cc-b240-99c78bb18a11","instructed_amount":300.0,"amount":268.70563158,"state":"active","created_at":"2013-02-07T19:09:44+01:00","updated_at":"2013-02-14T13:12:00+01:00","price":15.9199,"type":"buy"}]
+```json
+{
+ "errors": [
+ "Operations account operations amount is greater than your available balance (1781.96 EUR)"
+ "Amount can't be greater than your limit (1781.96 EUR)"
+ ]
+}
```
-If you encounter SSL certificate errors while trying this example it's probably because your Ruby install doesn't know where to find the CA certificates. In development you can use an incredibly ugly hack to temporarily skip SSL certificate validation : `OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE`. You should never do this in production.
-
-## Base URL
-
-The base URL for all calls is `https://bitcoin-central.net`. A complete URL would look like this `https://bitcoin-central.net/api/v1/quotes/3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d`.
+## Successful calls
-## Formats and required HTTP request headers
+If the API call was successful, the platform will answer with:
-The API will only answer with JSON or empty responses. It expects parameters to be passed in JSON with the correct `Content-Type: application/json` being set.
+ * An HTTP 200 status (OK) or HTTP 201 (Created),
+ * A JSON representation of the entity being created or updated if relevant
-## Rate-limiting
+### Rate-limiting
-API calls are rate-limited by IP to 5000 calls per day. Information about the status of the limit can be found in the `X-RateLimit-Limit` and `X-RateLimit-Remaining` HTTP headers.
+API calls are rate-limited by IP to 86400 calls per day (one per second on average). Information about the status of the limit can be found in the `X-RateLimit-Limit` and `X-RateLimit-Remaining` HTTP headers.
**Example response with rate-limit headers**
@@ -164,1519 +117,1267 @@ API calls are rate-limited by IP to 5000 calls per day. Information about the st
X-Ratelimit-Remaining: 4982
Date: Wed, 30 Jan 2013 12:08:58 GMT
+## Authentication
-## Pagination
-
-Some API calls returning collections may be paginated. In this case the call description title mentions it.
-
-Calls that return paginated data are marked with "P" in the call description title.
-
-### HTTP response header
-
-Calls that return paginated collections will add a `Pagination` HTT header to the response. It will contain a pagination meta-data JSON object.
-
-**Pagination header example**
-
- {
- // Whether the current page is the first of the collection
- "first_page": true,
-
- // Total amount of available pages
- "total_pages": 1,
-
- // Previous page number
- "previous_page": null,
-
- // Total number of items in the collection
- "total": 1,
-
- // Next page number
- "next_page": null,
-
- // Whether the current page is the last available one
- "last_page": true,
-
- // Record collection offset
- "offset": 0
- }
-
-### Controlling pagination
-
-Optional pagination parameters may be passed in the request URI in order to control the way the collection gets paginated. If parameters are incorrect a HTTP 400 Bad request status is returned along with an empty body.
-
-| Parameter | Default | Acceptable values |
-|-----------|---------|--------------------------------|
-| page | 1 | Positive integer >0 |
-| per_page | 20 | Positive integer >=5 and <=100 |
-
-## Localization
-
-The relevant results and error messages will be localized to the language associated to the user, currently English and French are supported.
-
-## Datetime formats
+### Permissions
-Datetime values will be returned as regular JSON format and Unix timestamps, the timestamps are suffixed with `_int`.
+Before you request authorization to access a user's account, you must decide which permissions, or scopes you would like to access.
-## Error handling
+The following scopes are available:
-Whenever an error is encountered, the answer to a JSON API call will have :
+| name | description |
+|----------------|-------------------------------------------------------------------------------------------|
+| basic | Read account number, language, and balances (default) |
+| activity | Read trade orders, deposits, withdrawals, and other operations |
+| trade | Create and cancel trade orders |
+| withdraw | Request EUR and BTC withdrawals (requires email confirmation from users upon withdrawing) |
+| deposit | List bitcoin deposit addresses and create a new one if needed |
+| merchant | Create and manage an account's invoices |
- * An HTTP 422 status (Unprocessable entity) or HTTP 400 (Bad request),
- * A JSON array of localized error messages as body
+### Token authentication
-## Successful calls
+This authentication mechanism is the recommended method if you need to access your own account data and is also referred to as **HMAC authentication**, if you need to access other users accounts on their behalf you'll need to use the OAuth2 authentication method.
-If the API call was successful, the platform will answer with :
+##### Generating a token
- * An HTTP 200 status (OK) or HTTP 201 (Created),
- * A JSON representation of the entity being created or updated if relevant
+For this authentication method you need to generate a token/secret pair that you will use to make requests against our API. In order to do so visit the "API tokens" menu in your account profile and click on "Create token". You will be presented with the following screen that will enable you to select the desired access permissions for this token. For security reasons you will need to confirm your access credentials.
+
-# API Calls
+Once your token is created you'll be presented **once** with the matching secret key, this secret key is only displayed once, you need to record it carefully. If the secret key is lost the token becomes useless.
-## Account
+##### Making requests
-### Get balances (A)
+Once you have an API token and its matching secret key you can use them to make requests against our API. In order to do so you must include three HTTP headers that will authenticate your request.
-This call will return the balances in all currencies.
+```bash
+$ curl "https://paymium.com/api/v1/user" \
+ --header "Api-Key: " \
+ --header "Api-Signature: " \
+ --header "Api-Nonce: " \
+```
-This call requires the `read` OAuth2 scope.
+ * The **API key** is the token that is displayed when listing your currently active tokens,
+ * The **API signature** is the hexdigest of the HMAC-SHA256 hash of the nonce concatenated with the full URL and body of the HTTP request, encoded using your API secret key,
+ * The **nonce** is a positive integer number that must increase with every request you make
-**Request path :** `/api/v1/balances`
+### OAuth2 authentication
-**Request method :** `GET`
+This authentication mechanism is best suited to cases where a developer publishes an app that requires access its users Paymium accounts.
-**Request parameters**
-
-_None_
+Many programming languages already have libraries to develop clients that connect to OAuth2 APIs, hence the following steps may not be necessary. For instance, if you are a Ruby developer, you can use [this example to get started](#ruby-example).
-**Response**
+The process can be summarized as follows:
-A JSON object with the following attributes is returned :
+1. Send the user to your application's authorization URL
+2. Receive the authorization code if the user accepted the request
+3. Get an access token and a refresh token from the authorization code
+4. Refresh the access token when needed
-| Name | Type | Description |
-|------|----------|-------------|
-| EUR | Decimal | EUR balance |
-| USD | Decimal | USD balance |
-| GBP | Decimal | GBP balance |
-| BTC | Decimal | BTC balance |
-
-**Example request :** `GET /api/v1/balances`
+##### Requesting user authorization
-**Example response :**
-
- {
- "EUR" : 1.0,
- "BTC" : 1.42,
- "USD" : 0.0,
- "GBP" : 0.0
- }
-
-## Account operations
+To get user's permission to use his/her account, you must send him/her to your application's redirect URI. You can see this URI by visiting your application's page: [https://paymium.com/page/developers/apps](https://paymium.com/page/developers/apps).
-An account operation is any ledger operation that changes the account's balance.
+By default, the `basic` scope will be requested.
-These calls require the `read` OAuth2 scope.
+If your application requires specific access scopes, you must append a scope GET parameter to the authorization URI:
-### Get the details of an account operation (A)
-
-This call will return the details of a single account operation, the response contains : the UUID identifying the operation, the amount of this particular operation, its currency, its creation timestamp, its state (if relevant), a string indicating the type of the operation and the account balance that this operation led to (the sum of all transactions in the same currency including this one but not the ones that came after it).
+ https://paymium.com/...&scope=basic+activity+trade
-**Request path :** `/api/v1/account_operations/{uuid}`
+The user will then be prompted to authorize your application with the specified scopes.
-**Request method :** `GET`
+##### Receiving the authorization code
-**Request parameters**
+If you specified the test redirection URI `https://paymium.com/page/oauth/test`, the user will be presented the autorization code upon accepting your request which can be used by the application to fetch access tokens.
-| Name | Type | Description |
-|------|------|-------------------------------|
-| uuid | UUID | UUID of the account operation |
+Otherwise the code or error will be sent to the redirection URI so that your application can retrieve it (in this case `https://example.com/callback`):
-**Response**
+ https://example.com/callback?code=AUTHORIZATION_CODE
-A JSON object with the following attributes is returned :
+Or if the request was denied by the user:
-| Name | Type | Description |
-|------------|----------|---------------------------------------------------|
-| uuid | UUID | UUID of the account operation |
-| amount | Decimal | Amount of the operation (1) |
-| currency | String | Currency of the operation (2) |
-| created_at | Datetime | Timestamp of operation creation |
-| state | String | Operation state if relevant, `null` otherwise (3) |
-| type | String | Operation type (4) |
-| balance | Decimal | Balance this operation led to |
+ https://example.com/callback?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.
- 1. Credits are expressed as positive amounts, debits are expressed as negative amounts
- 2. See currencies table
- 3. See states table
- 4. See operation types table
-
-**Example request :** `GET /api/v1/account_operations/3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d`
+The authorization code is valid 5 minutes.
-**Example response :**
-
- {
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d",
- "amount" : 50.0,
- "currency" : "EUR",
- "created_at" : "2013-01-14T16:28:57Z",
- "created_at_int" : 1363858355,
- "state" : null,
- "type" : "wire_deposit",
- "balance" : 550.0
- }
-
-### Get a list of account operations (A,P)
-
-This call will return a paginated list of account operations relative to the authenticated account.
+##### Fetching an access token and a refresh token
-**Request path :** `/api/v1/account_operations`
+Once your application received the authorization code, it can request an access token and a refresh token:
-**Request method :** `GET`
+```bash
+$ curl "https://paymium.com/api/oauth/token" \
+ -d "client_id=APPLICATION_KEY" \
+ -d "client_secret=APPLICATION_SECRET" \
+ -d "grant_type=authorization_code" \
+ -d "redirect_uri=REDIRECT_URI" \
+ -d "code=AUTHORIZATION_CODE"
+```
-**Request parameters**
+```json
+{
+ "access_token": "ACCESS_TOKEN",
+ "token_type": "bearer",
+ "expires_in": 1800,
+ "refresh_token": "REFRESH_TOKEN",
+ "scope": "basic"
+}
+```
-_None_
+An access token can be used to authorize user requests for the approved scopes and is valid 30 minutes.
-**Response**
+##### Refreshing the access token
-A JSON array of account operations is returned. The structure collection elements is detailed at "Get the details of an account operation".
-
-**Example request :** `GET /api/v1/account_operations`
+Since an access token is only valid 30 minutes, your application may need to fetch a new access token using the refresh token:
-**Example response :**
-
- [
- {
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d",
- "amount" : 50.0,
- "currency" : "EUR",
- "created_at" : "2013-01-14T16:28:57Z",
- "created_at_int" : 1363858355,
- "state" : null,
- "type" : "wire_deposit",
- "balance" : 550.0
- },
- {
- "uuid" : "b3c08962-4dc3-9ffc-4dc3-3a7bc1b2ff4d",
- "amount" : 500.0,
- "currency" : "EUR",
- "created_at" : "2013-01-10T12:45:50Z",
- "created_at_int" : 1363858355,
- "state" : null,
- "type" : "wire_deposit",
- "balance" : 500.0
- }
- ]
+```bash
+$ curl "https://paymium.com/api/oauth/token" \
+ -d "client_id=APPLICATION_KEY" \
+ -d "client_secret=APPLICATION_SECRET" \
+ -d "grant_type=refresh_token" \
+ -d "redirect_uri=REDIRECT_URI" \
+ -d "refresh_token=REFRESH_TOKEN"
+```
-## Send money
+```json
+{
+ "access_token": "NEW_ACCESS_TOKEN",
+ "token_type": "bearer",
+ "expires_in": 1800,
+ "refresh_token": "NEW_REFRESH_TOKEN",
+ "scope": "basic"
+}
+```
-These calls require the `withdraw` OAuth2 scope.
+After refreshing the access token, the previous tokens (access and refresh) are no longer valid.
-### Send Bitcoins (A)
+## Public data
-This call will perform a Bitcoin transaction.
+Public data (ticker, asks, bids, trades) can be accessed without registering an application.
-**Request path :** `/api/v1/transfers/send_bitcoins`
+### Countries
-**Request method :** `POST`
+##### Description
-**Request parameters**
+Read the list of countries, we currently serve the residents of countries for which the `accepted` flag is set to `true`.
-| Name | Type | Description |
-|---------|---------|-----------------------------|
-| amount | Decimal | Amount to send |
-| address | String | Recipient's Bitcoin address |
+##### Endpoint
-**Response**
+| method | path | authorization |
+|--------|-------------------------|---------------|
+| GET | /api/v1/countries | not required |
-An `UUID` is returned after the request is queued for execution. It enables the client to make subsequent status check requests.
-
-**Example request :** `POST /api/v1/transfers/send_bitcoins`
+##### Example
- {
- "amount" : 10.0,
- "address" : "1KfNzSKFAmpC4kNYaGLqj8LGPHxGmRG2nZ"
- }
+```bash
+$ curl https://paymium.com/api/v1/countries
+```
-**Example response :**
-
- {
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d"
- }
+```json
+[
+ {
+ "id": 76,
+ "accepted": true,
+ "iso_alpha2": "FR",
+ "iso_alpha3": "FRA",
+ "iso_numeric": 250,
+ "name_en": "France",
+ "name_fr": "France",
+ "telephone_code": 33
+ },
+ {
+ "id": 157,
+ "accepted": true,
+ "iso_alpha2": "NL",
+ "iso_alpha3": "NLD",
+ "iso_numeric": 528,
+ "name_en": "Netherlands",
+ "name_fr": "Pays-Bas",
+ "telephone_code": 31
+ }
+]
+```
-### Send money to an e-mail address (A)
+### Ticker
-This call will move money to the account identified with the given e-mail address. If no such account is found an e-mail gets sent inviting its recipient to create an account, or sign-in to one to retrieve the sent funds. If the amount isn't claimed after a week the funds are returned to the sender.
+##### Description
-**Request path :** `/api/v1/transfers/send_to_email`
+Read the latest ticker data.
-**Request method :** `POST`
+##### Endpoint
-**Request parameters**
+| method | path | authorization |
+|--------|-------------------------|---------------|
+| GET | /api/v1/data/eur/ticker | not required |
-| Name | Type | Description |
-|----------|---------|-------------------------------------------|
-| amount | Decimal | Amount to send |
-| currency | String | Currency in which the amount is expressed |
-| address | String | Recipient's e-mail address |
+##### Example
-**Response**
+```bash
+$ curl https://paymium.com/api/v1/data/eur/ticker
+```
-An `UUID` is returned after the request is queued for execution. It enables the client to make subsequent status check requests.
-
-**Example request :** `POST /api/v1/transfers/send_bitcoins`
+```json
+{
+ "high": 720.0,
+ "low": 640.0001,
+ "volume": 198.16844745,
+ "bid": 676.01,
+ "ask": 679.9999999,
+ "midpoint": 678.00499995,
+ "at": 1389092410,
+ "price": 680.0,
+ "vwap": 679.87459,
+ "variation": -5.5556,
+ "currency": "EUR"
+}
+```
- {
- "amount" : 10.0,
- "currency" : "EUR",
- "address" : "david@bitcoin-central.net"
- }
+##### Properties
-**Example response :**
-
- {
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d"
- }
+| name | description | example value |
+|--------------|----------------------------------------------|---------------------------|
+| currency | currency | "EUR" |
+| at | timestamp | 1389092410 |
+| price | price of latest trade | 680.0 |
+| bid | bid price | 676.01 |
+| ask | ask price | 679.9999999 |
+| midpoint | midpoint price | 678.00499995 |
+| volume | 24h volume | 198.16844745 |
+| variation | 24h variation (percentage) | -5.5556 |
+| high | 24h high price | 720.0 |
+| low | 24h low price | 640.0001 |
+| vwap | 24h volume-weighted average price | 679.87459 |
-## Quotes
+### Latest trades
-Quotes are a mechanism for clients to send funds or exchange them to other currencies. They provide clients with a guaranteed fixed-rate at which the system will convert their funds before crediting them to their account or send them out.
+##### Description
-The canonical use of a quote is to pay in currency to a Bitcoin invoice, materialized as a QR code :
+Read the latest executed trades.
- 1. User scans Bitcoin QR code
- 2. Client app extracts requested Bitcoin amount
- 3. Client app requests a quote for this Bitcoin amount to the API and provides the currency in which debit upon quote payment
- 4. A guaranteed rate is returned by the API
- 5. Client app shows price expressed in the user's currency
- 6. After user confirmation the client app instructs the API to pay the quote to a specific Bitcoin address
- 7. The merchant receives the payment in Bitcoin and the user is debited in his native currency
-
-These calls require the `trade` OAuth2 scope, the [Pay a quote](#pay-a-quote-a) action requires the `withdraw` scope.
+##### Endpoint
-### Create a quote (A)
+| method | path | authorization |
+|--------|-------------------------|---------------|
+| GET | /api/v1/data/eur/trades | not required |
-This call will create a quote. When doing so clients must specify a currency (the other currency is always assumed to be "BTC") an amount they are requesting and a direction. Combining these parameters in various ways will have the system address a wide array of use cases.
+##### Parameters
-For example a client can request :
+| name | description | required | type | default | example |
+|-------|---------------------------------------------|----------|---------|------------|--------------|
+| since | The timestamp of the oldest trade to fetch. | false | Integer | 1 week ago | `1389094259` |
- 1. How much BTC would need to be sold to get exactly 10 EUR
- 2. How much BTC could be bought with 10 EUR
- 3. How much EUR would the sale of 1 BTC get
- 4. How much EUR would be required to buy 1 BTC
+##### Example
-To obtain the relevant quote a client would pass the following parameters :
+```bash
+$ curl "https://paymium.com/api/v1/data/eur/trades?since=1389094259"
+```
-| Case | Currency | direction | requested\_btc\_amount | requested\_currency\_amount |
-|------|----------|-----------|------------------------|-----------------------------|
-| 1 | EUR | sell | N/A | 10 |
-| 2 | EUR | buy | N/A | 10 |
-| 3 | EUR | sell | 1 | N/A |
-| 4 | EUR | buy | 1 | N/A |
+```json
+[
+ {
+ "uuid": "59f9c458-cb22-48d6-9103-0b6e54130e29",
+ "traded_btc": 0.153,
+ "traded_currency": 102.51,
+ "created_at": "2014-01-07T11:30:59Z",
+ "currency": "EUR",
+ "price": 670.0,
+ "created_at_int": 1389094259
+ },
+ {
+ "uuid": "4787c80b-bc90-48d4-87ee-b23fbff2fbb7",
+ "traded_btc": 0.06,
+ "traded_currency": 40.2,
+ "created_at": "2014-01-07T11:31:00Z",
+ "currency": "EUR",
+ "price": 670.0,
+ "created_at_int": 1389094260
+ },
+ {
+ "uuid": "67838a4d-cd2e-47d1-9b3c-0ff7a6d2ea89",
+ "traded_btc": 0.4,
+ "traded_currency": 268.0,
+ "created_at": "2014-01-07T11:31:00Z",
+ "currency": "EUR",
+ "price": 670.0,
+ "created_at_int": 1389094260
+ }
+]
+```
-**Request path :** `/api/v1/quotes`
+##### Properties
-**Request method :** `POST`
+The response is an array of trades.
-**Request parameters**
+##### Trade properties
-| Name | Type | Description |
-|-----------------------------|---------|------------------------------------------------------------------------|
-| requested\_currency\_amount | Decimal | Constrain on the currency amount (1) |
-| requested\_btc\_amount | Decimal | Constrain on the Bitcoin amount (1) |
-| direction | String | Whether the quote should apply to a sale or a purchase of Bitcoins (2) |
-| currency | String | Currency in which the requested_amount is expressed |
+| name | description | example value |
+|-----------------|----------------------------------------------|----------------------------------------|
+| uuid | unique ID of trade | "59f9c458-cb22-48d6-9103-0b6e54130e29" |
+| currency | currency | "EUR" |
+| created_at | date created | "2014-01-07T11:30:59Z" |
+| created_at_int | timestamp | 1389094259 |
+| price | price per BTC | 670.0 |
+| traded_btc | amount of BTC traded | 0.153 |
+| traded_currency | amount of currency traded | 102.51 |
- 1. Exactly one of the currencies must be constrained, the other parameter may be omitted
- 2. Acceptable values are `buy` and `sell`
+### Market depth
-**Response**
+##### Description
-A JSON object with the following parameters is returned. If the current market depth or volatility does not allow for a quote to be given an error will be returned.
+Read the market depth. Bids and asks are grouped by price.
-| Name | Type | Description |
-|-----------------------------|----------|-------------------------------------------------------|
-| uuid | UUID | Quote identifier |
-| requested\_currency\_amount | Decimal | The instructed currency amount or `null` |
-| requested\_btc\_amount | Decimal | The instructed Bitcoin amount or `null` |
-| direction | String | The direction you provided |
-| currency_amount | Decimal | The quoted currency amount or `null` |
-| btc_amount | Decimal | The quoted Bitcoin amount or `null` |
-| rate | Decimal | The quoted exchange rate |
-| valid_until | Datetime | The timestamp at which this quote will be invalidated |
-| created_at | Datetime | The creation date timestamp |
-| executed | Boolean | Whether this quote has already been settled or paid |
+##### Endpoint
+| method | path | authorization |
+|--------|-------------------------|---------------|
+| GET | /api/v1/data/eur/depth | not required |
-**Example request :** `POST /api/v1/quotes`
+##### Example
-This demonstrates how to obtain a quote as described in the example use case #1.
+```bash
+$ curl "https://paymium.com/api/v1/data/eur/depth"
+```
+```json
+{
+ "bids": [
{
- "requested_amount" : 10.0,
- "currency" : "EUR",
- "direction" : "sell"
- }
-
-**Example response :**
-
+ "timestamp": 1389087724,
+ "amount": 0.89744,
+ "price": 665.0,
+ "currency": "EUR"
+ },
{
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d",
- "currency" : "EUR",
- "direction" : "sell",
- "rate" : 10.65
- "currency_amount" : null,
- "btc_amount" : 0.93896714
- "requested_currency_amount" : 10,
- "requested_btc_amount" : null,
- "valid_until" : "2013-01-10T13:00:50Z",
- "created_at" : "2013-01-10T12:45:50Z",
- "created_at_int" : 1363858355,
- "executed" : false
+ "timestamp": 1389082088,
+ "amount": 0.06,
+ "price": 666.0,
+ "currency": "EUR"
}
-
-### View a quote (A)
-
-This call will return a JSON object representing a quote
-
-**Request path :** `/api/v1/quotes/{uuid}`
-
-**Request method :** `GET`
-
-**Request parameters**
-
-| Name | Type | Description |
-|------|------|------------------|
-| uuid | UUID | Quote identifier |
-
-
-**Response**
-
-A JSON object with the following parameters is returned.
-
-| Name | Type | Description |
-|-----------------------------|----------|-------------------------------------------------------|
-| uuid | UUID | Quote identifier |
-| requested\_currency\_amount | Decimal | The instructed currency amount or `null` |
-| requested\_btc\_amount | Decimal | The instructed Bitcoin amount or `null` |
-| direction | String | The direction you provided |
-| currency_amount | Decimal | The quoted currency amount or `null` |
-| btc_amount | Decimal | The quoted Bitcoin amount or `null` |
-| rate | Decimal | The quoted exchange rate |
-| valid_until | Datetime | The timestamp at which this quote will be invalidated |
-| created_at | Datetime | The creation date timestamp |
-| executed | Boolean | Whether this quote has already been settled or paid |
-
-
-**Example request :** `GET /api/v1/quotes/3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d`
-
-**Example response :**
-
+ ],
+ "asks": [
{
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d",
- "currency" : "EUR",
- "direction" : "sell",
- "rate" : 10.65
- "currency_amount" : null,
- "btc_amount" : 0.93896714
- "requested_currency_amount" : 10,
- "requested_btc_amount" : null,
- "valid_until" : "2013-01-10T13:00:50Z",
- "created_at" : "2013-01-10T12:45:50Z",
- "created_at_int" : 1363858355,
- "executed" : false
- }
-
-### List quotes (A,P)
-
-This call will return a paginated list of quotes for the client account.
-
-**Request path :** `/api/v1/quotes`
-
-**Request method :** `GET`
-
-**Request parameters**
-
-N/A
-
-**Response**
-
-A JSON array of quote objects is returned.
-
-**Example request :** `GET /api/v1/quotes`
-
-**Example response :**
-
- [
- {
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d",
- "currency" : "EUR",
- "direction" : "sell",
- "rate" : 10.65
- "currency_amount" : null,
- "btc_amount" : 0.93896714
- "requested_currency_amount" : 10,
- "requested_btc_amount" : null,
- "valid_until" : "2013-01-10T13:00:50Z",
- "created_at" : "2013-01-10T12:45:50Z",
- "created_at_int" : 1363858355,
- "executed" : true
- },
- {
- "uuid" : "4dc33a7bc1b2-9b7e-3a7b-9ffc-b3c08962ff4d",
- "currency" : "EUR",
- "direction" : "sell",
- "rate" : 10.65
- "currency_amount" : null,
- "btc_amount" : 0.93896714
- "requested_currency_amount" : 10,
- "requested_btc_amount" : null,
- "valid_until" : "2013-01-10T13:00:50Z",
- "created_at" : "2013-01-10T12:45:50Z",
- "created_at_int" : 1363858355,
- "executed" : true
- }
- ]
-
-### Pay a quote (A)
-
-This action applies only to quotes for buying BTC.
-
-It will perform the exchange creating a user account debit of the calculated `currency_amount` or instructed `requested_currency_amount` and send out the calculated `btc_amount` or instructed `requested_btc_amount` to the Bitcoin address in the `address` field.
-
-Calling this method queues the quote for payment if possible. The quote status can later be queried using the [view a quote](#view-a-quote-a) call.
-
-**Request path :** `/api/v1/quotes/{uuid}/pay`
-
-**Request method :** `POST`
-
-**Request parameters**
-
-| Name | Type | Description |
-|---------|--------|-----------------------|
-| uuid | UUID | Quote identifier |
-| address | String | Valid Bitcoin address |
-
-
-**Response**
-
-The quote as it was when the payment was requested is returned.
-
-**Example request :** `GET /api/v1/quotes/3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d/pay`
-
-**Example response :**
-
+ "timestamp": 1389094178,
+ "amount": 0.57709999,
+ "price": 679.99,
+ "currency": "EUR"
+ },
{
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d",
- "currency" : "EUR",
- "direction" : "sell",
- "rate" : 10.65
- "currency_amount" : null,
- "btc_amount" : 0.93896714
- "requested_currency_amount" : 10,
- "requested_btc_amount" : null,
- "valid_until" : "2013-01-10T13:00:50Z",
- "created_at" : "2013-01-10T12:45:50Z",
- "created_at_int" : 1363858355,
- "executed" : false
+ "timestamp": 1389092448,
+ "amount": 0.20684181,
+ "price": 680.0,
+ "currency": "EUR"
}
+ ]
+}
+```
-### Execute a quote (A)
+##### Properties
-This action applies to quotes for buying and selling BTC. It will perform the exchange creating user account debit and credit operations depending on the quote requested.
+| name | description |
+|-----------------|----------------------------------------------|
+| bids | an array of bids |
+| asks | an array of asks |
-Calling this method queues the quote for execution if possible. The quote status can later be queried using the [view a quote](#view-a-quote-a) call.
+##### Bids / asks properties
-**Request path :** `/api/v1/quotes/{uuid}/execute`
+| name | description | example value |
+|-----------------|----------------------------------------------|----------------------------------------|
+| currency | currency | "EUR" |
+| timestamp | timestamp | 1389087724 |
+| price | price | 665.0 |
+| amount | amount at price | 0.06 |
-**Request method :** `POST`
-**Request parameters**
+### Bitcoin-Charts endpoints
-| Name | Type | Description |
-|---------|--------|-----------------------|
-| uuid | UUID | Quote identifier |
+Two API endpoints dedicated to [Bitcoin-Charts](http://bitcoincharts.com) are publicly accessible, they are accessible at:
+ * `https://paymium.com/api/v1/bitcoin_charts/eur/trades`, and
+ * `https://paymium.com/api/v1/bitcoin_charts/eur/depth`
-**Response**
+The data they return is formatted according to the [Bitcoin Charts exchange API specification](http://bitcoincharts.com/about/exchanges/).
-The quote as it was when the execution was requested is returned.
+### WebSocket
-**Example request :** `POST /api/v1/quotes/3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d/execute`
+A [socket.io](http://socket.io) endpoint is available to receive public data. This allows you to receive new data without having to poll the server.
-**Example response :**
-
- {
- "uuid" : "3a7bc1b2-9b7e-4dc3-9ffc-b3c08962ff4d",
- "currency" : "EUR",
- "direction" : "sell",
- "rate" : 10.65
- "currency_amount" : null,
- "btc_amount" : 0.93896714
- "requested_currency_amount" : 10,
- "requested_btc_amount" : null,
- "valid_until" : "2013-01-10T13:00:50Z",
- "created_at" : "2013-01-10T12:45:50Z",
- "created_at_int" : 1363858355,
- "executed" : false
- }
+The socket.io socket will emit a `stream` event when new data is available. The received JSON data contains one or more of the properties listed below, depending on what was updated.
-## Invoices
+#### Socket.io configuration
-Invoices are requests for payment. They can be expressed in any arbitrary currency. They all get a unique Bitcoin payment address assigned and a Bitcoin amount calculated from the requested currency amount.
+Socket.io must connect to `paymium.com/` and the `path` option must be set to `/ws/socket.io`.
-Payment can be made by sending the `btc_amount` amount of Bitcoins to the `payment_address` address or directly in the requested currency from another account. The invoice payment will trigger a `POST`to the `callback_url`.
+#### Message descriptions
-These calls require the `merchant` OAuth2 scope.
+The Websocket messages are documented separately: [documentation](https://github.com/Paymium/api-documentation/blob/master/WEBSOCKETS.md).
-### View an invoice (A)
+#### Node.js example
-This call will return a JSON object representing an invoice
+Assuming you have node.js installed, you can install the socket.io client library by running `npm install socket.io-client`.
-**Request path :** `/api/v1/invoices/{uuid}`
+The code below shows how to connect to the Paymium socket, and outputs any received data to the console.
-**Request method :** `GET`
+The example is available in the `examples/public_socket.js` directory of this repository.
-**Request parameters**
+```javascript
+var io = require('socket.io-client');
-| Name | Type | Description |
-|------|------|------------------|
-| uuid | UUID | Quote identifier |
+var socket = io.connect('paymium.com/public', {
+ path: '/ws/socket.io'
+});
+console.log('CONNECTING');
-**Response**
+socket.on('connect', function() {
+ console.log('CONNECTED');
+ console.log('WAITING FOR DATA...');
+});
-A JSON object with the following parameters is returned.
+socket.on('disconnect', function() {
+ console.log('DISCONNECTED');
+});
-| Name | Type | Description |
-|---------------------------|----------|-----------------------------------------------------------------|
-| uuid | UUID | Invoice identifier |
-| state | String | Invoice state _(see appendix)_ |
-| payment\_address | String | Bitcoin payment address |
-| payment\_bitcoin_\uri | String | Payment URI, should be used to generate QR codes |
-| amount | Decimal | Requested amount to be credited upon payment |
-| btc_amount | Decimal | Payable amount expressed in BTC |
-| amount\_to\_pay | Decimal | Amount left to pay |
-| btc\_amount\_to\_pay | Decimal | Bitcoin amount amount left to pay |
-| currency | String | Currency in which the amount is expressed |
-| merchant\_reference | String | Merchant reference |
-| merchant\_memo | String | Merchant memo |
-| callback\_url | String | URL to which a callback should be made when the invoice is paid |
-| item\_url | String | Order-related URL |
-| paid\_at | Datetime | Payment timestamp |
-| created\_at | Datetime | Creation timestamp |
-| updated\_at | Datetime | Update timestamp |
-| expires\_at | Datetime | Expiration timestamp |
-| settled | Boolean | Has this invoice already been credited ? |
-| notification\_email\_sent | Boolean | Has the notification e-mail already been sent ? |
-| public\_url | String | The URL at which this invoice is publicly visible and payable |
+socket.on('stream', function(data) {
+ console.log('GOT DATA:');
+ console.log(data);
+});
+```
+### FIX streaming API
-**Example request :** `GET /api/v1/invoices/70c7936b-f8ce-443a-8338-3762de0a1e92`
+The FIX API is documented separately: [documentation](https://github.com/Paymium/api-documentation/blob/master/FIX-4.4.md).
-**Example response :**
-
- {
- "uuid": "70c7936b-f8ce-443a-8338-3762de0a1e92",
- "amount": 10.0,
- "amount_to_pay": 10.0,
- "btc_amount": 1.021732,
- "btc_amount_to_pay": 1.021732,
- "notification_email_sent": false,
- "callback_url": null,
- "created_at": "2013-01-21T10:20:07Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "expires_at": "2013-01-21T10:40:07Z",
- "item_url": null,
- "merchant_memo": null,
- "merchant_reference": null,
- "paid_at": null,
- "payment_address": "1JnjJNhdKSgvMKr6xMbqVEudB3eACsGJSz",
- "payment_bitcoin_uri" : "bitcoin:1JnjJNhdKSgvMKr6xMbqVEudB3eACsGJSz?amount=100.0&label=&x-pay-curamt=100.0&x-pay-cur=BTC&x-pay-id=7653453d-6372-4ffa-bc56-1e3182ef7f35",
- "settled": false,
- "state": "pending",
- "updated_at": "2013-01-21T10:20:07Z",
- "public_url": "https://paytunia.com/invoices/70c7936b-f8ce-443a-8338-3762de0a1e92"
- }
-### View an invoice (Public)
+## User data
-It is the same call as the above one, except this call will return a subset of the JSON object representing an invoice.
+Before you can access your own data or other users data, you must register an application on Paymium:
-**Request path :** `/api/v1/invoices/{uuid}`
+1. Verify your account and log in
+2. Visit [https://paymium.com/page/developers/apps](https://paymium.com/page/developers/apps)
+3. Create an application (set redirect URI to `https://paymium.com/page/oauth/test` when testing)
-**Request method :** `GET`
+### User info
-**Request parameters**
+##### Description
-| Name | Type | Description |
-|------|------|------------------|
-| uuid | UUID | Quote identifier |
+Read the latest user info.
+##### Endpoint
-**Response**
+| method | path | authorization |
+|--------|-------------------------|-----------------------|
+| GET | /api/v1/user | oauth2 (scope: basic) |
-A JSON object with the following parameters is returned.
+##### Example
-| Name | Type | Description |
-|---------------------|----------|-----------------------------------------------------------------|
-| uuid | UUID | Invoice identifier |
-| state | String | Invoice state _(see appendix)_ |
-| payment\_address | String | Bitcoin payment address |
-| amount | Decimal | Requested amount to be credited upon payment |
-| btc_amount | Decimal | Payable amount expressed in BTC |
-| currency | String | Currency in which the amount is expressed |
-| merchant\_reference | String | Merchant reference |
-| merchant\_memo | String | Merchant memo |
-| item\_url | String | Order-related URL |
-| paid\_at | Datetime | Payment timestamp |
-| created\_at | Datetime | Creation timestamp |
-| updated\_at | Datetime | Update timestamp |
-| expires\_at | Datetime | Expiration timestamp |
+```bash
+$ curl "https://paymium.com/api/v1/user" \
+ --header "Authorization: Bearer ACCESS_TOKEN"
+```
+```json
+{
+ "name": "BC-U123456",
+ "locale": "en",
+ "balance_btc": 25.78866278,
+ "locked_btc": 1.0,
+ "balance_eur": 1893.96,
+ "locked_eur": 300.00743886
+}
+```
-**Example request :** `GET /api/v1/invoices/70c7936b-f8ce-443a-8338-3762de0a1e92`
+##### Properties
-**Example response :**
-
- {
- "uuid": "70c7936b-f8ce-443a-8338-3762de0a1e92",
- "amount": 10.0,
- "btc_amount": 1.021732,
- "callback_fired": false,
- "callback_url": null,
- "created_at": "2013-01-21T10:20:07Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "expires_at": "2013-01-21T10:40:07Z",
- "item_url": null,
- "merchant_memo": null,
- "merchant_reference": null,
- "paid_at": null,
- "payment_address": "1JnjJNhdKSgvMKr6xMbqVEudB3eACsGJSz",
- "payment_bitcoin_uri" : "bitcoin:1JnjJNhdKSgvMKr6xMbqVEudB3eACsGJSz?amount=100.0&label=&x-pay-curamt=100.0&x-pay-cur=BTC&x-pay-id=7653453d-6372-4ffa-bc56-1e3182ef7f35",
- "settled": false,
- "state": "pending",
- "updated_at": "2013-01-21T10:20:07Z"
- }
+| name | description | example value |
+|--------------|----------------------------------------------|---------------------------|
+| name | account number / name | "BC-U123456" |
+| locale | locale code | "en" |
+| balance_eur | available EUR balance | 1893.96 |
+| locked_eur | EUR balance locked in trading | 300.00743886 |
+| balance_btc | available BTC balance | 25.78866278 |
+| locked_btc | BTC balance locked in trading | 1.0 |
-### List invoices (A,P)
+### User activity
-This call will return a paginated list of invoices for the client account.
+##### Description
-**Request path :** `/api/v1/invoices`
+Read user activity.
-**Request method :** `GET`
+##### Endpoint
-**Request parameters**
+| method | path | authorization |
+|--------|-------------------------|--------------------------|
+| GET | /api/v1/user/orders | oauth2 (scope: activity) |
-N/A
+##### Parameters
-**Response**
+| name | description | example value |
+|--------------|----------------------------------------------|---------------------------|
+| offset | pagination offset (optional) | 20 |
+| limit | pagination limit (optional) | 20 |
+| types[] | filter by types (optional) | LimitOrder |
+| active | only show active orders (optional) | true |
-A JSON array of invoice objects is returned.
+##### Example
-**Example request :** `GET /api/v1/quotes`
+```bash
+$ curl "https://paymium.com/api/v1/user/orders?offset=20" \
+ --header "Authorization: Bearer ACCESS_TOKEN"
+```
-**Example response :**
-
- [
+```json
+[
+ {
+ "uuid": "968f4580-e26c-4ad8-8bcd-874d23d55296",
+ "amount": 1.0,
+ "state": "executed",
+ "btc_fee": 0.0,
+ "currency_fee": 0.0,
+ "updated_at": "2013-10-24T10:34:37.000Z",
+ "created_at": "2013-10-22T19:12:02.000Z",
+ "currency": "BTC",
+ "type": "Transfer",
+ "account_operations": [
{
- "uuid": "8338936b-f8ce-443a-70c7-3762de0a1e92",
- "amount": 10.0,
- "btc_amount": 1.021732,
- "callback_fired": false,
- "callback_url": null,
- "created_at": "2013-01-21T10:20:07Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "expires_at": "2013-01-21T10:40:07Z",
- "item_url": null,
- "merchant_memo": null,
- "merchant_reference": null,
- "paid_at": null,
- "payment_address": "1JnjJNhdKSgvMKr6xMbqVEudB3eACsGJSz",
- "settled": false,
- "state": "pending",
- "updated_at": "2013-01-21T10:20:07Z"
- },
+ "uuid": "94b42d0f-9c2d-43f3-978b-aba28533d1f9",
+ "name": "bitcoin_transfer",
+ "amount": -1.0,
+ "currency": "BTC",
+ "created_at": "2013-10-22T19:12:02.000Z",
+ "created_at_int": 1382469122,
+ "is_trading_account": false
+ }
+ ]
+ },
+ {
+ "uuid": "1953cd1b-3903-4812-9590-42c3ebcc08c2",
+ "amount": 49.38727114,
+ "state": "executed",
+ "btc_fee": 0.0,
+ "currency_fee": 0.0,
+ "updated_at": "2013-10-22T14:30:06.000Z",
+ "created_at": "2013-10-22T14:30:06.000Z",
+ "currency": "BTC",
+ "type": "AdminOrder",
+ "account_operations": [
{
- "uuid": "70c7936b-f8ce-443a-8338-3762de0a1e92",
- "amount": 10.0,
- "btc_amount": 1.021732,
- "callback_fired": false,
- "callback_url": null,
- "created_at": "2013-01-21T10:20:07Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "expires_at": "2013-01-21T10:40:07Z",
- "item_url": null,
- "merchant_memo": null,
- "merchant_reference": null,
- "paid_at": null,
- "payment_address": "1JnjJNhdKSgvMKr6xMbqVEudB3eACsGJSz",
- "settled": false,
- "state": "pending",
- "updated_at": "2013-01-21T10:20:07Z"
+ "uuid": "a940393b-4d2f-4a5a-8a0a-3470d7419bad",
+ "name": "account_operation",
+ "amount": 49.38727114,
+ "currency": "BTC",
+ "created_at": "2013-10-22T14:30:06.000Z",
+ "created_at_int": 1382452206,
+ "is_trading_account": false
}
]
+ }
+]
+```
-### Create an invoice (A)
-
-This call creates an invoice
+##### Properties
-**Request path :** `/api/v1/invoices`
+The response is an array of orders. See [order properties](#order-properties).
-**Request method :** `POST`
+### Order details
-**Request parameters**
+##### Description
-| Name | Type | Description |
-|---------------------|---------|------------------------------------------------------------------------------|
-| amount | Decimal | Requested amount to be credited upon payment |
-| currency | String | Currency in which the amount is expressed |
-| merchant\_reference | String | Merchant reference _(optional)_ |
-| merchant\_memo | String | Merchant memo _(optional)_ |
-| callback\_url | String | URL to which a callback should be made when the invoice is paid _(optional)_ |
-| item\_url | String | Order-related URL _(optional)_ |
+Read details from a specific order.
-**Response**
+##### Endpoint
-An invoice JSON object is returned.
+| method | path | authorization |
+|--------|----------------------------|--------------------------|
+| GET | /api/v1/user/orders/{UUID} | oauth2 (scope: activity) |
-**Example request :** `POST /api/v1/invoices`
+##### Example
- {
- "amount" : 10.0,
- "currency" : "EUR"
- }
+```bash
+$ curl "https://paymium.com/api/v1/user/orders/968f4580-e26c-4ad8-8bcd-874d23d55296" \
+ --header "Authorization: Bearer ACCESS_TOKEN"
+```
-**Example response :**
-
+```json
+{
+ "uuid": "968f4580-e26c-4ad8-8bcd-874d23d55296",
+ "amount": 1.0,
+ "state": "executed",
+ "btc_fee": 0.0,
+ "currency_fee": 0.0,
+ "updated_at": "2013-10-24T10:34:37.000Z",
+ "created_at": "2013-10-22T19:12:02.000Z",
+ "currency": "BTC",
+ "type": "Transfer",
+ "account_operations": [
{
- "uuid": "70c7936b-f8ce-443a-8338-3762de0a1e92",
- "amount": 10.0,
- "btc_amount": 1.021732,
- "callback_fired": false,
- "callback_url": null,
- "created_at": "2013-01-21T10:20:07Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "expires_at": "2013-01-21T10:40:07Z",
- "item_url": null,
- "merchant_memo": null,
- "merchant_reference": null,
- "paid_at": null,
- "payment_address": "1JnjJNhdKSgvMKr6xMbqVEudB3eACsGJSz",
- "settled": false,
- "state": "pending",
- "updated_at": "2013-01-21T10:20:07Z"
+ "uuid": "94b42d0f-9c2d-43f3-978b-aba28533d1f9",
+ "name": "bitcoin_transfer",
+ "amount": -1.0,
+ "currency": "BTC",
+ "created_at": "2013-10-22T19:12:02.000Z",
+ "created_at_int": 1382469122,
+ "is_trading_account": false
}
+ ]
+}
+```
-### Payment buttons and creation through signed GET request
-
-This approach can be used when it is not desirable to create invoices before presenting them to the user, to create payment buttons, or when the previous flow is not practical.
-
-The approach will let a merchant securely redirect a customer to a the payment page that will generate an invoice on the fly for this particular request.
-
-The URL includes :
-
- - The merchant's account number,
- - A `query` parameter describing the payment,
- - A unique token used to make these invoice creations non-replayable,
- - A signature string created by hashing a shared secret along with the invoice data
-
-The current value of the shared secret for each account is available on the account details page.
-
-All parameters are passed in the query-string.
-
-**Request path :** `/api/v1/invoices/create_unauthenticated`
-
-**Request method :** `GET`
-
-**Request parameters**
-
-| Name | Value |
-|-----------|---------------------------------------------------------------|
-| merchant | Merchant account number |
-| token | A globally unique token, a random UUID is recommended |
-| query | The invoice parameters |
-| signature | The SHA256 hash of `merchant + shared_secret + token + query` |
-
-**Building the query parameter**
-
-The `query` parameter is created by building a string with parameters separated with the pipe character "|". Optional parameters may use a blank value.
-
-The parameters should be concatenated according to the following model :
-
- AMOUNT_IN_CENTS|CURRENCY|MERCHANT_REFERENCE|MERCHANT_MEMO|CALLBACK_URL|ITEM_URL
-
-For example, to create a payment for 12.58 EUR with the "123456" reference and `https://example.com/callback` callback URL the query should look like this :
-
- 1258|EUR|123456||https://example.com/callback|
-
-
-#### Full example
-
-A merchant wishes to display a link redirecting to a Paytunia payment page, his shared secret is `792fae4f81c12764c4e4f570920fbe89`, he wishes to create an invoice for 10 EUR with the reference "SALE-42" and a "Hello world" merchant memo, his account number is "PY-123456". The URLs are `https://example.com/callback` and `https://merchant.com/orders/SALE-42`
-
-First, the `query` parameter must be constructed, it should look like :
-
- 1000|EUR|SALE-42|Hello world|https://example.com/callback|https://merchant.com/orders/SALE-42
-
-Then a unique token should be generated, a random UUID is perfect, we'll use `46113b61-1590-447a-9bab-ceb4a5586aa9`
-
-The signature should then be generated by hashing the following string with SHA256 :
-
- # Hashed string
- PY-123456792fae4f81c12764c4e4f570920fbe8946113b61-1590-447a-9bab-ceb4a5586aa91000|EUR|SALE-42|Hello world|https://example.com/callback|https://merchant.com/orders/SALE-42
-
- # Signature generated in command-line
- $ echo -n "PY-123456792fae4f81c12764c4e4f570920fbe8946113b61-1590-447a-9bab-ceb4a5586aa91000|EUR|SALE-42|Hello world|https://example.com/callback|https://merchant.com/orders/SALE-42" | sha256sum
-
- -> 8e26068a13cbf81dac5ddca203897bbafc5a227411b36771cebcf7aad693d0ab
-
-Finally, the full URL can be generated by appending the URL-encoded parameters as following :
-
- https://bitcoin-central.net/api/v1/invoices/create_unauthenticated?merchant=PY-123456&token=46113b61-1590-447a-9bab-ceb4a5586aa9&signature=8e26068a13cbf81dac5ddca203897bbafc5a227411b36771cebcf7aad693d0ab&query=PY-123456792fae4f81c12764c4e4f570920fbe8946113b61-1590-447a-9bab-ceb4a5586aa91000%7CEUR%7CSALE-42%7CHello+world%7Chttps%3A%2F%2Fexample.com%2Fcallback%7Chttps%3A%2F%2Fmerchant.com%2Forders%2FSALE-42
-
-### Payment callbacks
-
-When a payment is received for an invoice the backend will perform an HTTP POST to the URL given as `callback_url`. The content-type for the request will be `application/x-www-form-urlencoded`.
-
-The parameters sent are the exact same as the ones returned by a [view invoice](#view-an-invoice-a).
-
-The callback is not guaranteed to be fired and may be fired multiple times, the receiver must take it into account when designing a proper handling logic.
-
-#### Signature headers
-
-A `X-Paytunia-Signature` header is added to all callback requests. Its purpose is to authenticate the call from the backend to the callback URL, this signature **must** be properly checked by the receiving server in order to ensure that the request is legitimate and hasn't been tampered with.
-
-The signature is computed by concatenating the raw request body with the client's shared secret and applying a SHA256 hash function to it.
-
-**Example signed callback request :**
-
-In this example the client secret is `792fae4f81c12764c4e4f570920fbe89`.
-
- POST / HTTP/1.1
- Accept: */*
- User-Agent: Ruby
- Content-Type: application/x-www-form-urlencoded
- X-Paytunia-Signature: ab9c3b33631e40d2880b2c4cf5bdf894bf42d6ea115dd2de71277e4382aaaeab
- Connection: close
- Host: lvh.me:3000
- Content-Length: 642
+##### Properties
- uuid=cbfb237f-dd9e-47bd-b18b-73b2f4ccdb51&state=paid&btc_amount=100.0&payment_address=1FXWhKPChEcUnSEoFQ3DGzxKe44MDbat0.42903373550437307&payment_bitcoin_uri=bitcoin%3A1FXWhKPChEcUnSEoFQ3DGzxKe44MDbatz%3Famount%3D0.0%26label%3D%26x-pay-cur%3DBTC%26x-pay-id%3Dcbfb237f-dd9e-47bd-b18b-73b2f4ccdb51&callback_url=http%3A%2F%2Flvh.me%3A3000%2F&paid_at=2013-02-08+12%3A22%3A39+UTC&created_at=2013-02-08+12%3A22%3A39+UTC&updated_at=2013-02-08+12%3A22%3A39+UTC&merchant_reference&merchant_memo&item_url¬ification_email_sent=true¤cy=BTC&amount=100.0&settled=false&expires_at=2013-02-08+12%3A42%3A39+UTC&amount_to_pay=0.0&btc_amount_to_pay=0.0
-
-In Ruby this signature can be easily checked by doing `Digest::SHA2.hexdigest(data + secret)` where `data` is the raw request body and `secret` is the client's shared secret.
+See [order properties](#order-properties).
-## Trading
+### Trading
-Account specific calls require the `trade` OAuth2 scope.
+##### Description
-### Place an order (A)
+Create trade orders.
-This call will place a trade order and queue it for execution.
+Limit and market orders are supported, the `price` parameter must be omitted for market orders.
-**Request path :** `/api/v1/trade_orders`
+Either one of `amount` or `currency_amount` must be specified. When the `amount` is specified, the
+engine will buy or sell this amount of Bitcoins. When the `currency_amount` is specified, the engine
+will buy as much Bitcoins as possible for `currency_amount` or sell as much Bitcoins as necessary to
+obtain `currency_amount`.
-**Request method :** `POST`
-**Request parameters**
+##### Endpoint
-| Name | Type | Description |
-|----------|---------|--------------------------------------------------|
-| amount | Decimal | Amount of Bitcoins to trade |
-| currency | String | Currency to trade against |
-| price | Decimal | Price _(may be omitted to place a market order)_ |
-| type | String | Must be `buy` (bid) or `sell` (ask) |
+| method | path | authorization |
+|--------|----------------------------|--------------------------|
+| POST | /api/v1/user/orders | oauth2 (scope: trade) |
-**Response**
+##### Payload
-An trade order JSON object is returned with the following parameters
+| name | description | example value |
+|--------------------|---------------------------------------------------------------|---------------|
+| type | must be "LimitOrder" or "MarketOrder" | "LimitOrder" |
+| currency | must be "EUR" | "EUR" |
+| direction | trade direction, must be "buy" or "sell" | "buy" |
+| price | price per BTC, must be omitted for market orders | 300.0 |
+| amount | BTC amount to trade (only if no currency_amount is specified) | 1.0 |
+| currency_amount | Currency amount to trade (only if no amount is specified) | 1.0 |
-| Name | Type | Description |
-|-------------------|----------|-----------------------------------|
-| uuid | UUID | Trade order identifier |
-| amount | Decimal | Remaining Bitcoin amount to trade |
-| instructed_amount | Decimal | Amount of Bitcoins to trade |
-| currency | String | Currency to trade against |
-| price | Decimal | Price _(null for a market order)_ |
-| type | String | Either `buy` or `sell` |
-| created_at | Datetime | Creation timestamp |
-| updated_at | Datetime | Update timestamp |
+##### Example
-**Example request :** `POST /api/v1/trade_orders`
+```bash
+$ curl "https://paymium.com/api/v1/user/orders" \
+ --header "Authorization: Bearer ACCESS_TOKEN" \
+ -d "type=LimitOrder" \
+ -d "currency=EUR" \
+ -d "direction=buy" \
+ -d "price=300.0" \
+ -d "amount=1.0"
+```
+Would return:
+
+```json
+{
+ "uuid": "4924ee0f-f60e-40b4-b63e-61637ef253ac",
+ "amount": 1.0,
+ "state": "pending_execution",
+ "btc_fee": 0.0,
+ "currency_fee": 0.0,
+ "updated_at": "2013-11-21T15:27:04.000Z",
+ "created_at": "2013-11-21T15:27:04.000Z",
+ "currency": "EUR",
+ "type": "LimitOrder",
+ "traded_btc": 0.0,
+ "traded_currency": 0.0,
+ "direction": "buy",
+ "price": 300.0,
+ "account_operations": [
{
- "amount" : 10.0,
- "type" : "buy",
- "currency" : "EUR"
- }
-
-**Example response :**
-
+ "uuid": "63e1d9c4-dff2-42bc-910b-c5b585b625cc",
+ "name": "lock",
+ "amount": -300.0,
+ "currency": "EUR",
+ "created_at": "2013-11-21T15:27:04.000Z",
+ "created_at_int": 1385047624,
+ "is_trading_account": false
+ },
{
- "amount": 10.0,
- "currency": "EUR",
- "type": "buy",
- "created_at": "2013-01-21T22:07:15Z",
- "created_at_int" : 1363858355,
- "instructed_amount": 10.0,
- "price": null,
- "currency": "EUR",
- "state": "pending_execution",
- "updated_at": "2013-01-21T22:07:15Z",
- "uuid": "8b3c3446-9c5d-48a8-8044-08622cd4607b"
+ "uuid": "c9d3e824-b29a-4630-8396-3864a0704336",
+ "name": "lock",
+ "amount": 300.0,
+ "currency": "EUR",
+ "created_at": "2013-11-21T15:27:04.000Z",
+ "created_at_int": 1385047624,
+ "is_trading_account": true
}
+ ]
+}
+```
-### Cancel an order (A)
-
-This call will enqueue a cancel order job to remove it from the order book.
-
-**Request path :** `/api/v1/trade_orders/{uuid}`
-
-**Request method :** `DELETE`
-
-**Request parameters**
-
-| Name | Type | Description |
-|------|------|------------------------|
-| uuid | UUID | Trade order identifier |
-
-**Example request :** `DELETE /api/v1/trade_orders/8b3c3446-9c5d-48a8-8044-08622cd4607b`
+##### Properties
-**Example response :**
+See [order properties](#order-properties).
-N/A
+### Withdrawing
-### View trades for an order (A)
+Request BTC or fiat withdrawals. A confirmation is sent by email to the user before it can be executed.
-This call will return a collection of trades that were executed for a particular order.
+##### Endpoint
-**Request path :** `/api/v1/trade_orders/{uuid}/trades`
+| method | path | authorization |
+|--------|----------------------------|--------------------------|
+| POST | /api/v1/user/orders | oauth2 (scope: withdraw) |
-**Request method :** `GET`
+##### Payload
-**Request parameters**
+| name | description | example value |
+|--------------------|-----------------------------------------|----------------------------------------|
+| type | must be "Transfer" | "Transfer" |
+| currency | currency code | "BTC" |
+| amount | amount to transfer | 0.5 |
+| address | BTC address if withdrawing BTC | "1PzU1ERAnHJmtU8J3qq3wwJhyLepwUYzHn" |
-| Name | Type | Description |
-|------|------|------------------------|
-| uuid | UUID | Trade order identifier |
+##### Example
-**Response**
+```bash
+$ curl "https://paymium.com/api/v1/user/orders" \
+ --header "Authorization: Bearer ACCESS_TOKEN" \
+ -d "type=Transfer" \
+ -d "currency=BTC" \
+ -d "amount=0.5" \
+ -d "address=1PzU1ERAnHJmtU8J3qq3wwJhyLepwUYzHn"
+```
-An array of trade JSON objects is returned.
+Would return:
+
+```json
+{
+ "uuid": "9229fd6e-0aad-45d6-8090-a400f37a0129",
+ "amount": 0.5,
+ "state": "pending",
+ "btc_fee": 0.0,
+ "currency_fee": 0.0,
+ "updated_at": "2014-01-09T10:22:00.858Z",
+ "created_at": "2014-01-09T10:22:00.858Z",
+ "currency": "BTC",
+ "type": "Transfer",
+ "account_operations": [
+ {
+ "uuid": "4c4f4682-354f-46d1-a916-72d88d5584e3",
+ "name": "bitcoin_transfer",
+ "amount": -0.5,
+ "currency": "BTC",
+ "created_at": "2014-01-09T10:22:02.171Z",
+ "created_at_int": 1389262922,
+ "is_trading_account": false
+ }
+ ]
+}
+```
-| Name | Type | Description |
-|-----------------|----------|--------------------------------------------------|
-| uuid | UUID | Trade identifier |
-| traded_currency | Decimal | Amount traded, expressed in `currency` |
-| traded_btc | Decimal | Amount of Bitcoins traded |
-| currency | String | Currency in which `traded_currency` is expressed |
-| price | Decimal | Price at which the exchange was made |
-| created_at | Datetime | Creation timestamp |
+##### Properties
+See [order properties](#order-properties).
+### Sending money
-**Example request :** `GET /api/v1/trade_orders/8b32ddf1-1675-4ed3-b1bb-b4efc4ecd98c/trades`
+##### Description
-**Example response :**
+Initiate a money transfer to an e-mail address.
- [
- {
- "created_at": "2013-01-22T08:19:41Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "price": 5.0,
- "traded_btc": 980.0,
- "traded_currency": 4940.0,
- "uuid": "1c86abf0-170a-4101-84d1-cdad913c95dd"
- },
- {
- "created_at": "2013-01-22T08:19:41Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "price": 6.0,
- "traded_btc": 10.0,
- "traded_currency": 60.0,
- "uuid": "170aabf0-1c86-4101-84d1-cdad913c95dd"
- }
- ]
+The transfer is immediately executed if the user have a valid account. Otherwise, an e-mail is sent with a registration invitation.
-### View an order (A)
+This transfer expire after 1 month if it is not collected. In this case, the order is cancelled and the sender re-credited.
-This call will return a trade order JSON object.
+#### Endpoint
-**Request path :** `/api/v1/trade_orders/{uuid}`
+| method | path | authorization |
+|--------|----------------------------|--------------------------|
+| POST | /api/v1/user/orders | oauth2 (scope: send) |
-**Request method :** `GET`
+##### Payload
-**Request parameters**
+| name | description | example value |
+|--------------------|-----------------------------------------|----------------------------------------|
+| type | must be "EmailTransfer" | "EmailTransfer" |
+| currency | currency code | "BTC" |
+| amount | amount to transfer | 0.5 |
+| email | an e-mail address | "user@example.com" |
+| comment | a small note explaining the transfer | "Hi, refund for that thing" |
-| Name | Type | Description |
-|------|------|------------------|
-| uuid | UUID | Order identifier |
+##### Example
-**Response**
+```bash
+$ curl "https://paymium.com/api/v1/user/orders" \
+ --header "Authorization: Bearer ACCESS_TOKEN" \
+ -d "type=EmailTransfer" \
+ -d "currency=BTC" \
+ -d "amount=0.5" \
+ -d "email=user@example.com" \
+ -d "comment=Hi, refund for that thing"
+```
-A JSON object with the following parameters is returned.
+Would return:
+
+```json
+{
+ "uuid": "9229fd6e-0aad-45d6-8090-a400f37a0129",
+ "amount": 0.5,
+ "state": "pending",
+ "btc_fee": 0.0,
+ "currency_fee": 0.0,
+ "updated_at": "2014-01-09T10:22:00.858Z",
+ "created_at": "2014-01-09T10:22:00.858Z",
+ "currency": "BTC",
+ "type": "EmailTransfer",
+ "account_operations": [
+ {
+ "uuid": "4c4f4682-354f-46d1-a916-72d88d5584e3",
+ "name": "email_transfer",
+ "amount": -0.5,
+ "currency": "BTC",
+ "created_at": "2014-01-09T10:22:02.171Z",
+ "created_at_int": 1389262922,
+ "is_trading_account": false
+ }
+ ]
+}
+```
-| Name | Type | Description |
-|-------------------|----------|-----------------------------------|
-| uuid | UUID | Trade order identifier |
-| amount | Decimal | Remaining Bitcoin amount to trade |
-| instructed_amount | Decimal | Amount of Bitcoins to trade |
-| currency | String | Currency to trade against |
-| price | Decimal | Price _(null for a market order)_ |
-| type | String | Either `buy` or `sell` |
-| created_at | Datetime | Creation timestamp |
-| updated_at | Datetime | Update timestamp |
+### Requesting money by e-mail
-**Example request :** `GET /api/v1/trade_orders/8b32ddf1-1675-4ed3-b1bb-b4efc4ecd98c`
+##### Description
-**Example response :**
-
- {
- "amount": 10.0,
- "type": "buy",
- "created_at": "2013-01-22T08:19:37Z",
- "created_at_int" : 1363858355,
- "instructed_amount": 1000.0,
- "currency": "EUR",
- "price": 11.0,
- "state": "active",
- "updated_at": "2013-01-22T08:19:41Z",
- "uuid": "8b32ddf1-1675-4ed3-b1bb-b4efc4ecd98c"
- }
+This functionality allows one to create a payment request that is sent by e-mail to the designated recipient, when the link contained in the e-mail is clicked,
+the recipient is presented with a Bitcoin address to which he is instructed to direct his payment.
-### List active orders (A,P)
+Once the Bitcoin payment is confirmed, the payee is credited in the originally requested currency.
-This call will return a paginated list of the client's executable trade orders (`pending_execution`, `active` or `insufficient_funds` states).
+#### Endpoint
-**Request path :** `/api/v1/trade_orders/active`
+| method | path | authorization |
+|--------|-------------------------------|-------------------------|
+| POST | /api/v1/user/payment_requests | oauth2 (scope: receive) |
-**Request method :** `GET`
+##### Payload
-**Request parameters**
+| name | description | example value |
+|-------------- |-----------------------------------------|-----------------------------|
+| type | must be "PaymentRequest" | "PaymentRequest" |
+| currency | currency code | "BTC" |
+| amount | amount to transfer | 0.5 |
+| email | an e-mail address | "user@example.com" |
+| payment_split | Percentage of the payment the _merchant_ will get in `currency` expressed as a two-decimal places float between 0 and 1 (required) | 1.0 |
+| comment | a small note explaining the transfer | "Hi, refund for that thing" |
-N/A
+##### Example
-**Example request :** `GET /api/v1/trade_orders/active`
+```bash
+$ curl "https://paymium.com/api/v1/user/payment_requests" \
+ --header "Authorization: Bearer ACCESS_TOKEN" \
+ -d "type=PaymentRequest" \
+ -d "currency=BTC" \
+ -d "amount=0.5" \
+ -d "email=user@example.com" \
+ -d "payment_split=1" \
+ -d "comment=Hi, refund for that thing"
+```
-**Example response :**
+If successful, responds with a `HTTP/1.1 201 Created` status code.
- [
- {
- "amount": 10.0,
- "currency": "EUR",
- "type": "buy",
- "created_at": "2013-01-21T22:15:38Z",
- "created_at_int" : 1363858355,
- "instructed_amount": 10.0,
- "price": null,
- "state": "pending_execution",
- "updated_at": "2013-01-21T22:15:38Z",
- "uuid": "52823408-972f-4551-acc5-e7d3f032c6d5"
- }
- ]
+### Canceling orders
-### List all orders (A,P)
+##### Description
-This call will return a paginated list of the client's trade orders.
+Cancel an order. Only active trade orders and email tranfers may be canceled.
-**Request path :** `/api/v1/trade_orders`
+##### Endpoint
-**Request method :** `GET`
+| method | path | authorization |
+|--------|-----------------------------------|--------------------------|
+| DELETE | /api/v1/user/orders/{UUID}/cancel | oauth2 (scope: trading) |
-**Request parameters**
+##### Example
-N/A
+```bash
+$ curl "https://paymium.com/api/v1/user/orders/968f4580-e26c-4ad8-8bcd-874d23d55296" \
+ -X DELETE --header "Authorization: Bearer ACCESS_TOKEN"
+```
+### Bitcoin addresses
-**Example request :** `GET /api/v1/trade_orders`
+##### Description
-**Example response :**
+List and create bitcoin deposit addresses
- [
- {
- "amount": 10.0,
- "currency": "EUR",
- "type": "buy",
- "created_at": "2013-01-21T22:15:38Z",
- "created_at_int" : 1363858355,
- "instructed_amount": 10.0,
- "price": null,
- "state": "pending_execution",
- "updated_at": "2013-01-21T22:15:38Z",
- "uuid": "52823408-972f-4551-acc5-e7d3f032c6d5"
- },
- {
- "amount": 10.0,
- "currency": "EUR",
- "type": "buy",
- "created_at": "2013-01-21T22:15:40Z",
- "created_at_int" : 1363858355,
- "instructed_amount": 10.0,
- "price": null,
- "state": "canceled",
- "updated_at": "2013-01-21T22:15:40Z",
- "uuid": "6e3ea778-9ef7-4e4f-9910-85e735f7b42a"
- }
- ]
+##### Endpoint
-### Read the ticker
+| method | path | authorization |
+|--------|-------------------------------------|--------------------------|
+| GET | /api/v1/user/addresses | oauth2 (scope: deposit) |
+| GET | /api/v1/user/addresses/:btc_address | oauth2 (scope: deposit) |
+| POST | /api/v1/user/addresses | oauth2 (scope: deposit) |
-This call will return the ticker.
+##### Examples
-**Request path :** `/api/v1/ticker/{currency}`
+Retrieve your Bitcoin deposit addresses along with their expiration timestamp.
-**Request method :** `GET`
+```bash
+$ curl "https://paymium.com/api/v1/user/addresses" \
+ --header "Authorization: Bearer ACCESS_TOKEN"
+```
-**Request parameters**
+```json
+[
+ {
+ "address": "1PzU1ERAnHJmtU8J3qq3wwJhyLepwUYzHn",
+ "valid_until": 1402579836
+ }
+]
+```
-| Name | Type | Description |
-|----------|--------|----------------------------------------------------------------------|
-| currency | String | Show the ticker for the given currency, default to `EUR`if ommitted |
+Retrieve details for a single address.
-**Example request :** `GET /api/v1/ticker/eur`
+```bash
+$ curl "https://paymium.com/api/v1/user/addresses/1PzU1ERAnHJmtU8J3qq3wwJhyLepwUYzHn" \
+ --header "Authorization: Bearer ACCESS_TOKEN"
+```
-**Alternate example :** `GET /api/v1/ticker`
+```json
+{
+ "address": "1PzU1ERAnHJmtU8J3qq3wwJhyLepwUYzHn",
+ "valid_until": 1402579836
+}
+```
-**Example response :**
+Create a new Bitcoin deposit address unless another one is already active.
- {
- "ask": 20.4,
- "at": 1361056527,
- "bid": 20.1,
- "currency": "EUR",
- "high": 20.74,
- "low": 20.2,
- "midpoint": 20.25,
- "price": 20.2,
- "variation": -1.4634,
- "volume": 148.80193218
- }
+```bash
+$ curl -X POST "https://bitcoin-central.net/api/v1/user/addresses" \
+ --header "Authorization: Bearer ACCESS_TOKEN"
+```
-### Read the market depth
+```json
+{
+ "address": "1PzU1ERAnHJmtU8J3qq3wwJhyLepwUYzHn",
+ "valid_until": 1402579836
+}
+```
-This call will return the full sorted market depth. If the `currency` parameter is omitted, the currency defaults to EUR.
+### Price alerts
-The asks are sorted by ascending price and the bids by descending price.
+##### Description
-**Request path :** `/api/v1/depth` or `/api/v1/depth/{currency}`
+Register a mobile device for alerts on price movements.
-**Request method :** `GET`
+##### Endpoint
-**Request parameters**
+| method | path | authorization |
+|--------|-------------------------------------|--------------------------|
+| GET | /api/v1/user/price_alerts | oauth2 (scope: activity) |
+| POST | /api/v1/user/price_alerts | oauth2 (scope: activity) |
+| DELETE | /api/v1/user/price_alerts/:id | oauth2 (scope: activity) |
-N/A
+##### Examples
-**Example request :** `GET /api/v1/depth/eur`
+Retrieve currently active price alerts.
-**Example response :**
+```bash
+$ curl "https://paymium.com/api/v1/user/price_alerts" \
+ --header "Authorization: Bearer ACCESS_TOKEN"
+```
- {
- "asks": [
- {
- "amount": 0.48762,
- "currency": "EUR",
- "price": 24.48996,
- "timestamp": 1361925287
- },
- {
- "amount": 12.96657232,
- "currency": "EUR",
- "price": 24.49,
- "timestamp": 1361924964
- }
- ],
- "bids": [
- {
- "amount": 0.77372456,
- "currency": "EUR",
- "price": 24.05,
- "timestamp": 1361902889
- },
- {
- "amount": 0.40491093,
- "currency": "EUR",
- "price": 24.001,
- "timestamp": 1361887469
- }
- ]
- }
+```json
+[
+ {
+ "id": 42,
+ "token": "0ff2f39d-cd9f-4710-9eb5-3f8385f5e059",
+ "notify_above": 220.5,
+ "notify_below": 180.0,
+ "last_sent_at": 1445610041
+ }
+]
+```
-### Read historical trades (P)
+Create a new price alert.
-This call will return the most recent trades
+```bash
+$ curl "https://paymium.com/api/v1/user/price_alerts" \
+ -X POST \
+ --header "Authorization: Bearer ACCESS_TOKEN" \
+ -d "token=0ff2f39d-cd9f-4710-9eb5-3f8385f5e059" \
+ -d "notify_below=100" \
+ -d "notify_above=110" \
+```
-**Request path :** `/api/v1/trades/{currency}`
+If successful, it responds with a `HTTP/1.1 201 Created` status code.
-**Request method :** `GET`
-**Request parameters**
+## Merchant API
-| Name | Type | Description |
-|----------|--------|-----------------------------------------------|
-| currency | String | Currency filter, defaults to `EUR` if omitted |
+The Merchant API enables merchants to securely sell goods and services and get paid in Bitcoin. The API makes it possible for the merchant to completely eliminate the risk of market fluctuations when requesting to receive fiat currency in their account. It is also possible to keep a part of the payment in Bitcoin without having it converted at a guaranteed rate.
-**Response**
+The API allows developers to integrate Bitcoin payments very tightly into their platforms, pre-packaged plugins are also available for a growing list of popular e-commerce frameworks.
-An array of trade JSON objects is returned.
+For merchants that have very simple needs payment buttons are also available, these buttons remove the integration completely by allowing merchants to simply include a code snippet on a static HTML page, or on a blog to receive fixed-amount payments.
-| Name | Type | Description |
-|-----------------|----------|--------------------------------------------------|
-| uuid | UUID | Trade identifier |
-| traded_currency | Decimal | Amount traded, expressed in `currency` |
-| traded_btc | Decimal | Amount of Bitcoins traded |
-| currency | String | Currency in which `traded_currency` is expressed |
-| price | Decimal | Price at which the exchange was made |
-| created_at | Datetime | Creation timestamp |
+### Payment creation
-**Example request :** `GET /api/v1/trades/eur`
+##### Authentication
-**Example response :**
+_The "merchant token" authentication mechanism has been removed please use an [API token](#token-authentication) or an [OAuth2 token](#oauth2-authentication) instead with the "merchant" scope._
- [
- {
- "created_at": "2013-01-22T08:19:41Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "price": 5.0,
- "traded_btc": 980.0,
- "traded_currency": 4940.0,
- "uuid": "1c86abf0-170a-4101-84d1-cdad913c95dd"
- },
- {
- "created_at": "2013-01-22T08:19:41Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "price": 6.0,
- "traded_btc": 10.0,
- "traded_currency": 60.0,
- "uuid": "170aabf0-1c86-4101-84d1-cdad913c95dd"
- }
- ]
+##### Description
-## Coupons
+A payment is created by a merchant platform when the customer chooses Bitcoin as his desired checkout option.
-Coupons are a way to easily move money between accounts, they are debited from the issuer's account upon creation and may be redeemed at anytime against any account (including the issuer).
+The merchant platform can then :
+* display the payment Bitcoin address on his own web interface,
+* include the Paymium web interface url in an iframe in order to display a payment pop-up as an overlay,
+* redirect the buyer to the payement's URL (see below), in this case the payment is displayed on a separate screen
-They are materialized by a unique redemption code. This code should be kept private as anyone having knowledge of it can redeem the funds.
+To display the payment request to the user, the `https://paymium.com/invoice/{UUID}` can be used, this is used by the e-commerce framework plugins.
-Creating a coupon requires the `withdraw` OAuth2 scope, other actions require the `read` scope.
+
+
+
-### Create a coupon (A)
+Once the payment request is displayed, the customer has 15 minutes to send the appropriate amount.
-This call issues a coupon
+Paymium notifies the merchant of the completion of his payment via the associated callback (for which an URL may be provided when creating the payment request), once one Bitcoin confirmation for the payment is received the funds are credited to the merchant's account, a callback notification is then made.
-**Request path :** `/api/v1/coupons`
-**Request method :** `POST`
+##### Endpoint
-**Request parameters**
+| method | path | authorization |
+|--------|---------------------------------|--------------------------|
+| POST | /api/v1/merchant/create_payment | oauth2 (scope: merchant) |
-| Name | Type | Description |
-|---------------------|---------|-------------------------------------------|
-| amount | Decimal | Currency value for the issued coupon |
-| currency | String | Currency in which the amount is expressed |
-**Response**
+##### Parameters
-A coupon code is returned
+| name | description | example value |
+|--------------|----------------------------------------------|--------------------|
+| amount | Amount requested for the payment (required) | 20 |
+| payment_split | Percentage of the payment the _merchant_ will get in `currency` expressed as a two-decimal places float between 0 and 1 (required) | 1.0 |
+| currency | Currency in which the merchant wishes to be credited and in which the `amount` is expressed (required) | EUR |
+| callback_url | Merchant callback URL, it is called when the state of the payment changes (optional) | http://myonlineshop/payments/order-987978/callback |
+| redirect_url | URL to which the customer should be redirected at upon payment (optional) | http://myonlineshop/payments/order-987978/success |
+| merchant_reference | Arbitrary merchant data associated to the payment (optional) | order-987978 |
-**Example request :** `POST /api/v1/coupons`
+##### Response
- {
- "amount" : 12.0,
- "currency" : "EUR"
- }
+See [Payment properties](#returned-json-object-properties)
-**Example response :**
-
- {
- "code": "BP-EUR-9660407B43799CCED320"
- }
+### Payment callbacks
-### View a coupon
+When a payment is created or updated, and if a callback URL was provided, a notification is made.
-This call will return a JSON object representing a coupon
+When the notification is made a `POST` request is made to the callback URL, it contains the JSON representation of the payment (see the [payment properties](#get-payment-information)).
-**Request path :** `/api/v1/coupons/{code}`
+The merchant should ensure the callback is legitimate by requesting confirmation from the Paymium API for the invoice data.
-**Request method :** `GET`
+**Note :** The callback notifications are not guaranteed to be unique, it must have idempotent results on the merchant side if the payment has not actually changed.
-**Request parameters**
-| Name | Type | Description |
-|------|--------|------------------|
-| code | String | Coupon code |
+### Get payment information
+This endpoint returns the payment request as a JSON object given a payment UUID
-**Response**
-A JSON object with the following parameters is returned.
+##### Endpoint
-| Name | Type | Description |
-|-----------------------|----------|-------------------------------------------|
-| uuid | UUID | Coupon account operation identifier |
-| code | String | Coupon code |
-| state | String | Coupon state _(see appendix)_ |
-| amount | Decimal | Coupon value |
-| currency | String | Currency in which the amount is expressed |
-| created\_at | Datetime | Creation timestamp |
+| Method | Path |
+|--------|-------------------------------------|
+| GET | /api/v1/merchant/get_payment/{UUID} |
-**Example request :** `GET /api/v1/coupons/BP-EUR-9660407B43799CCED320`
+##### Returned JSON object properties
-**Example response :**
-
- {
- "amount": -12.0,
- "code": "BP-EUR-9660407B43799CCED320",
- "created_at": "2013-01-30T11:52:36Z",
- "created_at_int" : 1363858355,
- "currency": "EUR",
- "state": "pending",
- "uuid": "c21adaf6-f5a2-4d93-a762-a63b89b52265"
- }
+| Name | Description |
+|--------------------|-----------------------------------------------------------------------|
+| uuid | Payment UUID |
+| currency | Currency in which the `currency_amount` is expressed |
+| payment_split | Percentage of the payment the merchant will get in `currency` |
+| state | See [payment states](#payment-states) |
+| callback_url | Merchant notification URL |
+| redirect_url | Redirection url to which the customer is redirected on success |
+| merchant_name | Name of the merchant that is displayed to the customer |
+| expires_at | Expiration timestamp |
+| merchant_reference | Reference string associated to the payment |
+| amount | Amount associated to the payment |
+| btc_amount | BTC amount to pay |
+| payment_address | Payment address |
+| created_at | Creation timestamp |
+| updated_at | Last update timestamp |
+| account_operations | Account operations made against the merchant account |
-### Redeem a coupon (A)
-This call will a redeem a coupon to the client's account. It returns an `UUID`, this identifier can be used to request details about the account operation created for the client's account by the redemption of the coupon (credit of the coupon value).
+**Example**
+```json
+{
+ "account_operations": [
+ {
+ "amount": 25.0,
+ "created_at": "2014-05-15T10:19:21.000Z",
+ "created_at_int": 1400149161,
+ "currency": "EUR",
+ "is_trading_account": false,
+ "name": "merchant_currency_payment",
+ "uuid": "afca953b-dfa6-40b6-b856-c04d548baefb"
+ }
+ ],
+ "amount": 25.0,
+ "btc_amount": 0.079945,
+ "callback_url": "http://mysite.com/wc-api/WC_Paymium/",
+ "cancel_url": "http://mysite.com/commande/panier/",
+ "comment": null,
+ "created_at": 1400147834,
+ "currency": "EUR",
+ "expires_at": 1400148734,
+ "merchant_name": "Demo SAS",
+ "merchant_reference": "888",
+ "payment_address": "1NHRnMn1831D84owh7powxtAbqfzA9aaL5",
+ "payment_split": 1.0,
+ "redirect_url": "http://mysite.com/order/checkout/order-received/888?key=wc_order_53784&order=888",
+ "state": "paid",
+ "updated_at": 1400149161,
+ "uuid": "f8e7c539-7b7b-4b63-9ccf-5fc2ca91bf0b"
+}
+```
-This call may be used to void a coupon by redeeming it against the account that issued it.
+### E-commerce frameworks plugins
-**Request path :** `/api/v1/coupons/redeem`
+The currently available plugins are available
-**Request method :** `POST`
+| Framework | Plugin URL |
+|----------------|----------------------------------------|
+| PrestaShop 1.6 | https://github.com/Paymium/prestashop |
+| WooCommerce | https://github.com/Paymium/woocommerce |
-**Request parameters**
+## Appendix
-| Name | Type | Description |
-|------|--------|------------------|
-| code | String | Coupon code |
+### Currencies
-**Response**
+The following currencies are available:
+
+| symbol | currency |
+|--------|----------|
+| EUR | Euro |
+| BTC | Bitcoin |
+
+### Order types
+
+Orders can have the following types:
+
+| type | description |
+|----------------|------------------------------------|
+| WireDeposit | wire (fiat) deposit |
+| BitcoinDeposit | BTC deposit |
+| LimitOrder | limit trade order |
+| Transfer | BTC or fiat transfer or withdraw |
+| EmailTransfer | BTC or fiat transfer by e-mail |
+| AdminOrder | special order executed by an admin |
+
+### Order properties
+
+All order types share generic properties.
+
+Each type may have additional properties as described below.
+
+##### Generic order properties
+
+| name | description | example value |
+|--------------------|-----------------------------------------|----------------------------------------|
+| uuid | unique id | "968f4580-e26c-4ad8-8bcd-874d23d55296" |
+| type | order type | "Transfer" |
+| currency | currency | "BTC" |
+| created_at | date created | "2013-10-24T10:34:37.000Z" |
+| updated_at | date updated | "2013-10-22T19:12:02.000Z" |
+| amount | currency amount | 1.0 |
+| state | order state | "executed" |
+| currency_fee | currency fee collected | 0.0 |
+| btc_fee | BTC fee collected | 0.0 |
+| comment | optional comment | |
+| account_operations | an array of account operations executed | |
+
+##### Market order specific properties
+
+| name | description | example value |
+|--------------------|-----------------------------------------|----------------------------------------|
+| direction | trade direction ("buy" or "sell") | "buy" |
+| price | price per BTC | 620.0 |
+| traded_currency | currency exchanged | 310.0 |
+| traded_btc | BTC echanged | 0.5 |
+
+##### EmailTransfer specific properties
+
+| name | description | example value |
+|--------------------|-----------------------------------------|----------------------------------------|
+| email_address | email address of the receiver | "user@example.com" |
+
+
+### Order states
+
+| name | description |
+|--------------------|----------------------------------------------------------------------------------|
+| pending_execution | order is queued and pending execution |
+| pending | order is pending, such as an unconfirmed withdrawal |
+| processing | order is processing |
+| authorized | order has been authorized, such as a confirmed withdrawal |
+| active | order is active, such as a trade order in the order book |
+| filled | order has been completely filled |
+| executed | order has been executed |
+| canceled | order has been canceled |
+
+### Email Transfer states
+
+| Name | Description |
+|--------------------|----------------------------------------------------------------------------------------|
+| pending | Email Transfer is pending the email confirmation |
+| pending_collection | Email Transfer queued and pending for the receiver registration and profile completion |
+| executed | Email Transfer has been executed |
+| expired | Email Transfer has expired |
+| canceled | Email Transfer has been canceled |
+
+### Payment states
+
+| Name | Description |
+|----------------|---------------------------------------------------------------------------------------------------------------------|
+| pending_payment| Waiting for payment |
+| processing | The correct amount has been received, waiting for a Bitcoin network confirmation |
+| paid | Payment completed, the requested amount has been credited to the merchant account |
+| error | An error has occurred, the merchant must get in touch with the support |
+| btc_forwarded | Due to an incorrect paid, the received funds could not be converted and have been credited directly to the merchant |
+| expired | Payment expired, no Bitcoins were received |
+
+### Account operation properties
+
+| name | description | example value |
+|--------------------|-----------------------------------------|----------------------------------------|
+| uuid | unique id | "a940393b-4d2f-4a5a-8a0a-3470d7419bad" |
+| currency | currency | "BTC" |
+| name | name of operation | "account_operation" |
+| created_at | date created | "2013-10-22T14:30:06.000Z" |
+| created_at_int | timestamp | 1382452206 |
+| amount | currency amount | 49.38727114 |
+| address | bitcoin address if any | "1FPDBXNqSkZMsw1kSkkajcj8berxDQkUoc" |
+| tx_hash | bitcoin transaction hash if any | "86e6e72aa559428524e035cd6b2997004..." |
+| is_trading_account | whether the trading account is targeted | false |
+
+### Ruby example
-A JSON object with the following parameters is returned.
+This example uses the OAuth2 Ruby gem.
-| Name | Type | Description |
-|-----------------------|----------|-------------------------------------------|
-| uuid | UUID | Redemption account operation identifier |
+The [`AutoRefreshToken`](https://gist.github.com/davout/edb4db0315dc417fa78d) class encapsulates this logic, it is available as a [Gist](https://gist.github.com/davout/edb4db0315dc417fa78d).
-**Example request :** `POST /api/v1/coupons`
+```ruby
+require 'oauth2'
- {
- "code": "BP-EUR-9660407B43799CCED320"
- }
+client = OAuth2::Client.new('6fcf1c32f6e14cd773a7a6640832bdbf83a5b2b8d4382e839c6aff83a8f1bb3b', '55554ecad5627f0465034c4a116e59a38d9c3ab272487a18404078ccc0b64798', site: 'https://paymium.com', authorize_url: '/api/oauth/authorize', token_url: '/api/oauth/token')
-**Example response :**
-
- {
- "uuid": "3e0004cd-158c-40d6-b8f9-f4b672e86308"
- }
+client.auth_code.authorize_url(redirect_uri: 'https://paymium.com/page/oauth/test', scope: 'basic activity trade withdraw')
+ => "https://staging.paymium.com/api/oauth/authorize?response_type=code&client_id=71a28131e16a0d6756a41aa391f1aa28b2f5a2ed4a6b911cf2bf640c8a0cc2cd&redirect_uri=https%3A%2F%2Fstaging.paymium.com%2Fpage%2Foauth%2Ftest&scope=basic+activity+trade+withdraw"
-# Appendix
+# Visit this URL in your browser, approve the request and copy the authorization code
-## Codes and types tables
+authorization_code = '9b55e27c840f59d927284fdc438ee3d8fac94b00e24d331162ddff76c1a6bcc0'
-### Currencies
+token = client.auth_code.get_token(authorization_code, redirect_uri: 'https://paymium.com/page/oauth/test')
-The following currencies are available :
-
-| Symbol | Currency |
-|--------|----------------|
-| BTC | Bitcoin |
-| EUR | Euro |
-| GBP | Pound Sterling |
-| USD | US Dollar |
-
-
-### Operation types
-
-| Type | Description |
-|-----------------------------|---------------------------------------------------------|
-| fee | Trading fee |
-| coupon | Issue of a redeemable code |
-| bitcoin_transfer | Bitcoin withdrawal |
-| wire_transfer | Wire transfer withdrawal |
-| email_transfer | Transfer of funds to an e-mail address |
-| coupon_redemption | Redemption of a redeemable code |
-| email\_transfer\_redemption | Redemption of an e-mail transfer |
-| charge | Generic charge |
-| bank_charge | Bank charge |
-| invoice_credit | Payment of an invoice you issued (credits your account) |
-| invoice_payment | Payment for an invoice (debits your account) |
-| wire_deposit | Deposit by bank wire |
-| trade | Trade |
-| reversal | Reversal |
-
-### States
-
-#### Transfer (Bitcoin transfer, Wire transfer) statuses
-
-The state of a transfer lets you check whether it has been sent out to the underlying network (banking network or Bitcoin network).
-
-| State | Description |
-|-----------|---------------------------------------|
-| pending | The transfer hasn't been sent out yet |
-| processed | The transfer has been sent out |
-
-#### Coupon statuses
-
-| State | Description |
-|----------|-----------------------------------------|
-| pending | The coupon is valid and may be redeemed |
-| redeemed | The coupon has already been redeemed |
-| canceled | The coupon was redeemed to the issuer |
-
-#### E-mail transfer statuses
-
-| State | Description |
-|----------------------|--------------------------------------------------------------------------|
-| pending_collection | The recipient hasn't claimed the e-mail transfer amount yet |
-| canceled | The e-mail transfer was canceled |
-| expired | The transfer has expired |
-| unreachable_receiver | An error occurred while sending the e-mail notification to its recipient |
-| processed | The recipient has collected the sent amount |
-
-#### Invoice statuses
-
-| State | Description |
-|----------------|-------------------------------------------------|
-| pending | The invoice is pending payment |
-| partially_paid | The invoice has a partially confirmed payment |
-| confirming | A full or over-payment is confirming |
-| paid | The invoice has a confirmed payment |
-| overpaid | The invoice has a confirmed over-payment |
-| error | The payment could not be converted as requested |
-
-#### Trade order statuses
-
-| State | Description |
-|--------------------|--------------------------------------------------------------------------------|
-| pending_execution | The order has been queued for execution |
-| active | The order has been executed but not filled it is visible in the order book (1) |
-| filled | The order has been filled |
-| canceled | The order has been canceled |
-| insufficient_funds | The order cannot execute further due to lack of funds (2) |
-
- 1. The amount shown in the order book is the amount that is actually executable given your balance, not necessarily the instructed amount
- 2. Order execution resumes as soon as more funds are available
-
-# Left TODO
-
-## Websockets
-
- * Document the socket.io API
-
-## Misc
-
- * Get an estimate (unsaved quote)
- * Add a `/me` API call
- * Add a call for account balances
- * Add order lag
+token.get('/api/v1/user').body
+=> {"name":"BC-U123456","locale":"en","balance_btc":117.56672217,"locked_btc":0.0,"balance_eur":0.0,"locked_eur":0.00995186}
+```
diff --git a/WEBSOCKETS.md b/WEBSOCKETS.md
new file mode 100644
index 00000000..c86c239c
--- /dev/null
+++ b/WEBSOCKETS.md
@@ -0,0 +1,274 @@
+# WebSocket API
+
+* [Public socket](#public-socket)
+ * [Subscribing](#subscribing)
+ * [NodeJS example](#nodejs-example)
+ * [Public Data](#public-data)
+ * [publicData.ticker](#publicdataticker)
+ * [publicData.trades](#publicdatatrades)
+ * [publicData.bids](#publicdatabids)
+ * [publicData.asks](#publicdataasks)
+* [User socket](#user-socket)
+ * [Subscribing](#subscribing-1)
+ * [NodeJS example](#nodejs-example-1)
+ * [User Data](#user-data)
+ * [userData.balance_eur](#userdatabalance_eur)
+ * [userData.locked_eur](#userdatalocked_eur)
+ * [userData.balance_btc](#userdatabalance_btc)
+ * [userData.locked_btc](#userdatalocked_btc)
+ * [userData.orders](#userdataorders)
+
+Websockets are implemented using **socket.io v1.3**.
+
+## Public socket
+
+### Subscribing
+
+You must connect your socket.io client to `paymium.com/public`, setting the path
+option to `/ws/socket.io`. When new data is available, a `stream` event is
+triggered.
+
+### NodeJS example
+
+```javascript
+var io = require('socket.io-client');
+
+var socket = io.connect('https://www.paymium.com/public', {
+ path: '/ws/socket.io'
+});
+
+console.log('CONNECTING');
+
+socket.on('connect', function() {
+ console.log('CONNECTED');
+ console.log('WAITING FOR DATA...');
+});
+
+socket.on('disconnect', function() {
+ console.log('DISCONNECTED');
+});
+
+socket.on('stream', function(publicData) {
+ console.log('GOT DATA:');
+ console.log(publicData);
+});
+```
+
+### Public data
+
+The `stream` event will emit an object when new data is available. The object
+will have properties **only for the data that changed**.
+
+#### publicData.ticker
+
+If the ticker changed, `publicData.ticker` will contains the new ticker
+information.
+
+Example:
+
+```javascript
+{
+ ticker: {
+ high: 275,
+ low: 275,
+ volume: 0.10909089,
+ bid: 205,
+ ask: 275,
+ midpoint: 240,
+ vwap: 275,
+ at: 1446464202,
+ price: 275,
+ open: 270,
+ variation: 1.8519,
+ currency: 'EUR',
+ trade_id: '460aff60-8fff-4fb0-8be5-2f8dc67758c2',
+ size: 0.03636363
+ }
+}
+```
+
+#### publicData.trades
+
+If new trades are executed, `publicData.trades` will be an array containing the
+new trades.
+
+Example:
+
+```javascript
+{
+ trades: [
+ {
+ price: 275,
+ traded_btc: 0.03636363,
+ timestamp: 1446464202000,
+ currency: 'EUR'
+ }
+ ]
+}
+```
+
+#### publicData.bids
+
+If buy orders have changed (created, changed, or deleted), `publicData.bids`
+will be an array containing the modified orders. Orders are aggregated by price.
+If `amount` is `0`, there are no more orders at this price.
+
+Example:
+
+```javascript
+{
+ bids: [
+ {
+ timestamp: 1424208720,
+ amount: 17.43992373,
+ price: 265,
+ currency: 'EUR',
+ category: 'buy'
+ }
+ ]
+}
+```
+
+#### publicData.asks
+
+If sell orders have changed (created, changed, or deleted), `publicData.asks`
+will be an array containing the modified orders. Orders are aggregated by price.
+If `amount` is `0`, there are no more orders at this price.
+
+Example:
+
+```javascript
+{
+ asks: [
+ {
+ timestamp: 1424208720,
+ amount: 17.43992373,
+ price: 275,
+ currency: 'EUR',
+ category: 'sell'
+ }
+ ]
+}
+```
+
+## User socket
+
+### Subscribing
+
+You must connect your socket.io client to `https://www.paymium.com/user`, setting the path
+option to `/ws/socket.io`.
+
+You must emit a `channel` event with the user channel id. This channel id is
+available in the user's json (`/api/v1/user`).
+
+When new data is available, a `stream` event is triggered.
+
+### NodeJS example
+```javascript
+var io = require('socket.io-client');
+
+var socket = io.connect('https://www.paymium.com/user', {
+ path: '/ws/socket.io'
+});
+
+console.log('CONNECTING');
+
+socket.on('connect', function() {
+ console.log('CONNECTED');
+ console.log('WAITING FOR DATA...');
+});
+
+// Replace USER_CHANNEL_ID with the channel id of the user
+socket.emit('channel', 'USER_CHANNEL_ID');
+
+socket.on('disconnect', function() {
+ console.log('DISCONNECTED');
+});
+
+socket.on('stream', function(userData) {
+ console.log('GOT DATA:');
+ console.log(userData);
+});
+```
+
+### User data
+
+The `stream` event will emit an object when new data is available. The object
+will have properties **only for the data that changed**.
+
+#### userData.balance_eur
+
+If the available EUR balance changed, `userData.balance_eur` will contain the
+new balance.
+
+```javascript
+{
+ balance_eur: 410.04
+}
+```
+
+#### userData.locked_eur
+
+If the locked EUR balance changed, `userData.locked_eur` will contain the
+new balance.
+
+```javascript
+{
+ locked_eur: 20.24
+}
+```
+
+#### userData.balance_btc
+
+If the available BTC balance changed, `userData.balance_btc` will contain the
+new balance.
+
+```javascript
+{
+ balance_btc: 53.29811458
+}
+```
+
+#### userData.locked_btc
+
+If the locked BTC balance changed, `userData.locked_btc` will contain the
+new balance.
+
+```javascript
+{
+ locked_btc: 0
+}
+```
+
+#### userData.orders
+
+If user orders have changed (created, filled, cancelled, etc...),
+`userData.orders` will be an array containing the modified orders. You can check
+the state of the orders to handle them properly.
+
+Example:
+
+```javascript
+{
+ orders: [
+ {
+ uuid: '89d4b612-5e6a-4154-94f3-120d03f4e891',
+ amount: null,
+ currency_amount: 10,
+ state: 'pending_execution',
+ btc_fee: 0,
+ currency_fee: 0,
+ updated_at: '2015-11-02T11:36:41.000Z',
+ created_at: '2015-11-02T11:36:41.000Z',
+ currency: 'EUR',
+ comment: null,
+ type: 'MarketOrder',
+ traded_btc: 0,
+ traded_currency: 0,
+ direction: 'buy',
+ price: null,
+ account_operations: []
+ }
+ ]
+}
+```
diff --git a/contrib/quickfixtest.py b/contrib/quickfixtest.py
new file mode 100644
index 00000000..87a56424
--- /dev/null
+++ b/contrib/quickfixtest.py
@@ -0,0 +1,131 @@
+import time
+import quickfix as fix
+import quickfix44 as fixMsg
+
+USERNAME = 'PYTHON_TESTS'
+SENDERCOMPID = 'TEST_CLIENT'
+FIX44FILE = './FIX44.xml'
+DEBUG = False
+
+
+class MyApplication(fix.Application):
+
+ def onCreate(self, sessionID):
+ pass
+
+ def onLogon(self, sessionID):
+ pass
+
+ def onLogout(self, sessionID):
+ pass
+
+ def toAdmin(self, message, sessionID):
+ msg_type = message.getHeader().getField(fix.MsgType()).getString()
+ if msg_type == fix.MsgType_Logon:
+ message.setField(fix.Username(USERNAME))
+ message.setField(fix.ResetSeqNumFlag(True))
+
+ def toApp(self, message, sessionID):
+ pass
+
+ def fromAdmin(self, message, sessionID):
+ passr
+
+ def fromApp(self, message, sessionID):
+ msg_type = message.getHeader().getField(fix.MsgType()).getString()
+ depth = {}
+ if msg_type == fix.MsgType_MarketDataSnapshotFullRefresh:
+ group = fixMsg.MarketDataSnapshotFullRefresh.NoMDEntries()
+ nb_entries = int(message.getField(fix.NoMDEntries()).getString())
+ for i in range(1, nb_entries + 1):
+ message.getGroup(i, group)
+ md_type = group.getField(fix.MDEntryType()).getString()
+ md_price = group.getField(fix.MDEntryPx()).getString()
+ md_amount = group.getField(fix.MDEntrySize()).getString()
+ if not md_amount:
+ md_amount = 0
+ order = {'price': float(md_price), 'amount': float(md_amount)}
+ if md_type == fix.MDEntryType_OFFER:
+ if 'asks' not in depth:
+ depth['asks'] = []
+ depth['asks'].append(order)
+ if md_type == fix.MDEntryType_BID:
+ if 'bids' not in depth:
+ depth['bids'] = []
+ depth['bids'].append(order)
+ print("Received a full market data snapshot: %s" % (depth))
+ elif msg_type == fix.MsgType_MarketDataIncrementalRefresh:
+ group = fixMsg.MarketDataIncrementalRefresh.NoMDEntries()
+ nb_entries = int(message.getField(fix.NoMDEntries()).getString())
+ for i in range(1, nb_entries + 1):
+ message.getGroup(i, group)
+ md_type = group.getField(fix.MDEntryType()).getString()
+ md_price = group.getField(fix.MDEntryPx()).getString()
+ md_amount = group.getField(fix.MDEntrySize()).getString()
+ if not md_amount:
+ md_amount = 0
+ order = {'price': float(md_price), 'amount': float(md_amount)}
+ if md_type == fix.MDEntryType_OFFER:
+ if 'asks' not in depth:
+ depth['asks'] = []
+ depth['asks'].append(order)
+ if md_type == fix.MDEntryType_BID:
+ if 'bids' not in depth:
+ depth['bids'] = []
+ depth['bids'].append(order)
+ print("Received an incremental market data update: %s" % (depth))
+
+def main():
+ sessionID = fix.SessionID('FIX.4.4', SENDERCOMPID, 'PAYMIUM')
+
+ params = fix.Dictionary()
+ params.setString('ConnectionType', 'initiator')
+ params.setString('StartTime', '00:00:00')
+ params.setString('EndTime', '00:00:00')
+ params.setString('HeartBtInt', '30')
+ params.setString('CheckLatency', 'Y')
+ params.setString('SocketConnectHost', '195.154.171.115')
+ params.setString('SocketConnectPort', '8359')
+ params.setString('DataDictionary', FIX44FILE)
+ params.setString('EncryptMethod', '0')
+
+ settings = fix.SessionSettings()
+ settings.set(sessionID, params)
+
+ application = MyApplication()
+ factory = fix.FileStoreFactory("store")
+ acceptor = fix.SocketInitiator(application, factory, settings, fix.ScreenLogFactory(DEBUG, DEBUG, DEBUG))
+ acceptor.start()
+
+ time.sleep(2)
+
+ mdr = fixMsg.MarketDataRequest()
+ mdr.setField(fix.MDReqID("MDRQ-%d" % (time.time() * 1000000)))
+ # We want the full book here, not just the top
+ mdr.setField(fix.MarketDepth(1))
+ # We want to get a snapshot and also subscribe to the market depth updates
+ mdr.setField(fix.SubscriptionRequestType(
+ fix.SubscriptionRequestType_SNAPSHOT_PLUS_UPDATES))
+ # We'll want only incremental refreshes when new data is available
+ mdr.setField(fix.MDUpdateType(fix.MDUpdateType_INCREMENTAL_REFRESH))
+ # Specify the currency
+ instruments = fixMsg.MarketDataRequest().NoRelatedSym()
+ instruments.setField(fix.Symbol("EUR/XBT"))
+ mdr.addGroup(instruments)
+ # Specify that we'll want the bids and asks
+ mdr.setField(fix.NoMDEntryTypes(2))
+ group = fixMsg.MarketDataRequest().NoMDEntryTypes()
+ group.setField(fix.MDEntryType(fix.MDEntryType_BID))
+ group.setField(fix.MDEntryType(fix.MDEntryType_OFFER))
+ mdr.addGroup(group)
+
+ fix.Session.sendToTarget(mdr, sessionID)
+
+ while True:
+ time.sleep(10)
+
+ acceptor.stop()
+
+if __name__ == '__main__':
+
+ main()
diff --git a/create-api-token.png b/create-api-token.png
new file mode 100644
index 00000000..41d50259
Binary files /dev/null and b/create-api-token.png differ
diff --git a/display-invoice.png b/display-invoice.png
new file mode 100644
index 00000000..92c345d9
Binary files /dev/null and b/display-invoice.png differ
diff --git a/examples/node.js/README.md b/examples/node.js/README.md
new file mode 100644
index 00000000..6979b1e5
--- /dev/null
+++ b/examples/node.js/README.md
@@ -0,0 +1,20 @@
+## bcjs
+
+This is an example of how to use the Bicoin-Central API using Node.js, including handling OAuth2 callbacks and refresh tokens.
+
+USE AT YOUR OWN RISK!
+
+### Configuration
+
+To use, you must register an application on Bitcoin-Central with redirection URI set to `http://localhost:8000/callback`.
+
+Configuration is stored in `config.js`. You must set `appKey` and `appSecret` to your application's key and secret.
+
+### Installation
+
+1. install node.js
+2. download this package
+3. run `npm install`
+4. run `npm link`
+5. launch the app using `bcjs`
+6. type `help` for a list of commands
diff --git a/examples/node.js/config.js b/examples/node.js/config.js
new file mode 100644
index 00000000..98d6566a
--- /dev/null
+++ b/examples/node.js/config.js
@@ -0,0 +1,15 @@
+var path = require('path');
+
+module.exports = {
+ appKey: '33be5e031fbe0f72827609503a2f7d100d62d7e6f31375bb7ba54a9abc2475c0',
+ appSecret: 'd0c9527d343c43de642d57acb5303b6b5e036a329341b799431dd7cb7f740e50',
+
+ scopes: 'basic activity trade withdraw',
+
+ apiBaseUrl: 'https://paymium.com/api',
+
+ serverBaseUrl: 'http://localhost:8000',
+ serverPort: 8000,
+
+ tokenFile: path.resolve(__dirname, 'tokens')
+};
diff --git a/examples/node.js/index.js b/examples/node.js/index.js
new file mode 100755
index 00000000..345dd221
--- /dev/null
+++ b/examples/node.js/index.js
@@ -0,0 +1,491 @@
+#! /usr/bin/env node
+
+// Node.js cli example
+
+var config = require('./config'),
+ express = require('express'),
+ app = express(),
+ request = require('request'),
+ cli = require('cline')(),
+ fs = require('fs'),
+ open = require('open'),
+ easycrypto = require('easycrypto').getInstance(),
+ babar = require('babar');
+
+// Known order uuids
+var knownUuids = {};
+
+// OAuth2 configuration
+var OAuth2 = require('simple-oauth2')({
+ clientID: config.appKey,
+ clientSecret: config.appSecret,
+ site: config.apiBaseUrl,
+ tokenPath: '/oauth/token'
+});
+
+// Authorization uri definition
+var authorization_uri = OAuth2.AuthCode.authorizeURL({
+ redirect_uri: config.serverBaseUrl + '/callback',
+ scope: config.scopes
+});
+
+// Authorization page redirecting to Bitcoin-Central
+app.get('/auth', function (req, res) {
+ res.redirect(authorization_uri);
+});
+
+// Callback service parsing the authorization token and asking for the access token
+var afterAuth;
+app.get('/callback', function (req, res) {
+ var code = req.query.code;
+
+ OAuth2.AuthCode.getToken({
+ code: code,
+ redirect_uri: config.serverBaseUrl + '/callback'
+ }, saveToken);
+
+ function saveToken(error, tokens) {
+ if (error) {
+ console.error(error.message);
+ return res.send(error.message);
+ }
+
+ res.send('You may close this window.');
+
+ cli.password('choose a password: ', '*', function(pwd) {
+ var data = easycrypto.encrypt(JSON.stringify(tokens), pwd);
+ fs.writeFileSync(config.tokenFile, data, {encoding: 'utf8'});
+
+ access_token = tokens.access_token;
+ expires = new Date(new Date().getTime() + 1000 * tokens.expires_in);
+
+ if(afterAuth) afterAuth();
+ afterAuth = null;
+ });
+ }
+});
+
+// Refresh tokens
+function refreshTokens(cb) {
+ function doIt() {
+ cli.password('enter password: ', '*', function(pwd) {
+ try {
+ var tokens = JSON.parse(easycrypto.decrypt(fs.readFileSync(config.tokenFile, {
+ encoding: 'utf8'
+ }), pwd));
+ }
+ catch(e) {
+ return doIt();
+ }
+
+ OAuth2.AccessToken.create(tokens).refresh(function(error, result) {
+ if (!error) {
+ var tokens = result.token;
+ var data = easycrypto.encrypt(JSON.stringify(tokens), pwd);
+ fs.writeFileSync(config.tokenFile, data, {encoding: 'utf8'});
+ access_token = tokens.access_token;
+ expires = new Date(new Date().getTime() + 1000 * tokens.expires_in)
+ }
+
+ if(cb) cb(error);
+ });
+ });
+ }
+
+ doIt();
+};
+
+// Convert trade orders to string
+function tradeOrdersToString(data) {
+ output = '';
+
+ data.forEach(function(order) {
+ knownUuids[order.uuid] = true;
+ output += order.uuid + '\t';
+ output += order.direction + '\t';
+ output += order.amount.toFixed(8) + ' BTC for ';
+ output += order.price.toFixed(2) + ' ' + order.currency;
+ output += ' (' + order.traded_btc.toFixed(8) + ' BTC traded)'
+ output += '\t' + order.state + '\n'
+ });
+
+ return output;
+}
+
+// Try to match incomplete uuid to know ones
+function matchUuid(uuid) {
+ if(uuid.length === 36) {
+ return [uuid];
+ }
+
+ var matches = [];
+
+ for (key in knownUuids) {
+ if(key.indexOf(uuid) === 0) {
+ matches.push(key);
+ }
+ }
+
+ return matches;
+}
+
+// Register an API command
+var access_token;
+var expires;
+
+function addApiCommand(cmd, path, options, cb) {
+ options = options || {};
+
+ cli.command(cmd, cmd.desc, options.args, function (input, args) {
+ if(options.restricted && !access_token) {
+ delete cli._nextTick;
+
+ if (fs.existsSync(config.tokenFile)) {
+ return refreshTokens(doRequest);
+ }
+ else {
+ var url = config.serverBaseUrl + '/auth';
+ cli.stream.print('opening ' + url + ' in your browser...');
+ afterAuth = doRequest;
+ return open(url);
+ }
+ }
+
+ var state;
+
+ function doRequest() {
+ delete cli._nextTick;
+
+ if (options.confirm) {
+ delete cli._nextTick;
+ cli.confirm(options.confirm(input, args) + ' (y/n) ', function(ok) {
+ if (ok) {
+ runRequest();
+ }
+ else {
+ cli.interact('> ');
+ }
+ });
+ }
+ else {
+ runRequest();
+ }
+
+ function runRequest() {
+ options.headers = options.headers || {};
+
+ if(options.restricted) {
+ options.headers['Authorization'] = 'Bearer ' + access_token;
+ }
+
+ var pathStr = path;
+
+ if (typeof path === 'function') {
+ pathStr = path(input, args);
+
+ if (!pathStr) {
+ return cli.interact('> ');
+ }
+ }
+
+ if (typeof options.payload === 'function') {
+ options.form = options.payload(input, args);
+ }
+
+ request(config.apiBaseUrl + pathStr, options, function(error, resp, body) {
+ if (error) {
+ cli.stream.print(error.message);
+ return cli.interact('> ');
+ }
+
+ if (resp.statusCode === 401) {
+ if (access_token && !state) {
+ refreshTokens(function(error) {
+ state = 'refreshed';
+ doRequest();
+ });
+ }
+ else if (state == 'refreshed') {
+ state = 'authorizing';
+ var url = config.serverBaseUrl + '/auth';
+ cli.stream.print('opening ' + url + ' in your browser...');
+ afterAuth = doRequest;
+ open(url);
+ }
+ else {
+ cli.stream.print('unauthorized');
+ cli.interact('> ');
+ }
+
+ return;
+ }
+
+ if (resp.statusCode === 422) {
+ cli.stream.print(JSON.parse(body).errors);
+ return cli.interact('> ');
+ }
+
+ var data = {};
+
+ try {
+ var data = JSON.parse(body);
+ } catch(e) {}
+
+ cli.stream.print(cb(data));
+ cli.interact('> ');
+ });
+ }
+ }
+
+ doRequest();
+ });
+}
+
+// Ticker command
+addApiCommand('ticker', '/v1/data/eur/ticker', {
+ desc: 'show ticker'
+}, function(data) {
+ return JSON.stringify(data, true, '\t');
+});
+
+// Depth command
+addApiCommand('depth', '/v1/data/eur/depth', {
+ desc: 'show market depth',
+}, function(data) {
+ var bids = data.bids.slice(0).sort(function(a, b) {return b.price - a.price;});
+ var asks = data.asks.slice(0).sort(function(a, b) {return a.price - b.price;});
+
+ var mid = .5 * (bids[0].price + asks[0].price);
+ var min = Math.floor(mid * .2);
+ var max = Math.ceil(mid * 1.8);
+
+ bids = bids.filter(function(i) {return i.price >= min;});
+ asks = asks.filter(function(i) {return i.price <= max;});
+
+ var points = [];
+
+
+
+ for (var i = 0, c = 0; i < bids.length; i++) {
+ var p = bids[i];
+ c += p.amount;
+ points.unshift([p.price, c]);
+ };
+
+ for (var i = 0, c = 0; i < asks.length; i++) {
+ var p = asks[i];
+ c += p.amount;
+ points.push([p.price, c]);
+ };
+
+ return babar(points, {
+ width: process.stdout.columns,
+ height: process.stdout.rows - 1
+ });
+});
+
+// Balances command
+addApiCommand('balances', '/v1/user', {
+ desc: 'show account balances',
+ restricted: true
+}, function(data) {
+ var output = '';
+
+ output += 'Currency\tAccount\t\tBalance\n';
+ output += 'BTC\t\tavailable\t' + data.balance_btc + '\n';
+ output += 'BTC\t\ttrading\t\t' + data.locked_btc + '\n';
+ output += 'EUR\t\tavailable\t' + data.balance_eur + '\n';
+ output += 'EUR\t\ttrading\t\t' + data.locked_eur;
+
+ return output;
+});
+
+// Active command
+addApiCommand('active', '/v1/user/orders', {
+ desc: 'show active trade orders',
+ restricted: true,
+ qs: {
+ 'types[]': 'LimitOrder',
+ active: true
+ }
+}, function(data) {
+ return tradeOrdersToString(data);
+});
+
+// Orders command
+addApiCommand('orders', '/v1/user/orders', {
+ desc: 'show all tade orders',
+ restricted: true,
+ qs: {
+ 'types[]': 'LimitOrder'
+ }
+}, function(data) {
+ return tradeOrdersToString(data);
+});
+
+// Show command
+addApiCommand('show {uuid}', function(input, args) {
+ var uuids = matchUuid(args.uuid);
+
+ if(uuids.length === 0) {
+ cli.stream.print('no matching uuid');
+ }
+ else if(uuids.length === 1) {
+ return '/v1/user/orders/' + uuids[0];
+ }
+ else {
+ cli.stream.print('multiple matching uuids: ' + uuids);
+ }
+}, {
+ desc: 'show all orders',
+ restricted: true,
+ args: {
+ uuid: '[0-9a-z\-]+'
+ }
+}, function(data) {
+ return JSON.stringify(data, true, '\t');
+});
+
+// Buy command
+addApiCommand('buy {amount} {price}', '/v1/user/orders', {
+ desc: 'place a buy order',
+ restricted: true,
+ method: 'POST',
+ args: {
+ amount: '[0-9\.]+',
+ price: '[0-9\.]+'
+ },
+ confirm: function(input, args) {
+ return "buy " + args.amount + " BTC for " + args.price + " EUR each?";
+ },
+ payload: function(input, args) {
+ return {
+ 'type': 'LimitOrder',
+ currency: 'EUR',
+ direction: 'buy',
+ amount: args.amount,
+ price: args.price
+ }
+ }
+}, function(data) {
+ knownUuids[data.uuid] = true;
+ return data.uuid;
+});
+
+// Sell command
+addApiCommand('sell {amount} {price}', '/v1/user/orders', {
+ desc: 'place a sell order',
+ restricted: true,
+ method: 'POST',
+ args: {
+ amount: '[0-9\.]+',
+ price: '[0-9\.]+'
+ },
+ confirm: function(input, args) {
+ return "sell " + args.amount + " BTC for " + args.price + " EUR each?";
+ },
+ payload: function(input, args) {
+ return {
+ 'type': 'LimitOrder',
+ currency: 'EUR',
+ direction: 'sell',
+ amount: args.amount,
+ price: args.price
+ }
+ }
+}, function(data) {
+ knownUuids[data.uuid] = true;
+ return data.uuid;
+});
+
+// Cancel command
+addApiCommand('cancel {uuid}', function(input, args) {
+ var uuids = matchUuid(args.uuid);
+
+ if(uuids.length === 0) {
+ cli.stream.print('no matching uuid');
+ }
+ else if(uuids.length === 1) {
+ return '/v1/user/orders/' + uuids[0] + '/cancel';
+ }
+ else {
+ cli.stream.print('multiple matching uuids: ' + uuids);
+ }
+}, {
+ desc: 'cancel a trade order',
+ restricted: true,
+ method: 'DELETE',
+ args: {
+ uuid: '[0-9a-z\-]+'
+ }
+}, function(data) {
+ return 'cancel requested';
+});
+
+// Withdraw EUR command
+addApiCommand('withdraw_eur {amount}', '/v1/user/orders', {
+ desc: 'withdraw eur',
+ restricted: true,
+ method: 'POST',
+ args: {
+ amount: '[0-9\.]+'
+ },
+ confirm: function(input, args) {
+ return "withdraw " + args.amount + " EUR?";
+ },
+ payload: function(input, args) {
+ return {
+ 'type': 'Transfer',
+ currency: 'EUR',
+ amount: args.amount
+ }
+ }
+}, function(data) {
+ knownUuids[data.uuid] = true;
+ return data.uuid;
+});
+
+// Withdraw BTC command
+addApiCommand('withdraw_btc {amount} {address}', '/v1/user/orders', {
+ desc: 'withdraw eur',
+ restricted: true,
+ method: 'POST',
+ args: {
+ amount: '[0-9\.]+',
+ address: '[13][1-9A-HJ-NP-Za-km-z]{26,33}'
+ },
+ confirm: function(input, args) {
+ return "withdraw " + args.amount + " BTC to " + args.address + " ?";
+ },
+ payload: function(input, args) {
+ return {
+ 'type': 'Transfer',
+ currency: 'BTC',
+ amount: args.amount,
+ address: args.address
+ }
+ }
+}, function(data) {
+ knownUuids[data.uuid] = true;
+ return data.uuid;
+});
+
+// TTL command
+cli.command('ttl', 'show access token time to live', function () {
+ if (access_token) {
+ var time = expires.getTime() - new Date().getTime();
+ cli.stream.print(Math.ceil(time / 1000 / 60) + ' min');
+ }
+ else {
+ cli.stream.print('no access token');
+ }
+});
+
+console.log('Welcome to Bitcoin-Central JS. Type `help` for help.');
+
+app.listen(config.serverPort);
+cli.interact('> ');
+
+cli.on('close', function () {
+ process.exit();
+});
diff --git a/examples/node.js/package.json b/examples/node.js/package.json
new file mode 100644
index 00000000..7218c710
--- /dev/null
+++ b/examples/node.js/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "bitcoin_central_example",
+ "version": "0.0.0",
+ "description": "Bitcoin-Central API Example",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "Paymium",
+ "license": "MIT",
+ "dependencies": {
+ "simple-oauth2": "~0.1.8",
+ "express": "~3.4.7",
+ "request": "~2.31.0",
+ "cline": "~0.7.0",
+ "open": "0.0.4",
+ "easycrypto": "~0.1.1",
+ "babar": "0.0.3"
+ },
+ "preferGlobal": "true",
+ "bin": {
+ "bcjs": "index.js"
+ }
+}
diff --git a/examples/public_socket.js/README.md b/examples/public_socket.js/README.md
new file mode 100644
index 00000000..fb9e1416
--- /dev/null
+++ b/examples/public_socket.js/README.md
@@ -0,0 +1,12 @@
+## WebSocket
+
+This is an example of how to connect to the Bitcoin-Central WebSocket with node.js .
+
+It simply prints the data received to the console.
+
+### Installation
+
+1. install node.js
+2. download this package
+3. run `npm install`
+4. run `node client.js`
diff --git a/examples/public_socket.js/client.js b/examples/public_socket.js/client.js
new file mode 100644
index 00000000..bb00c957
--- /dev/null
+++ b/examples/public_socket.js/client.js
@@ -0,0 +1,21 @@
+var io = require('socket.io-client');
+
+var socket = io.connect('https://www.paymium.com/public', {
+ path: '/ws/socket.io'
+});
+
+console.log('CONNECTING');
+
+socket.on('connect', function() {
+ console.log('CONNECTED');
+ console.log('WAITING FOR DATA...');
+});
+
+socket.on('disconnect', function() {
+ console.log('DISCONNECTED');
+});
+
+socket.on('stream', function(data) {
+ console.log('GOT DATA:');
+ console.log(data);
+});
diff --git a/examples/public_socket.js/package.json b/examples/public_socket.js/package.json
new file mode 100644
index 00000000..6f25df7a
--- /dev/null
+++ b/examples/public_socket.js/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "bitcoin_central_public_socket_client",
+ "version": "0.0.0",
+ "description": "Bitcoin-Central Public Socket Example",
+ "main": "client.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "Paymium",
+ "license": "MIT",
+ "dependencies": {
+ "socket.io-client": "1.3.x"
+ }
+}
diff --git a/logo.png b/logo.png
new file mode 100644
index 00000000..34d2a1f2
Binary files /dev/null and b/logo.png differ