NAV
javascript

Introduction

This is the documentation for Coinify application APIs.

Environments

The following environments are available

Environment Base URL BTC Blockchain
Production https://app-api.coinify.com Mainnet
Sandbox https://app-api.sandbox.coinify.com Testnet3

Response format

The API always responds with a HTTP status code and usually a JSON object in the response body. This JSON object carries the data of the response, or an error object which provides more information about an error than the HTTP status code. If the endpoint doesn’t return any data, the response body is empty.

You can determine whether a call was successful or not by checking the HTTP status code.

All timestamps used in requests and responses are in ISO 8601 format.

Success format

The body of a successful response (HTTP status code is 2xx) will always be a JSON object or an empty body (if no data needs to be returned).

The contents of the response JSON object depends entirely on the endpoint and the type of operation performed.

Error format

In addition to the JSON response body seen below, a failed request always returns with a 4xx or 5xx HTTP status code.

{
  "error": "api_key_required",
  "error_description": "Please provide a valid API key for this operation.",
  "error_uri": "https://www.coinify.com/merchant/api"
}

The url field is optional and does not appear in all error requests.

Whenever a request fails (the HTTP status code is 4xx or 5xx), the API returns a JSON object with two or three strings:

Authentication

In order to call most of the API endpoints, one needs to obtain an access token. This token is currently obtainable by authenticating yourself to the system.

This section describes how to do just that.

Example Authorization header with an access token

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Once you have obtained your access token, you must include it in all requests that require authentication. You do so by adding a Authorization header to the request with the value Bearer <access-token> as seen in the example on the right.

Failure to include an access token when accessing protected resources will result in a 401 Unauthorized response, while a 403 Forbidden means that you don’t have access to the protected resource.

Authenticate

Example success response body

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ",
  "token_type": "bearer",
  "expires_in": 1200, // Lifetime of access token in seconds
  "refresh_token": "wt5RoH8i6HkSQvI8kFpEBLEIB6lw8lOpYKHEz0ND9znDaAOtH1dFI32GqhvT9PGC"
}

POST https://app-api.coinify.com/auth

In order to obtain an access token, you must authenticate yourself using one of the authentication methods.

When a successful authentication has been performed, you will receive an access token and a refresh token as exemplified in the response to the right. You must use this access token to authenticate yourself to most other endpoints.

You must include a grant_type parameter (string) in the request which defines the authentication method. The authentication endpoint currently supports the following grant_types:

The possible response types, regardless of the grant_type used, are listed in the following table:

HTTP Response code JSON data
200 OK Success, Response with a fresh authentication token. See example to the right.
400 Bad request Error, see OAuth2 Error Response for possible error codes.

Email authentication

Example request with grant_type == "password"

{
  "grant_type": "password",
  "email": "user@coinify.com",
  "partnerId": 11,
  "password": "password"
}

Use this grant_type to authenticate a user with a combination of email address and password.

Request parameter Type Description
grant_type string password - Authenticate using email and password.
partnedId integer Id of the partner the user belongs to.
email string Email address of user to authenticate.
password string User’s password.

Refresh access token

Example request with grant_type == "refresh_token"

{
  "grant_type": "refresh_token",
  "refresh_token": "wt5RoH8i6HkSQvI8kFpEBLEIB6lw8lOpYKHEz0ND9znDaAOtH1dFI32GqhvT9PGC"
}

The access token that you received upon authentication is only valid for 20 minutes. After the token has expired, you can obtain a new one by either (1) re-authenticating or by (2) refreshing your token. This endpoint allows you to refresh your token without requiring the user to re-authenticate.

Request parameter Type Description
grant_type string refresh_token - Refresh using a refresh token.
refresh_token string The refresh token obtained from a previous authentication response.

Offline token

Example request with grant_type == "offline_token"

{
    "grant_type": "offline_token",
    "offline_token": "A3873gbnvgHgniehfq8QHkSQvI8kFpEBsiudhAS83Nat2g7ASB2GqhvT9PGC"
}

Example success response body for a request with an Offline token

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ",
  "token_type": "bearer",
  "expires_in": 1200 // Lifetime of access token in seconds
}

The offline token is used exactly as you would use a refresh token, except that it doesn’t expire. (When you have an offline token, there is no need to also use a refresh token).

This token does not expire (it’s life-long).

Request parameter Type Description
grant_type string offline_token - Authenticate using an offline token, that does not expire.
offline_token string The offline token obtained upon signup

Sign out (Revoke refresh token)

Example request

{
  "token_type_hint": "refresh_token",
  "token": "wt5RoH8i6HkSQvI8kFpEBLEIB6lw8lOpYKHEz0ND9znDaAOtH1dFI32GqhvT9PGC"
}

POST https://app-api.coinify.com/auth/revoke

If the user wants to sign out, the client will have to revoke the refresh token and “forget” the current access token. This endpoint allows you to revoke a refresh token, so it is no longer valid.

Request parameter Type Description
token_type_hint string Must be refresh_token
token string The refresh token obtained from the authentication response

The possible response types are listed in the following table:

HTTP Response code JSON data
204 No Content Success, Empty response body
400 Bad request Error, see OAuth2 Error Response for possible error codes.

Deactivate account

PUT https://user.coinify.com/me/deactivate

If you wish to deactivate your account, you can make the above request. The only expected payload is the Authentication HTTP Header.

You can only deactivate your own account.

A deactivated account can not obtain an access token and thus is unable to use the parts of the API that require an access token.

Response
HTTP Response code JSON data
204 No Content Success, Empty response body
500 Server Error Error, fulfilling the request.

Signup

Currently, only trader signup is supported.

The signup endpoints reside under https://app-api.coinify.com/signup.

Trader signup

Minimal example request for POST /signup/trader

{
  "email": "trader@example.com",
  "profile": {
    "address": {
      "country": "US"
    }
  }
}

Maximal example request for POST /signup/trader

{
  "partnerId": 123,
  "contractId": 444,
  "email": "trader@example.com",
  "password": "mypassword",
  "defaultCurrency": "EUR",
  "profile": {
    "name": "John Doe",
    "dateOfBirth": "1970-01-01",
    "gender": "male",
    "address": {
      "street": "123 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    },
    "mobile": {
      "countryCode": 1,
      "number": "555-1337"
    }
  },
  "generateOfflineToken": true,
  "consentAdditionalMails": true
}

Example response for POST /signup/trader

{
  "trader": {
    "id": 754035,
    "email": "trader@example.com",
    "defaultCurrency": "EUR",
    "profile": {
      "name": "John Doe",
      "gender": "male",
      "address": {
        "street": "123 Example Street",
        "zipcode": "12345",
        "city": "Exampleville",
        "state": "CA",
        "country": "US"
      },
      "mobile": {
        "countryCode": 1,
        "number": "555-1337"
      }
    },
    "level": {}, // Information about trader's current level
    "consentAdditionalMails": true
  },
  // Offline token, only included if requested explicitly, and only in the signup response.
  "offlineToken": "aGFja2VydHlwZXIuY29tIGlzIG15IElERQ=="
}

POST https://app-api.coinify.com/signup/trader

This endpoint allows you to sign up a new trader

Request object

The parameters in the request object are as follows:

Parameter Type Default Description
email String Required Email address of the new trader (and user)
password String null The password of the user used in combination with the email address to sign in. If omitted or null, user cannot sign in until they manually reset their password.
partnerId Integer null Provide a Coinify partner ID to associate this trader with a specific Coinify partner. If omitted or null, trader will not be associated with any partner.
contractId  Integer null Provide a contract if the trader should be associated with another contract than the default contract of the partner. (partnerId must be provided and contractId must reference a contract where partner is included.)
defaultCurrency String "EUR" Default fiat currency (ISO 4217) for trader. Defaults to "EUR" if not set. Can be changed later using the Update trader information endpoint.
profile Object null Object with additional information about the trader.
name String null Trader’s full name
dateOfBirth String null Trader’s date of birth (in format YYYY-MM-DD) or null if unknown. NOTE: The updated date of birth is not shown in the trader object for security reason.
gender String null Trader’s gender. Must be either null, "male", or "female"
address Object  null Object with information about the trader’s physical address.
    →street String null Street address
    →zipcode String null Zip/Postal code
    →city String null City
    →state String null ISO 3166-2 state/province
    →country String Required ISO 3166-1 alpha-2 country code.
mobile Object /
String
null If object provided, object with information about the trader’s primary mobile phone.
If string provided, a string containing both the country code and the phone number.
    →countryCode Integer null Country code of mobile phone number without leading zeroes or plus (+)
    → number String null Mobile phone number
trustedEmailValidationToken String null (Only for trusted Coinify partners, partnerId must be provided) Signed message from partner for automatic validation of email. See Trusted email validation.
generateOfflineToken Boolean false Also generate and return an offline token for the new trader. If set to true, an offline token is created for the new trader and returned in the response with the key offlineToken.
consentAdditionalMails Boolean null Determines whether the user consents to receive additional email from Coinify.
Response object

The success response object contains the following fields:

Key Type Description
trader Object Trader object as specified in Trader object
offlineToken String (Optional) An offline token for the new trader. Only created and returned if the generateOfflineToken request parameter is explicitly set to true
Error object

If the signup request fails for some reason, the response contains the first error encountered during the signup process:

HTTP status code Error code Description
201 N/A Signup successful
400 invalid_request There was something wrong with the signup request. See the error_description argument for a specific, human-readable error message.
400 email_address_and_partner_id_in_use The provided email address is already associated with an existing trader that belongs to the specified partner.
400 invalid_trusted_email_validation_token The supplied trustedEmailValidationToken was invalid.
500 internal_error An internal error happened during signup. Please try again later.

Email validation

When signing up a trader with Coinify, we have to ensure that the email address provided is valid and that the new trader can receive emails sent to that address. This can happen in one of two ways:

Manual validation

As the name suggests, a manual validation requires manual action from the new user. Namely they must retrieve the mail that we have sent to the provided email address, and do one of the following to prove that the email address is valid and under the user’s control:

Manual validation API endpoint

Example request to POST /signup/validate-email

{
  "email": "johndoe@example.com",
  "token": "a7da4b9ad83256bd90fd0b5952fdeb2b"
}

Example response to the above request

{
  "success": true
}

POST https://app-api.coinify.com/signup/validate-email

Validate the email address of a user with the token sent in an email to the user’s email address.

Request object

The parameters in the request object are as follows:

Parameter Type Default Description
email String Required Email address to validate.
token String Required Email validation token received in an email
Response object

The success response object contains the following fields:

Key Type Description
success Boolean Always true

Trusted validation

While the manual validation described previously is easier to implement, it sometimes doesn’t make sense to perform an additional email validation from a user experience perspective - if the user is signing up for Coinify through a partner, the partner will most likely already have validated the user’s email address. In this case, the partner can issue a signed message to the user stating that the email address has already been validated by the partner.

Coinify then trusts the partner to have validated the email address themselves, and the email address is immediately marked as validated, and the user won’t have to perform any manual action to validate the email address to Coinify.

Example of 2048-bit RSA public key in PEM format.
Coinify must have the partner’s public key (RSA/EC) in advance for trusted validation to work

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3joQFkg6LXuR2PvFDiZn
fOlF5edR4nEUxTErLlvjg00cus/MvgP8QwKhVYMlfNqEqa2N6vWeLyT0reJ8KKBl
6M7BKnxRmPwh0dx6S8E+tdHMoryjwopCDUlPpxoB8lw9/aRkFm4tLKzHH53Ypijl
9U+4M28KQHUnSq+rfskNXI7bgN1jIX7CAECqjQLExNsu7iAit5RsUBCiEb+p+HVy
mQ0S30CQJy93NT5AuWTrWKiNv1rUXYZ6YWODWLNCZ+GHJG6U0sV36EooFGmxadpH
UVo4HGMPEHNu07HK0CYlJgRF1h6z3ea6uCHVap4F6Kwa4chdKJm+H6ukCElPGaW1
YwIDAQAB
-----END PUBLIC KEY-----

In essence, for trusted validation to work, the partner must have generated a cryptographic key pair and sent the public key to Coinify. Before the signup, the partner then signs a message containing the same email address as the email parameter in the signup. If the email address of the signed message equals that of the signup request and the signature of the message is valid using the public key, Coinify considers the email address as valid. If the email addresses differ or the signature is invalid, the signup request will fail with a invalid_trusted_email_validation_token error code.

Signed message details

The signed message containing the email address must be a JSON Web Token (JWT) and passed in the signup request as the trustedEmailValidationToken parameter.

The message must be signed using one of the following algorithms:

JWT alg name Algorithm
RS256 RSASSA using SHA-256 hash algorithm
RS384 RSASSA using SHA-384 hash algorithm
RS512 RSASSA using SHA-512 hash algorithm
ES256 ECDSA using P-256 curve and SHA-256 hash algorithm
ES384 ECDSA using P-384 curve and SHA-384 hash algorithm
ES512 ECDSA using P-521 curve and SHA-512 hash algorithm
JWT Header

Example JWT header using RS256 algorithm

{
  "alg": "RS256",
  "typ": "JWT"
}

The header must contain exactly two values (see example to the right):

Key Type Description
typ String JWT identifier. Must contain the string "JWT".
alg String Signature algorithm. Must be one of the allowed signature algorithms listed above.
JWT payload

Example JWT payload for email address johndoe@example.com

{
  "email": "johndoe@example.com",
  "exp": 1467331200  // Expires at 2016-07-01 00:00:00 UTC
}

The payload of the JWT can contain the following values (see example to the right):

Key Type Default value Description
email String Required Email address. The valid email address.
exp Integer Never expire Expiration time. Unix timestamp for when this JWT will no longer be valid.
If given, the message will only be valid for validating the email address up until the given time.
If not given, the message will always be valid.
JWT example

Example JWT token (with added line break)

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
eyJlbWFpbCI6ImpvaG5kb2VAZXhhbXBsZS5jb20iLCJleHAiOjE0NjczMzEyMDB9.
qpn5iey9H86OwxsH8npw_IkmRIE3nxJKgl3FqRP0lSjc5XCA71XcMppwU2WqELgu
Cl7arKSmiHdp9GTu_sfXTk1bSiZMYfpfO810y02l_IrSh4YcZeYko3wW2QpVfgZF
lqwoNQcBM878mveUAmRKfhtQjohHcjLb5YDS2uVf2AFvXFUS443HL25_DC1IuUzr
YCv9pMBI4YHVxWIPU25EERMA03pa0O1XoF9LJR4uTBmKcQTC94IDbbf5GKz29Htk
kEvmx9z5cl0TZGxsRSwzsF0xI6v1taGzKo0NCn8AXpXkjiuffHm_Ml_v5L-bHGhZ
EYs25682iuS6K9Nl1FAggw

The above JWT contains the following header and payload. The token is signed with the private key matching the public key example shown previously.

// Header
{
  "alg": "RS256",
  "typ": "JWT"
}
// Payload
{
  "email": "johndoe@example.com",
  "exp": 1467331200  // Expires at 2016-07-01 00:00:00 UTC
}

Partner

Trader KYC

Example of JWT payload

{
  "traderId": 123,
  "externalId": "id-of-the-partner-kyc-review"
}

Example of a request

{
  "traderId": 123,
  "externalId": "id-of-the-partner-kyc-review",
  "state": "completed",
  "expiryTime": "2018-11-19T05:23:35Z",
  "approveTime": "2018-11-19T01:23:35Z",
  "createTime": "2018-11-19T00:23:35Z",
  "pep": {
    "approved": true,
    "approveTime": "2018-11-19T01:23:35Z"
  },
  "sanction": {
    "approved": true,
    "approveTime": "2018-11-19T01:23:35Z"
  },
  "profile": {
    "birthCountry": "DK",
    "citizenCountry": "DK",
    "phoneNumber": "+22 607 123 4567",
    "name": "John doe",
    "dateOfBirth": "1988-12-14",
    "address": {
      "street": "London Street 123",
      "city": "London",
      "postalCode": "2001",
      "country": "UK"
    }
  },
  "client": {
    "ip": "123.03.0.1",
    "userAgent": "chrome...."
  },  
  "documents": [
    {
      "type": "passport",
      "downloadUrl": "https/partner.info/download-document-in-a-safe-way"
    }
  ]
}

POST https://app-api.coinify.com/partners/:partner-id/kyc

This endpoint will be used by partners to send us KYC review information for traders who are KYC approved. Once documents are download the trader will be KYC approved using eventual consistency.

Authentication

To authenticate request we will use public / private key from trusted email validation.

JWT payload will be different, see example to the right

The JWT token should be sent as a Bearer token in the Authorization header like this Authorization: Bearer <jwt_token>

Request params

Example of JWT payload

{
  "traderId": 123,
  "externalId": "id-of-the-partner-kyc-review"
}
Parameter Type Description
traderId Integer ID of the trader
externalId String Identifier for this KYC review
state String State of the review, only copmpleted so far
expiryTime ISO 8601 time When will this review expire? (ISO 8601)
approveTime ISO 8601 time Timestamp of approval
createTime ISO 8601 time Timestamp of creation
pep Object (optional) Object containing PEP details (politically exposed person)
pep.approved Boolean If profile was pep checked
pep.approveTime ISO 8601 time Timestamp of approval
sanction Object (optional) Object containing sanction check details
sanction.approved Boolean If profile was sanction checked
sanction.approveTime ISO 8601 time Timestamp of approval
profile Object Containing profile information
profile.birthCountry String ISO 3166-1 alpha-2 birth country code
profile.citizenCountry String ISO 3166-1 alpha-2 citizen country code
profile.phoneNumber String E.123 international notation phone number
profile.name String Full name of the trader
profile.dateOfBirth String Date of birth (YYYY-MM-DD)
profile.address Object Object containing address details
profile.address.street String Street with number
profile.address.city String City
profile.address.postalCode String Postal code
profile.address.country String ISO 3166-1 alpha-2 country of residence
client Object Details on client submitting this review
client.ip String IP address
client.userAgent String User agent
documents Array Array of uploaded documents
documents[].type String Type of document, can be passport, bankStatement, driversLicense
documents[].downloadUrl String URL where we (Coinify) can download this document, see downloading documents
Response

If the response is anything else but 200 or 201 the partner should resend request using some exponential backoff strategy.

HTTP Response code JSON data
200 OK Success, review already exists (nothing changed)
201 Created Success, just empty response {}.
400 Bad request Error interpreting the request.
401 Unauthorized Error, authentication failed.

Downloading documents

Partner will provide details on how to do this a secure way

User

A user is the entity used for authentication.

Update user

This endpoint is currenty only used for changing password.

Example request for PATCH /users/me

{
  "oldPassword": "myoldpassword1337",
  "newPassword": "mynewpassword1337"
}

Example response for PATCH /users/me

{
  "id": 1234,
  "email": "user@email.com"
}

PATCH users/me

Update information about a specific user.

Request parameter Type Description
oldPassword String The old password the user wants to change
newPassword String The new password the user wants to use
HTTP Response code JSON data
200 OK Success, user response as shown to the right
400 Bad request Error interpreting the request.
401 Unauthorized Error, access token missing.
Error codes Description
wrong_password The provided oldPassword doesn’t match the existing password.
invalid_request Error in the request body.

Request password reset

Starts the password reset flow for given email

Example request for POST /users/request-password-reset

{
  "email": "user@email.com",
  "partnerId": 11,
}

POST users/request-password-reset

Update information about a specific user.

Request parameter Type Description
email String Email of the user for whom the password should change.
partnerId Integer partnerId for partner associated with the user.
HTTP Response code JSON data
200 OK Success
400 Bad request Error
Error codes Description
invalid_request Error in the request body.

Reset password

Sets new password for the user

Example request for POST /users/reset-password

{
  "id": 1,
  "token": "1234567890asdfghjk",
  "time": 123456789,
  "password": "mynewpassword"
}

POST /users/reset-password

Sets new password for the user

Request parameter Type Description
id Integer ID of the user who will get new password.
token String Token for checking validity of the request.
time Integer Time of the request.
password String New password.
HTTP Response code JSON data
200 OK Success
400 Bad request Error interpreting the request.
Error codes Description
invalid_password_reset_token The provided token is not valid.
user_not_found User with given id does not exist.

Trader

A trader is an entity that can perform trades.

Currently, you can create a trader entity with the trader signup endpoint.

Trader object

Example trader profile object

{
  "id": 754035,
  "defaultCurrency": "EUR",
  "email": "trader@example.com",
  "profile": {
    "name": "John Doe",
    "gender": "male",
    "address": {
      "street": "123 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    },
    "mobile": {
      "countryCode": "1",
      "number": "555-1337"
    }
  },
  "level": {
    "id": 2,
    "name": "2",
    "currency": "EUR",
    "feePercentage": 3.0,
    "limits": {
      "card": {
        "in": {
          "daily": 100.00,
          "yearly": 1000.00
        }
      }
    }
  },
  "tradeSubscriptionsAllowed": true,
  "consentAdditionalMails": true
}

When an endpoint returns information about a trader, the information is exposed in the following object (see example to the right):

Key Type Description
id Integer ID of the trader
defaultCurrency String Primary currency (ISO 4217) of the trader
email String Email address of the trader
canTradeAfter String (Deprecated - use payment methods instead) (Optional) The date (ISO 8601) when the trader will be allowed to make trades again. This property is only present if canTrade is false and cannotTradeReason is after_first_trade.
canTrade Boolean (Deprecated - use payment methods instead) Can this trader create new trades?
tradeSubscriptionsEnabled Boolean Can this trader create new trade subscriptions?
cannotTradeReason String (Optional) The reason (code) why the trader cannot create new trades. See below for possible values. Always present if canTrade is false. (deprecated - use payment methods instead)
profile Object Object with additional information about the trader.
name String Trader’s full name or null if unknown.
gender String Trader’s gender. Either null, "male", or "female"
address Object Object with information about the trader’s physical address.
    →street String Street address or null if unknown.
    →zipcode String Zip/Postal code or null if unknown.
    →city String City or null if unknown.
    →state String ISO 3166-2 state/province or null if unknown.
    →country String ISO 3166-1 alpha-2 country code or null if unknown.
mobile Object Object with information about the trader’s primary mobile phone
    →countryCode Integer Country code of mobile phone number without leading zeroes or plus (+), or null if unknown.
    → number String Mobile phone number or null if unknown.
level Trader level Trader’s current level
nextLevel Trader level Trader’s next possible level
currentLimits Object (Deprecated - use payment methods instead) Information about the trader’s current limits, i.e. how much could the trader trade for, if they did it now?. All amounts are denominated in the trader’s defaultCurrency.
card Object Information about the trader’s current card buying limits.
    →in Float  Trader’s current limit for buying with card payment.
bank Object Information about the trader’s current bank transfer limits.
    →in Float  Trader’s current limit for buying with bank transfer.
    →out Float  Trader’s current limit for selling to bank transfer.
consentAdditionalMails Boolean Determines whether the user consents to receive additional email from Coinify. This is to comply with GDPR

Level object

Key Type Description
id Integer ID of the level - The level number
name String Name of the level - just a string representation of the level number
currency String Currency (ISO 4217) that amounts in this object are denominated in.
feePercentage Decimal Trade fee in percent of total trade amount
limits Object Limit information
card Object Information about card payment limits
    →in Object Information about card payment limits. Contains values daily and yearly, which define the daily and yearly limits, respectively. If e.g. the yearly key is missing, there are no yearly limits.
bank Object Information about bank transfer limits
    →in Object Information about incoming bank transfer limits (i.e. buying with a bank transfer). Contains values daily and yearly, which define the daily and yearly limits, respectively. If e.g. the yearly key is missing, there are no yearly limits.
    →out Object Information about outgoing bank transfer limits (i.e. selling and receiving the result as a bank transfer). Contains values daily and yearly, which define the daily and yearly limits, respectively. If e.g. the yearly key is missing, there are no yearly limits.
requirements List (Deprecated - use payment methods instead) Information about how to reach this level: A list of objectives which all must be fulfilled in order to get to the this level. This list is empty for the initial level. Each element in the list is a Level requirement object.

Level requirement object (deprecated>

Key Type Description
type String Type of objective. See “Level requirement types” below for possible types.
fulfilled Boolean Whether or not this objective has already been fulfilled for the trader.
amount Float (Optional, only if required by type) Amount to fulfill this requirement. Denominated in the currency of the nesting Level object.
fulfilledDelay Integer (Optional, only if required by type) Delay in seconds after this requirement has been fulfilled, until it is actually achieved. (Used to incur a delay of e.g. 7 days after e.g. a volume requirement has been met, until it is possible to reach the next level). If not included, there is no delay.
Level requirement types:
cannotTradeReason types:

Get trader information

Example response for GET /traders/me

{
  "id": 754035,
  "partnerId": 123,
  "email": "trader@example.com",
  "defaultCurrency": "EUR",
  "profile": {
    "name": "John Doe",
    "gender": "male",
    "address": {
      "street": "123 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    },
    "mobile": {
      "countryCode": "1",
      "number": "555-1337"
    }
  },
  "level": {}, // Information about trader's current level
  "nextLevel": {}, // Information about the next level trader can achieve
  "tradeSubscriptionsAllowed": true,
  "consentAdditionalMails":: true
}

GET https://app-api.coinify.com/traders/me

This endpoint returns a trader object for your trader, provided you are authorized as a trader.

Response
HTTP Response code JSON data
200 OK Success, response as shown to the right.
400 Bad request Error, interpreting the request.
404 Not found Error, trader not found.

Update trader information

Example request for PATCH /traders/me

// Change the street address of a trader
{
  "profile": {
    "street": "234 Example Street"
  }
}

Example response for PATCH /traders/me

{
  "id": 754035,
  "email": "trader@example.com",
  "defaultCurrency": "EUR",
  "profile": {
    "name": "John Doe",
    "gender": "male",
    "address": {
      "street": "234 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    },
    "mobile": {
      "countryCode": "1",
      "number": "555-1337"
    }
  },
  "level": {} // Information about trader's current level,
  "consentAdditionalMails": true
}

PATCH https://app-api.coinify.com/traders/me

This endpoint returns a trader object, provided that you are authorized to update and read that information.

Request object
Parameter Type Description
id Integer ID of the trader
defaultCurrency String Primary currency (ISO 4217) of the trader.
email String Email address of the trader
profile Object Object with additional information about the trader.
name String Trader’s full name or null if unknown.
dateOfBirth String Trader’s date of birth (in format YYYY-MM-DD) or null if unknown. NOTE: The updated date of birth is not shown in the trader object for security reason.
gender String Trader’s gender. Either null, "male", or "female"
address Object Object with information about the trader’s physical address.
    →street String Street address
    →zipcode String Zip/Postal code
    →city String City
    →state String ISO 3166-2 state/province
    →country String ISO 3166-1 alpha-2 country code
mobile Object /
String
If object provided, object with information about the trader’s primary mobile phone.
If string provided, a string containing both the country code and the phone number.
    →countryCode Integer Country code of mobile phone number without leading zeroes or plus (+).
    → number String Mobile phone number

Trader KYC

In order to comply with financial regulations, traders must undergo a KYC (Know-Your-Customer) review if they want to do larger trades. A KYC review typically revolves around verifying the identity of the trader.

This section deals with the mechanisms for doing so.

Trader KYC review object

Example of a KYC review object:

{
  "id": 55555,
  "traderId": 12345,
  "state": "completed",
  "returnUrl": "https://mypage.com/kyc_complete",
  "redirectUrl": "https://example.com/url/to/perform/kyc/review",
  "externalId": "1234-abcd-5678-f33d",
  "updateTime": "2016-07-07T12:11:36Z",
  "createTime": "2016-07-07T12:10:19Z"
}

A KYC review is represented as an object as seen to the right. The table below describes each of the properties in the object.

Key Type Description
id Integer Identifier for the KYC review
traderId Integer ID of the trader that this KYC review belongs to
state KYC review state State of the KYC review
returnUrl URL (String) URL to return to when kyc flow is completed (this is only necessary in redirect mode).
redirectUrl URL (String) URL to redirect the user to in order to perform the KYC review
externalId String Reference to the external KYC review, this ID can be used in embedded mode.
updateTime ISO 8601 time The time when the bank account was last updated.
createTime ISO 8601 time Timestamp for when this bank account was first created.

KYC review state

A KYC review can be in a number of well-defined states throughout its lifetime.

State Description
pending (Starting state) KYC review has been initiated, but is waiting for action from the end-user.
rejected (Final state) KYC review was rejected
failed (Final state) KYC review failed due to an error with the provider
expired (Final state) KYC review expired before it was completed
completed (Final state) KYC review completed successfully. (This state is also used if the KYC review was manual and accepted)
reviewing (Intermediate state) KYC is awaiting manual review
documentsRequired (Intermediate state) Trader needs to upload more documents

Prepare KYC review

Example request to POST /traders/me/kyc

{
  "returnUrl": "https://mypage.com/kyc_complete"
}

Example response to POST /traders/me/kyc

{
  "id": 55555,
  "traderId": 12345,
  "state": "pending",
  "returnUrl": "https://mypage.com/kyc_complete",
  "redirectUrl": "https://example.com/url/to/perform/kyc/review",
  "externalId": "1234-abcd-5678-f33d",
  "updateTime": "2016-07-07T12:11:36Z",
  "createTime": "2016-07-07T12:10:19Z"
}

POST https://app-api.coinify.com/traders/me/kyc

Prepare a KYC review. The user must be redirected to the URL specified in the redirectUrl parameter of the response in order to actually undergo the review.

Request object

The parameters in the request object are as follows:

Parameter Type Default Description
returnUrl URL (String) https://www.coinify.com/trade URL to return to after the process is done when using the redirectUrl.
Response
HTTP Response code JSON data
201 Created Success, KYC review object as shown to the right.
400 Bad request Error interpreting the request.
401 Unauthorized Error, access token missing.

Get KYC review

Example request for GET /kyc/55555

{
  "id": 55555,
  "traderId": 12345,
  "state": "completed",
  "returnUrl": "https://mypage.com/kyc_complete",
  "redirectUrl": "https://example.com/url/to/perform/kyc/review",
  "externalId": "1234-abcd-5678-f33d",
  "updateTime": "2016-07-07T12:11:36Z",
  "createTime": "2016-07-07T12:10:19Z"
}

GET https://app-api.coinify.com/kyc/<id>

This endpoint allows you to query a specific KYC review by ID.

Response
HTTP Response code JSON data
200 OK Success, KYC review object as shown to the right.
401 Unauthorized Error, access token missing.
404 Not Found Error retrieving KYC review with the specified ID.

List KYC reviews

Example request for GET /kyc

[
  {
    "id": 55555,
    "traderId": 12345,
    "state": "completed",
    "returnUrl": "https://mypage.com/kyc_complete",
    "redirectUrl": "https://example.com/url/to/perform/kyc/review",
    "externalId": "1234-abcd-5678-f33d",
    "updateTime": "2016-07-07T12:11:36Z",
    "createTime": "2016-07-07T12:10:19Z"
  },
  {
    // next review...
  }
]

GET https://app-api.coinify.com/kyc

This endpoint allows you to get all KYC reviews for the trader.

The reviews are ordered by id (highest first).

Response
HTTP Response code JSON data
200 OK Success, A list of KYC review objects as shown to the right.
401 Unauthorized Error, access token missing.

Trades

This section describes the trade object as well as the endpoints that allow you to create, query and manipulate trades:

The following sections describe the trade object and continue to describe each of the endpoints in greater detail.

Trade object

Example awaiting_transfer_in trade object buying 2.41526674 BTC for 1,000.00 USD

{
  "id": 113475347,
  "traderId": 754035,
  "state": "awaiting_transfer_in",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      // This URL can be used for redirect mode
      "redirectUrl": "https://provider.com/payment/d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      // This ID can be used for embbeded mode
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18"
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "quoteExpireTime": "2016-04-01T12:38:19Z",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

Example completed trade object buying 2.41551728 BTC for 1,000.00 USD

{
  "id": 113475347,
  "traderId": 754035,
  "state": "completed",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmount": 2.41551728,
  "transferIn": {
    "id": 5539662233,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      // This URL can be used for redirect mode
      "redirectUrl": "https://provider.com/payment/d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      // This ID can be used for embbeded mode
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18"
    }
  },
  "transferOut": {
    "id": 5533262233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
       // Trader's bitcoin address that has received the 2.41551728 BTC
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
      // The BTC transaction that sent out the BTC to the above address
      "transaction": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
    }
  },
  "receiptUrl": "https://trade.coinify.com/receipt/f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

Example completed trade object selling 2.41551728 BTC for 1,000.00 USD

{
  "id": 113475348,
  "traderId": 754035,
  "state": "completed",
  "inCurrency": "BTC",
  "outCurrency": "USD",
  "inAmount": 2.41551728,
  "outAmount": 1000.00,
  "transferIn": {
    "id": 5533662233,
    "currency": "BTC",
    "sendAmount": 2.41551728,
    "receiveAmount": 2.41551728,
    "medium": "blockchain",
    "details": {
      // Coinify's bitcoin address to where the trader sent the 2.41551728 BTC
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
      // The BTC transaction that sent out the BTC to the above address
      "transaction": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
    }
  },
  "transferOut": {
    "id": 5533662244,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "bank",
    "mediumReceiveAccountId": 12345 // Reference to the traders bank account
  },
  "receiptUrl": "https://trade.coinify.com/receipt/f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

The following table defines the fields of a trade object:

Key Type Description
id Integer Unique ID for this trade
traderId Integer Reference to the trader that created the trade
subscription Trade subscription object (Optional) Object only exists if this trade was made as a subscription.
state Trade state The current state of the trade
inCurrency String Currency (ISO 4217) denominating inAmount.
outCurrency String Currency (ISO 4217) denominating outAmount or outAmountExpected.
inAmount Float The amount of inAmount that this trade covers. Is always positive.
outAmount Float (Optional) The amount of outCurrency that this trade resulted in. Is always positive. NOTE: This field is only defined if the state of the trade is completed. For all other states, see the outAmountExpected field.
outAmountExpected Float The amount of outCurrency that this trade is expected to result in. Is always positive.
transferIn Transfer object Object describing how we (Coinify) will receive/have received the money to fund the trade.
transferOut Transfer object Object describing how we (Coinify) will send/have sent the result of the trade back to the trader.
receiptUrl String (URL) (Optional). URL to a printable receipt for this trade. This field is present if state is complete.
quoteExpireTime ISO 8601 time (Optional) The time when the price quote underlying this trade expires. NOTE: This field is only defined in the following states: awaiting_transfer_in, processing, reviewing.
updateTime ISO 8601 time The time when the trade was last updated.
createTime ISO 8601 time Timestamp for when this trade was first created

Trade states

The following table lists all possible states of a trade (the state property):

State Description
awaiting_transfer_in (Starting state) Trade was successfully created, and is waiting for trader’s payment
processing Trade has received the trader’s payment, and we are processing the trade.
reviewing Trade is undergoing manual review
completed (Ending state) Trade completed successfully.
cancelled (Ending state) Trade cancelled.
rejected (Ending state) Trade was rejected.
expired (Ending state) Trade expired before it completed.

The states, as well as the possible transitions between them, are visualized in this diagram:

Trade state diagram

Transfer object

Each trade has two transfer objects - transferIn and transferOut - which contain details about how Coinify will receive money from the trader, and how Coinify will send money back to the trader, respectively.

Each transfer object contains the following keys:

Key Type Description
id Integer Unique identifier for this transfer.
state String State of this transfer. One of the following:
  • waiting: Waiting to receive money, or waiting for signal to send money
  • completed: Transfer completed
  • completed_test: Test transfer completed
  • cancelled: Transfer cancelled
  • expired: Transfer expired
  • rejected: Transfer rejected
  • reviewing: Transfer is in review
currency String Currency (ISO 4217) that this transfer is/will be denominated in.
sendAmount Float Amount that is/will be sent to this transfer. Denominated in currency. Is always positive.
receiveAmount Float Amount that this transfer will result in. Denominated in currency. Is always positive and equal to or smaller then sendAmount. The difference between the sendAmount and the receiveAmount will be the fee of the transfer.
medium String Transfer medium. The medium transferring the currency.
mediumReceiveAccountId Integer Reference to our internal accounts. Note at the moment we only have internal bank accounts.
details Medium details Information relevant for this medium

Transfer media

Medium Description
blockchain Blockchain - Transfer on a public blockchain, such as Bitcoin. NOTE: The currency field of the transfer object will determine which blockchain currency.
card Card - Card payment.
bank Bank - Bank account payment. If transfer is incoming we sent our own bank details as the details object. And if transfer is outgoing its the details of the traders bank account.

Blockchain

Details object
Key Type Description
account String Account receiving the money in this transfer (blockchain address).
tx String  Transaction sending the money in this transfer. Only defined if money has been sent.

Card

Details object

Below, a description of the request/response objects for creating a trade.

Request object
Key Type Description
preferredIntegrationMethod String Current possible value is payment-page. Please see preferred integration method. Note: If this is ommited or its value is not valid, then the Coinify Payment Page method will not be used. Default flow will be used instead
returnUrl String The return URL to which the user to be sent back after the payment has been created. Can be provided when creating a trade. Only relevant when provider = ‘isignthis’ or provider = 'isignthis-staging’
Reponse object
Key Type Description
provider String String identifying the PSP. Current possible values are ('isignthis’,'isignthis-staging’, 'safecharge’)
paymentId String Id of the external payment. The paymentId is used for the integration mode: embedded mode.
cardPaymentId Integer Reference to the card payment.
redirectUrl String Source URL to process the payment.
returnUrl String The return URL to which the user to be sent back after the payment has been created. Can be provided when creating a trade. Only relevant when provider = 'isignthis’ or provider = 'isignthis-staging’

Preferred Integration Method

Please note that the preferred method indicates a method that will be attempted to be used, but it is not necessarily the method that will be ultimately used for paying for the trade.

Below there are the possible values and description of workflow for each possible value of preferred card payment method.

Key Description
payment-page Coinify Payment Page flow, ready to embbed into an iFrame
Embedded payment page

The following chapter describes how to embed a payment page into the front-end application. In a nutshell the trade endpoint returns a redirect URL. This redirect URL is used as the source URL for an iframe.

Example pseudo code to show a payment page to the end user.

<iframe id="wallet-payment-frame"></iframe>
<script>
  const pay = document.querySelector("#wallet-payment-frame");
  pay.srcUrl = trade_returned_by_trades_end_point.transferIn.details.redirectUrl;
  pay.addEventListener("message",(e) => {
    e.data.indexOf("complete")>=0 && alert("trade completed");
  });
</script>

(Please note: there will be an opensource fully fledged working sample avaiable soon)

Coinify Payment Page

The Coinify Payment Page is an easy way to show a payment page to the end user. The Coinify Payment Page also enables you to customize the UI so that the payment blends in seamless with the look and feel of your app.

The principle for embedding the Coinify Payment Page follows the same principle described in embedded payment page.

Redirect mode

For card payment we also support redirect mode. For using this integration mode you just have to redirect the trader to the transferIn.details.redirectUrl.

Bank

Details object
Key Type Description
referenceText String Text that the bank transfer must contain in order for Coinify to correctly register what trade it concerns.
account Object Object with additional information about the bank account.
currency String Currency of the bank account
type Bank account type Type of the bank account
bic String For sepa and international its the SWIFT / BIC number and for danish accounts its the REG number.
number String For sepa and international it’s the IBAN (International Bank Account Number). For danish accounts, it’s the BBAN (Basic Bank Account Number).
bank Object Object with additional information about the bank.
name String Name of the bank.
address Object Object with information about the address of the bank.
    →street String Street address.
    →zipcode String Zip/Postal code.
    →city String City.
    →state String State.
    →country String ISO 3166-1 alpha-2 country code
holder Object Object with additional information about the bank account holder.
name String Name of the bank account holder.
address Object Object with information about the address of the account holder.
    →street String Street address.
    →zipcode String Zip/Postal code.
    →city String City.
    →state String State.
    →country String ISO 3166-1 alpha-2 country code

Payment methods

This section contains information about different methods to buy/sell blockchain currencies.

The currently available payment methods are:

Payment method object

The object represents a single payment method, containing the information about how and with what currencies the money transfer can and should be performed, and optionally the fees that are going to be applied to the amounts.

Key Type Description
inMedium String The medium for the in transfer of the trade - by what way the customer pays
outMedium String The medium for the out transfer of the trade - what way the customer receives funds
name String A human-readable name/description of the payment method
inCurrencies List The possible currencies in which the incoming amount can be made, optionally filtered by request arguments
outCurrencies List The possible currencies in which the outgoing amount can be made, optionally filtered by request arguments
inFixedFees Object Object of inCurrencies and fixed fees for each currency for the in transfer.
inPercentageFee Float Percentage fee for the in transfer.
outFixedFees Object Object of outCurrencies and fixed fees for each currency for the out transfer.
outPercentageFee Float Percentage fee for the out transfer.
minimumInAmounts Object Object of inCurrencies and the minimum limit for each.
limitInAmounts Object Object of inCurrencies and the trader’s current limit for each currency, based on the current limits of the trader. Note: Only included for authenticated requests.
canTrade Boolean Can this trader create new trades for this payment method? Note: Only included for authenticated requests. If inCurrency, inAmount, outCurrency and outAmount are all provided in request, this value determines if a trade with the specific amounts/currencies can be made. Otherwise, this value determines if any trade can be made with this payment method.
cannotTradeReasons List (Optional) List of reason objects why the trader cannot create new trades (why canTrade is false). Note: Only included for authenticated requests if canTrade is false.
inCurrency String (Optional, if inCurrency parameter provided) Echo of inCurrency parameter.
inAmount Float (Optional, if inAmount parameter provided) Echo of inAmount parameter.
outCurrency String (Optional, if outCurrency parameter provided) Echo of outCurrency parameter.
outAmount Float (Optional, if outAmount parameter provided) Echo of outAmount parameter.
inFixedFee Float (Deprecated, see inFixedFees object instead) (Optional, if inCurrency parameter provided) Fixed fee for the in transfer. Denominated in inCurrency.
outFixedFee Float (Deprecated, see outFixedFees object instead) (Optional, if outCurrency parameter provided) Fixed fee for the out transfer. Denominated in outCurrency.

cannotTradeReason object

This object represents a reason for why a trader cannot create a trade with a given payment method. The only field that is always present in the object is the reasonCode. Depending on the value of the reasonCode, other reason-specific fields may be present in the object.

Key Type Description
reasonCode String Machine-readable code for the reason why the trade cannot create a trade. See Possible reasonCodes for a list of possible values
Possible reasonCodes

reasonCode value Description Extra fields
forced_delay Trader must wait until a specific time before creating trade delayEnd (string): ISO-8601 timestamp for when the delay is over.
trade_in_progress Trader must wait until a specific trade has completed tradeId (integer): ID of trade that must be completed
limits_exceeded Creating trade would exceed the trader’s limits None

List payment methods

Example response for GET /trades/payment-methods (authenticated)

[
    {
      "inMedium": "bank",
      "outMedium": "blockchain",
      "name": "Buy bitcoins with bank transfer",
      "inCurrencies": ["DKK", "EUR", "GBP", "USD"],
      "outCurrencies": ["BTC"],
      "inFixedFees": {
        "DKK": 0,
        "EUR": 0,
        "GBP": 0,
        "USD": 0
      },
      "inPercentageFee": 0,
      "outFixedFees": {
        "BTC": 0.001
      },
      "outPercentageFee": 0,
      "minimumInAmounts": {
        "DKK": 75.86,
        "EUR": 10.00,
        "GBP": 8.00,
        "USD": 12.50
      },
      "limitInAmounts": {
        "DKK": 7500.86,
        "EUR": 1000.00,
        "GBP": 8000.00,
        "USD": 1200.50
      },
      "canTrade": true
    },
    {
      "inMedium": "blockchain",
      "outMedium": "bank",
      "name": "Sell bitcoints to bank transfer",
      "inCurrencies": ["BTC"],
      "outCurrencies": ["DKK", "EUR", "GBP", "USD"],
      "inFixedFees": {
        "BTC": 0
      },
      "inPercentageFee": 0,
      "outFixedFees": {
        "DKK": 40.00,
        "EUR": 5.40,
        "GBP": 3.70,
        "USD": 6.10
      },
      "outPercentageFee": 0,
      "minimumInAmounts": {
        "BTC": 0.0102
      },
      "limitInAmounts": {
        "BTC": 1.86
      },
      "canTrade": true
    },
    {
      "inMedium": "card",
      "outMedium": "blockchain",
      "name": "Buy bitcoins with card transfer",
      "inCurrencies": ["DKK", "EUR", "GBP", "USD"],
      "outCurrencies": ["BTC"],
      "inFixedFees": {
        "DKK": 0,
        "EUR": 0,
        "GBP": 0,
        "USD": 0
      },
      "inPercentageFee": 3,
      "outFixedFees": {
        "BTC": 0.001
      },
      "outPercentageFee": 0,
      "minimumInAmounts": {
        "DKK": 75.86,
        "EUR": 10.00,
        "GBP": 8.00,
        "USD": 12.50
      },
      "limitInAmounts": {
        "DKK": 75.86,
        "EUR": 10.00,
        "GBP": 8.00,
        "USD": 12.50
      },
      "canTrade": false,
      "cannotTradeReasons": [
        {
          "reasonCode": "forced_delay",
          "delayEnd": "2016-04-01T12:27:36Z"
        }
      ]
    }
]

GET https://app-api.coinify.com/trades/payment-methods

This endpoint returns a list of payment methods objects, available for creating and paying for trades, optionally filtered by specific in- and out-currencies.

Query parameters
Parameter Type Description
inCurrency String (Optional) Filter payment methods to those who have this as one of the inCurrencies. Includes inFixedFee for the returned payment methods.
inAmount Float (Optional) If this is provided in an authenticated request along with inCurrency, outCurrency, and outAmount, the canTrade field in the response will reflect whether the trader can make a trade with the specified currencies and amounts.
outCurrency String (Optional) Filter payment methods to those who have this as one of the outCurrencies. Includes outFixedFee for the returned payment methods.
outAmount Float (Optional) If this is provided in an authenticated request along with inCurrency, inAmount, and outCurrency, the canTrade field in the response will reflect whether the trader can make a trade with the specified currencies and amounts.
priceQuoteId String (Optional) Id of price quote to which the payment methods will be applied. If this is provided in an authenticated request the response will show fees and exchange rates from when the supplied price quote was created (I.e. the same values that will be used in an eventual trade), otherwise fees and rates will be provisioned at the time of request and may be different from what is used in a subsequent trade.
Response
HTTP Response code Error code JSON data
200 OK Success, response as shown to the right.
400 Bad request invalid_argument Error, interpreting the request (wrong input values for query parameters).
500 Internal error internal_error Error, an internal error happened.

Request trade price quote

Example request for POST /trades/quote

// This request is saying: "I want to buy BTC for 1,000.00 USD. How much BTC will I get?"
{
  "baseCurrency": "USD",
  "quoteCurrency": "BTC",
  "baseAmount": -1000.00
}

Example response for POST /trades/quote

// This response is saying "We'll give you 2.41551728 BTC for 1,000.00 USD"
{
  "id": 123456,
  "baseCurrency": "USD",
  "quoteCurrency": "BTC",
  "baseAmount": -1000.00,
  "quoteAmount": 2.41551728,
  "issueTime": "2016-04-01T11:47:24Z",
  "expiryTime": "2016-04-01T12:02:24Z"
}

POST https://app-api.coinify.com/trades/quote

Before actually creating a trade, you (as a trader) have the option of getting a price quote (i.e. an offer for a specific exchange rate) that is valid for a short period of time. When creating a trade you can reference a price quote and trade using the rate given in the quote.

Request object

The parameters in the request object are as follows:

Parameter Type Default Description
baseCurrency String Required Relative to what currency (ISO 4217) do you want a price quote? Denominates baseAmount.
quoteCurrency String Required What currency (ISO 4217) do you want the price quote in?
baseAmount Float Required Amount to get a price quote for. Denominated in baseCurrency.
transferIn Object Empty object An object describing how Coinify will receive the money for this transfer.
medium String null Transfer medium
transferOut Object Empty object An object describing how Coinify will send the result of the trade to the trader.
medium String null Transfer medium
Response object

The success response object contains the following fields:

Key Type Description
id Integer Price quote identifier. Pass this identifier to the create trade endpoint to claim the offer. Note: Not included if anonymous (un-authenticated) request.
baseCurrency String Currency (ISO 4217) denominating baseAmount, the known amount.
quoteCurrency String Currency (ISO 4217) denominating quoteAmount, the unknown amount.
baseAmount Float How much of baseCurrency does this quote apply for?
quoteAmount Float How much of quoteCurrency is this quote? This is the “result”, the price quote.
transferIn Object transferIn object from request, if given.
medium String null
transferOut Object transferOut object from request, if given.
medium String null
issueTime ISO 8601 time Timestamp for when this price quote was issued.
expiryTime ISO 8601 time Timestamp for when this price quote expires.
Response
HTTP Response code JSON data
201 Created Success, A Price quote created and returned object as shown to the right
401 Unauthorized Error, access token missing.

Create trade

Example request for POST /trades, using a valid price quote

{
  "priceQuoteId": 123456,
  "transferIn": {
    "medium": "card"
  },
  "transferOut": {
    "medium": "blockchain",
    "details": {
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  }
}

Example response for the above request

{
  "id": 113475347,
  "traderId": 754035,
  "state": "awaiting_transfer_in",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      // This URL can be used for redirect mode
      "redirectUrl": "https://provider.com/payment/d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      // This ID can be used for embbeded mode
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18"
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      // Trader's bitcoin address that will receive approx. 2.41526674 BTC if trade completes
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "quoteExpireTime": "2016-04-01T12:38:19Z",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

Example request for POST /trades, using a valid price quote and as a subscription

{
  "priceQuoteId": 123456,
  "subscription": {
    "frequency": "weekly"
  },
  "transferIn": {
    "medium": "card"
  },
  "transferOut": {
    "medium": "blockchain",
    "details": {
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  }
}

Example response for the above request

{
  "id": 113475347,
  "traderId": 754035,
  "state": "awaiting_transfer_in",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "subscription": {
    "id": 123,
    "isActive": true,
    "frequency": "weekly"
  },
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      // This URL can be used for redirect mode
      "redirectUrl": "https://provider.com/payment/d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      // This ID can be used for embbeded mode
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18"
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      // Trader's bitcoin address that will receive approx. 2.41526674 BTC if trade completes
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "quoteExpireTime": "2016-04-01T12:38:19Z",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

Example request for POST /trades, paying used saved card

{
  "priceQuoteId": 123456,
  "transferIn": {
    "medium": "card",
    "details": {
      "card": {
        "CCV": "123",
        "externalTokenId": "34325434"
      }
    }
  },
  "transferOut": {
    "medium": "blockchain",
    "details": {
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  }
}

Example response for the above request

{
  "id": 113475347,
  "traderId": 754035,
  "state": "awaiting_transfer_in",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "subscription": {
    "id": 123,
    "isActive": true,
    "frequency": "weekly"
  },
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      "redirectUrl": "https://3dsecure.net/Barclays/3dauthentication",
      "redirectUrlType": "3DSecure"
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      // Trader's bitcoin address that will receive approx. 2.41526674 BTC if trade completes
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "quoteExpireTime": "2016-04-01T12:38:19Z",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

Example request for POST /trades, paying used card registered in custom form without saving card.

{
  "priceQuoteId": 123456,
  "subscription": {
    "frequency": "weekly"
  },
  "transferIn": {
    "medium": "card",
    "details": {
      card: {
        "provider": "safecharge",
        "ccTempToken": "343254-x231ds-xasdas2-xasdasd",
      }
    }
  },
  "transferOut": {
    "medium": "blockchain",
    "details": {
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  }
}

Example response for the above request

{
  "id": 113475347,
  "traderId": 754035,
  "state": "awaiting_transfer_in",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "subscription": {
    "id": 123,
    "isActive": true,
    "frequency": "weekly"
  },
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      "redirectUrl": "https://3dsecure.net/Barclays/3dauthentication",
      "redirectUrlType": "3DSecure"
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      // Trader's bitcoin address that will receive approx. 2.41526674 BTC if trade completes
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "quoteExpireTime": "2016-04-01T12:38:19Z",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

Example request for POST /trades (buy bitcoins for bank transfer)

{
  "baseCurrency": "USD",
  "quoteCurrency": "BTC",
  "baseAmount": -1000.00,
  "transferIn": {
    "medium": "bank"
  },
  "transferOut": {
    "medium": "blockchain",
    "details": {
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  }
}

Example response for the above request

{
  "id": 113475347,
  "traderId": 754035,
  "state": "awaiting_transfer_in",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "bank",
    "details": { // Information about where the user should sent the money
       "account": {
         "currency": "DKK", // Currency of the bank account
         "bic": "HIASDMIASD", // Account bic/swift/reg number depending on the type
         "number": "1234-34235-3324-2342" // Account number
       },
       "bank": {
         "name": "Bank name", // Name of the bank
         "address": { // Address of the bank
           "street": "123 Example Street",
           "zipcode": "12345",
           "city": "Exampleville",
           "state": "CA",
           "country": "US"
         }
       },
       "holder": {
         "name": "John Doe", // Name of the account holder
         "address": { // Address of the account holder
           "street": "123 Example Street",
           "zipcode": "12345",
           "city": "Exampleville",
           "state": "CA",
           "country": "US"
         }
       }
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      // Trader's bitcoin address that will receive approx. 2.41526674 BTC if trade completes
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "quoteExpireTime": "2016-04-01T12:38:19Z",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

POST https://app-api.coinify.com/trades

The Create trade endpoint allows a trader to trade crypto for fiat, or vice-versa.

On success, the endpoint returns the newly created trade object.

The endpoint supports the following directions:

Request object

The parameters in the request object are as follows:

Parameter Type Default Description
priceQuoteId Integer Required to use existing price quote Identifier of valid price quote to base the trade on. Passing an invalid price quote will result in an error.
baseCurrency String Required to create new price quote What currency (ISO 4217) is the amount known for? Denominates baseAmount.
quoteCurrency String Required to create new price quote What currency (ISO 4217) is the unknown amount for?
baseAmount String Required to create new price quote Amount to trade. Denominated in baseCurrency.
subscription Object Optional If trade should be created as a subscription. NOTE only if transferIn.medium='card'.
frequency String Required if subscription object is present Frequency for the trade subscription. See Trade subscription object.
endTime String Optional Determines when the subscription ends (if it ends). See Trade subscription object.
transferIn Object Required An object describing how Coinify will receive the money for this transfer.
medium String Required Transfer medium.
details Object Optional Can be used to supply returnUrl for medium=card. Transfer details.
transferOut Object Required An object describing how Coinify will send the result of the trade to the trader.
medium String Required Transfer medium.
mediumReceiveAccountId Integer Required if medium is bank Bank account of the trader.
details Object Required if medium is blockchain Transfer details
Request object examples

The following table exemplifies how baseCurrency and quoteCurrency should be interpreted.

baseCurrency quoteCurrency baseAmount Interpretation
"USD" "BTC" 123.45 I want to buy 123.45 USD for BTC.
"USD" "BTC" -123.45 I want to sell 123.45 USD for BTC.
"BTC" "USD" 1.5 I want to buy 1.5 BTC for USD.
"BTC" "USD" -1.5 I want to sell 1.5 BTC for USD.
HTTP Response code JSON data
201 Created Success, object returned, as shown to the right
401 Unauthorized Error, access token missing.

List trades

Example response for GET /trades

[
  {
    "id": 113475347,
    "traderId": 754035,
    "state": "awaiting_transfer_in",
    "inCurrency": "USD",
    "outCurrency": "BTC",
    "inAmount": 1000.00,
    "outAmountExpected": 2.41526674,
    "transferIn": {
      "id": 4433662222,
      "currency": "USD",
      "sendAmount": 1000.00,
      "receiveAmount": 1000.00,
      "medium": "card",
      "details": {
        // This URL can be used for redirect mode
        "redirectUrl": "https://provider.com/payment/d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
        // This ID can be used for embbeded mode
        "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18"
      }
    },
    "transferOut": {
      "id": 4433662233,
      "currency": "BTC",
      "medium": "blockchain",
      "sendAmount": 2.41526674,
      "receiveAmount": 2.41526674,
      "details": {
        // Trader's bitcoin address that will receive approx. 2.41526674 BTC if trade completes
        "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
      }
    },
    "quoteExpireTime": "2016-04-01T12:38:19Z",
    "updateTime": "2016-04-01T12:27:36Z",
    "createTime": "2016-04-01T12:23:19Z"
  },
  {
    // Next trade...
  }
]

GET https://app-api.coinify.com/trades

Response

This endpoint lists all trade objects belonging to the authorized trader.

The trades are ordered by id (highest first).

HTTP Response code JSON data
200 OK Success, response as shown to the right.
400 Bad request Error interpreting the request.
404 Not found Error, trades that belong to the provided trader were not found.

Get trade information

Example response for GET /trades/113475347

{
  "id": 113475347,
  "traderId": 754035,
  "state": "awaiting_transfer_in",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      // This URL can be used for redirect mode
      "redirectUrl": "https://provider.com/payment/d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      // This ID can be used for embbeded mode
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18"
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      // Trader's bitcoin address that will receive approx. 2.41526674 BTC if trade completes
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "quoteExpireTime": "2016-04-01T12:38:19Z",
  "updateTime": "2016-04-01T12:27:36Z",
  "createTime": "2016-04-01T12:23:19Z"
}

GET https://app-api.coinify.com/trades/<id>

This endpoint returns a trade object for the trade with ID <id>.

Response

See trade object.

HTTP Response code JSON data
200 OK Success, response as shown to the right.
400 Bad request Error interpreting the request.
404 Not found Error, trade is not found (no trade with such ID exists or no trade with such ID that belongs to the provided trader).

Cancel trade

Example response for PATCH /trades/113475347/cancel

{
  "id": 113475347,
  "traderId": 754035,
  // State is now "cancelled"
  "state": "cancelled",
  "inCurrency": "USD",
  "outCurrency": "BTC",
  "inAmount": 1000.00,
  "outAmountExpected": 2.41526674,
  "transferIn": {
    "id": 4433662222,
    "currency": "USD",
    "sendAmount": 1000.00,
    "receiveAmount": 1000.00,
    "medium": "card",
    "details": {
      "redirectUrl": "https://provider.com/payment/d3aab081-7c5b-4ddb-b28b-c82cc8642a18",
      "paymentId": "d3aab081-7c5b-4ddb-b28b-c82cc8642a18"
    }
  },
  "transferOut": {
    "id": 4433662233,
    "currency": "BTC",
    "medium": "blockchain",
    "sendAmount": 2.41526674,
    "receiveAmount": 2.41526674,
    "details": {
      "account": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    }
  },
  "updateTime": "2016-04-01T12:34:37Z",
  "createTime": "2016-04-01T12:23:19Z"
}

PATCH https://app-api.coinify.com/trades/<id>/cancel

This endpoint cancels a trade in the awaiting_transfer_in state and returns a trade object for the cancelled trade.

Request object

This endpoint requires no request body

Response

See trade object.

HTTP Response code JSON data
200 OK Success, response as shown to the right.
400 Bad request Error trade not cancellable.
404 Not found Error, trade is not found (no trade with such ID exists or no trade with such ID that belongs to the provided trader).

Trade subscriptions

You can create a trade subscription by calling the create trade and pass the subscription object.

A subscription will automatically create new trades using the provided frequency. If the trade or card payment gets rejected, we will cancel the subscription.

To list trades that were created as part of a subscription, just call the list trades endpoint and check which ones have the subscription object.

To cancel a trade subscription call the update subscription endpoint and set isActive to false.

Trade subscription object

If the trade was made as part of a trade subscription this object will be included in the trade object response.

Key Type Description
id Integer Reference to the subscription.
amount Float Amount of the subscription.
currency String Currency of the amount.
isActive Boolean If the subscription is active or has been cancelled.
frequency String How often will new trades be created from this subscription. Can have the following values
  • weekly
  • monthly
endTime ISO 8601 time (Optional) Determines when the subscription ends. If the value is not set, it means that the subscription never expires.

Update subscription

Example request for PATCH /trades/subscriptions/123

{
  "isActive": false
}

Example response for the above request

{
  "id": 123,
  "amount": 12.50,
  "currency": "EUR",
  "isActive": false,
  "frequency": "monthly",
  "endTime": "2017-10-09T13:36:48.000Z"
}

PATCH https://app-api.coinify.com/trades/subscriptions/<id>

Endpoint to update a trade subscription.

Request object

The parameters in the request object are as follows:

Parameter Type Description
isActive Boolean  Should the subscription be active or cancelled?

Response

HTTP Response code JSON data
200 OK Success, Trade subscription object.
400 Bad request Error interpreting the request.
403 Forbidden Error the subscription does not belong to this trader.
404 Not found Error the subscription could not be found.
500 Server error Error error has occurred parsing the data.

List subscriptions

Example response for GET /trades/subscriptions

[
  {
    "id": 123,
    "amount": 12.50,
    "currency": "EUR",
    "isActive": true,
    "frequency": "monthly"
  },
  {
    "id": 124,
    "amount": 150.00,
    "currency": "DKK",
    "isActive": false,
    "frequency": "weekly",
    "endTime": "2017-10-09T13:36:48.000Z"
  }
]

GET https://app-api.coinify.com/trades/subscriptions

Endpoint to list all trade subscriptions.

Response

HTTP Response code JSON data
200 OK Success, Array of Trade subscription object.
500 Server error Error error has occurred parsing the data.

Testing

This section contains information about endpoints related to testing trades:

Create fake bank transaction

Example request for POST /trades/113475347/test/bank-transfer

{
  "sendAmount": 200.00, // Amount of the fake transaction
  "currency": "EUR" // Currency of the amount
}

POST https://app-api.coinify.com/trades/<id>/test/bank-transfer

This endpoint creates a fake bank transfer for the trade with ID <id> and processes the trade as if a real bank transfer had occurred.

Request object

The parameters in the request object are as follows:

Parameter Type Default Description
sendAmount Integer Required  Amount sent from the trader’s bank account. This corresponds to the transferIn.sendAmount of the trade.
currency String Required Currency of the amount.

Response

This endpoint returns 204 No Content if the fake bank transfer creation succeeded.

HTTP Response code JSON data
204 No Content Success, empty response.
400 Bad request Error interpreting the request.
500 Server error Error error has occurred parsing the data.

Rates

Approximate rate (Deprecated)

This end-point is deprecated, please see the following:

Original (deprecated) documentation follows:

Example response for GET /rates/approximate?baseCurrency=BTC&quoteCurrency=EUR

{
  "baseCurrency": "BTC", // Echo of baseCurrency query parameter
  "quoteCurrency": "EUR", // Echo of quoteCurrency query parameter
  "rate": 576.77 // 1 BTC ≈ 576.77 EUR
}

GET https://app-api.coinify.com/rates/approximate

In some cases, it can be convenient to know whether creating a new trade would exceed the trader’s limits or not without actually creating a trade.

This endpoint gives you an approximate rate for converting an amount in one currency to another. By specifying a trader’s default currency as the quoteCurrency, you can use this rate to approximate how much a trade in a specific currency would decrease the trader’s current limits, and, by comparing this value to those in the limitInAmounts objects of the payment methods to decide whether or not the trade would be allowed or rejected due to exceeding the trader’s limits.

Query parameters
Parameter Type Description
baseCurrency String (Required) Currency (ISO 4217) that you wish to get a rate from.
quoteCurrency String (Required) Currency (ISO 4217) that you wish to get a rate to.
Response

The success response object contains the following fields:

Key Type Description
baseCurrency String Echo of baseCurrency input parameter.
quoteCurrency String Echo of quoteCurrency input parameter
rate Float Approximate rate for converting one unit of baseCurrency to quoteCurrency.
HTTP Response code JSON data
200 OK Success, response as shown to the right.
400 Bad request Error, interpreting the request (wrong input value for baseCurrency or quoteCurrency).

Bank accounts

This section contains the create, list, get and delete end-points of the bank accounts used when creating a trade and to make payouts:

Bank account object

Example of a bank account object:

{
  "id": 1234,
  "account": {
    "type": "danish", // Type of bank account
    "currency": "DKK", // Currency of the bank account
    "bic": "HIASDMIASD", // Account bic/swift/reg number depending on the type
    "number": "1234-34235-3324-2342" // Account number
  },
  "bank": {
    "address": {
      "country": "US"
    }
  },
  "holder": {
    "name": "John Doe", // Name of the account holder
    "address": { // Address of the account holder
      "street": "123 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    }
  },
  "update_time": "2016-04-01T12:27:36Z",
  "create_time": "2016-04-01T12:23:19Z"
}
Key Type Description
id Integer Identifier for the bank account
account Object Object with additional information about the bank account.
type bank account type Type of the bank account.
currency String Currency of the bank account
bic String For sepa and international its the SWIFT / BIC number and for danish accounts its the REG number.
number String For sepa and international it’s the IBAN (International Bank Account Number). For danish accounts, it’s the BBAN (Basic Bank Account Number).
bank Object Object with additional information about the bank.
address Object Object with information about the address of the bank.
    →country String ISO 3166-1 alpha-2 country code
    →state String State (Required for country US).
holder Object Object with additional information about the bank account holder.
name String Name of the bank account holder.
address Object Object with information about the address of the account holder.
    →street String Street address.
    →zipcode String Zip/Postal code.
    →city String City.
    →state String State. (Required for country US)
    →country String ISO 3166-1 alpha-2 country code
updateTime ISO 8601 time The time when the bank account was last updated.
createTime ISO 8601 time Timestamp for when this bank account was first created.

Bank account types

The bank accounts have 3 different types depending on the account currency (account.currency) and the bank country (bank.address.country).

When creating a new bank account, you don’t explicitly specify the type; instead Coinify decides the type for you, based on the requirements in the following table:

Type Description Requirements
danish Danish national bank account  Country must be DK and currency DKK.
sepa SEPA bank account Country must be in our list of SEPA countries, and currency must be EUR.
international International bank account Everything else.

Create bank account

Example request to POST /bank-accounts

{
  "account": {
    "currency": "DKK", // Currency of the bank account
    "bic": "6456", // Account REG number
    "number": "12345435345345" // Account number
  },
  "bank": {
    "address": { // Address of the bank
      "country": "DK"
    }
  },
  "holder": {
    "name": "John Doe", // Name of the account holder
    "address": { // Address of the account holder
      "street": "123 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    }
  }
}

Example response for the above request

{
  "id": 12345, // Identifier of the bank account
  "account": {
    "type": "danish", // Type of bank account
    "currency": "DKK", // Currency of the bank account
    "bic": "6456", // Account bic/swift/reg number depending on the type
    "number": "12345435345345" // Account number
  },
  "bank": {
    "address": { // Address of the bank
      "country": "DK"
    }
  },
  "holder": {
    "name": "John Doe", // Name of the account holder
    "address": { // Address of the account holder
      "street": "123 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    }
  },
  "update_time": "2016-04-01T12:27:36Z",
  "create_time": "2016-04-01T12:23:19Z"
}

POST https://app-api.coinify.com/bank-accounts

On success, the endpoint returns the newly created bank-account object.

Some of the fields are only required if the bank account is of type international see account-types.

Request object

The parameters in the request object are as follows:

Parameter Type Default Description
account Object Required  Object with additional information about the bank account.
currency String Required Currency of the bank account
bic String Required For sepa and international its the SWIFT / BIC number and for danish accounts its the REG number.
number String Required For sepa and international it’s the IBAN (International Bank Account Number). For danish accounts, it’s the BBAN (Basic Bank Account Number).
bank Object Required for non SEPA payments Object with additional information about the bank.
address Object Required Object with information about the address of bank.
    →country String Required ISO 3166-1 alpha-2 country code
    →state String State (Required for country US).
holder Object Required Object with additional information about the bank account holder.
name String Required Name of the bank account holder.
address Object Required Object with information about the address of the account holder.
    →street String Required Street address.
    →zipcode String Required Zip/Postal code.
    →city String Required City.
    →state String Required State. Required for country US
    →country String Required ISO 3166-1 alpha-2 country code
HTTP Response code JSON data
201 Created Success, response as shown to the right.
400 Bad request Error, interpreting the request (missing parameters).
401 Unauthorized Error, access token missing.
HTTP status code Error code  Description
400 missing_argument There was something wrong with the signup request. See the error_description argument for a specific, human-readable error message.
400 invalid_argument There was something wrong with the signup request. See the error_description argument for a specific, human-readable error message.
400 invalid_iban Provided account.number is an invalid IBAN. This is only for SEPA countries.

List bank accounts

Example request for GET /bank-accounts

[
    {
      "id": 12345, // Identifier of the bank account
      "account": {
        "type": "danish", // Type of bank account
        "currency": "DKK", // Currency of the bank account
        "bic": "6456", // Account bic/swift/reg number depending on the type
        "number": "12345435345345" // Account number
      },
      "bank": {
        "address": { // Address of the bank
          "country": "DK"
        }
      },
      "holder": {
        "name": "John Doe", // Name of the account holder
        "address": { // Address of the account holder
          "street": "123 Example Street",
          "zipcode": "12345",
          "city": "Exampleville",
          "state": "CA",
          "country": "US"
        }
      },
      "update_time": "2016-04-01T12:27:36Z",
      "create_time": "2016-04-01T12:23:19Z"
    },
    {
      // Next bank-account...
    }
]

GET https://app-api.coinify.com/bank-accounts

On success, the endpoint returns a list of bank-account objects for the current trader.

The accounts are ordered by id (highest first).

HTTP Response code JSON data
200 OK Success, response as shown to the right.
401 Unauthorized Error, access token missing.
404 Not found Error, no bank accounts found.

Get bank account

Example request for GET /bank-accounts/12345

{
  "id": 12345, // Identifier of the bank account
  "account": {
    "type": "danish", // Type of bank account
    "currency": "DKK", // Currency of the bank account
    "bic": "6456", // Account bic/swift/reg number depending on the type
    "number": "12345435345345" // Account number
  },
  "bank": {
    "address": { // Address of the bank
      "country": "DK"
    }
  },
  "holder": {
    "name": "John Doe", // Name of the account holder
    "address": { // Address of the account holder
      "street": "123 Example Street",
      "zipcode": "12345",
      "city": "Exampleville",
      "state": "CA",
      "country": "US"
    }
  },
  "update_time": "2016-04-01T12:27:36Z",
  "create_time": "2016-04-01T12:23:19Z"
}

GET https://app-api.coinify.com/bank-accounts/<id>

On success, the endpoint returns a bank-account object.

HTTP Response code JSON data
200 OK Success, response as shown to the right.
401 Unauthorized Error, access token missing.
403 Forbidden Error, the supplied access token doesn’t have the rights to delete this bank-account.
404 Not found Error, bank-account is not found.

Delete bank account

DELETE https://app-api.coinify.com/bank-accounts/<id>

Deletes a bank account.

HTTP Response code Description
204 No Content Success, empty response.
401 Unauthorized access token missing.
403 Forbidden The supplied access token doesn’t have the rights to delete this bank-account.
404 Not found bank-account is not found.

Cards

Introduction

We allow our partner’s to save credit/debit cards through our card API. This set of features is provided to allow partners to do a more custom skinned solution to handle;

This section contains the create, list, get and delete end-points of the (credit/debit) cards used when creating a trade.

Card object

Represents a card (credit/debit) used for payment.

Example of a card object:

{
  "externalId": "2820723",
  "lastFour": "0014",
  "nameOnCard":"John Doe",
  "bin":"401200",
  "expiryDate":"0120",
  "cardBrand":"visa"
}
Key Type Description
externalId String PSP’s assigned identifier for the card in this session. This number is not guaranteed to be unique per card.
lastFour String Last four numbers of the card
nameOnCard String The name of the customer on the card
bin String Bank Identification Number (first 6 or 8 digits, AKA IIN, Issue Identification Number)
expiryDate String Card’s expiration date (two digits for month and two for year)
cardBrand String Card’s brand (Mastercard, Visa, Amex, etc)

Save card

A card can be saved for future card purchases.

By utilising the functionality provided by the Coinify client-side psp library we allow partners to create a custom form to input card such as name, card number and CVV code in order to save the card for future purchases.

You can find more info about create card flow on Coinify client-side psp library.

List cards

Returns a list of card objects

Example response for GET /cards

[
  {
    "externalId": "2820723",
    "lastFour": "0014",
    "nameOnCard":"John Doe",
    "bin":"401200",
    "expiryDate":"0120",
    "cardBrand":"visa"
  },
  {
    "externalId": "2820724",
    "lastFour": "2500",
    "nameOnCard":"John Doe",
    "bin":"505100",
    "expiryDate":"1225",
    "cardBrand":"mastercard"
    }
  ]

GET https://app-api.coinify.com/cards/

On success, the endpoint returns a list of card objects for the current trader.

If no cards are saved for the current trader, an empty array is returned.

The accounts are ordered by id (highest first).

HTTP Response code JSON data
200 OK Success, response as shown to the right or JSON empty array if no cards.
401 Unauthorized Error, Access token missing or invalid.

Delete card

DELETE https://app-api.coinify.com/card/<id>

Deletes a card.

HTTP Response code Description
204 No Content Success, empty response.
401 Unauthorized Error Access token missing or invalid.
403 Forbidden Error The supplied access token doesn’t have the rights to delete this card.
404 Not found Error card is not found.

Pay using saved cards

The Coinify PSP Library handles the functionality needed when paying for a trade with a saved card.

You can find more info about trade payment flow on Coinify client-side psp library.

Webhooks

This section describes the webhooks that are sent to partners’ backend systems when certain events occur to entities controlled by the partner.

Webhooks perform signed HTTP POST requests about specific events to a URL of your choice.

Webhook structure

This section describes the general structure of the webhooks that you will receive.

// Example webhook payload
{
  "id": "bd21c0e7-ddb6-4f8e-9367-a6ca00eca25c",
  "time": "2017-09-14T09:07:11.335Z",
  "event": "kyc.approved",
  "context": {
    "kycId": "1",
    "traderId": "1"
  }
}

All webhooks are sent as JSON, and shares the same general structure as described in the following table:

Key Type Description
id String (UUID v4) Unique identifier for the event. Retries for the same events will share the same uuid.
time String (ISO-8601 timestamp) Timestamp for when the event occurred
event String Event that occurred. See Webhook events for a list of possible events
context Object Context for this event. Structure is defined by the event as described in Webhook events.

Webhook events

This section provides a list of possible events that can be received as webhooks

Context of kyc.* events

{
  "kycId": "1",
  "traderId": "1"
}
Event Description
kyc.approved KYC review has been approved
kyc.rejected KYC review has been rejected

How to respond to a webhook request

This section describes how your system should respond to an incoming webhook request

If you respond with a 2xx code, our system will consider the webhook as successfully sent and received.

If you respond with another status code than 2xx, our system will consider the webhook request as a failure and retry at a later time. See Retrying failed requests for more information about the retry strategy.

If the webhook signature is incorrect, you should consider replying just as you would if the signature was correct, to avoid attackers being able to brute-force the shared secret.

Retrying failed requests

This section describes how failed webhook requests will be retried

We will use exponential backoff for handling webhook retries.

Retry attempts Retry Interval
12 16 sec

And use this formula to calculate next retry attempt

next_retry_attempt = retry_interval + retry_count^2

Webhook signature

Node pseudo-code to validate signature

const crypto = require('crypto');

const sharedSecret = 'shared-secret';

// Express example
const body = req.body;
const signature = req.headers['X-Coinify-Webhook-Signature'];

const hash = crypto.createHmac('sha256', sharedSecret)
  .update(JSON.stringify(body))
  .digest('hex');

return hash === signature;

Python pseudo-code to validate signature

import hashlib, hmac

shared_secret = 'the_shared_secret'

# Get the raw HTTP POST body (JSON object encoded as a string)
body = get_body()

# Get the signature from the HTTP or email headers
signature = get_header("X-Coinify-Webhook-Signature")

expected_signature = hmac.new(shared_secret, msg=body, digestmod=hashlib.sha256).hexdigest()
return signature == expected_signature

All webhooks sent from Coinify are signed with a shared secret that is known only by you and Coinify. This ensures the integrity of the data contained in the webhook, and also proves that Coinify is the sender of the webhook (provided the shared secret is not known by anyone else).

Specifically, the signature uses HMAC-SHA256, using the shared secret as the key and the full HTTP request body (UTF-8 encoded) as the message. The resulting signature is provided in lowercase hexadecimal format in the X-Coinify-Webhook-Signature HTTP header.

Client-side psp library

This section outlines the overall info and purpose of the client-side psp library that is integrated in the partner’s front-end application to handle specific client-side operations used when saving a credit/debit card.

In order to safely handle the users card information under PCI regulations a client side library is needed for a limited set of functionality.

Coinify client-side library exposes a set of functionality to gracefully handle such functionality; 1. Save a credit/debit card for later purchases. ( without triggering a purchase ) 2. Pay with a saved credit/debit card. ( handle things like 3D secure authentication ) 3. Create custom payment form when paying for a trade. ( also allow for paying with out without saving card for later usage ). 4. Fetch 3rd-party client-side dependencies needed for various aspects of paying ( Risk Engine components, Analytics, Provider libraries )

Documentation and examples

The documentation along with examples can be found on the following url;

https://github.com/CoinifySoftware/coinify-psp-lib/blob/master/README.md