Introduction
Welcome to Januar API! You can use our API to automate access to your payment accounts with Januar.
Environments
Januar provides two distinct environments available to the public:
Environment name | Base URL | Description |
---|---|---|
UAT | https://api.uat.januar.com |
Used for testing integrations |
Production | https://api.januar.com |
Live production environment |
Message format
The Januar API uses JSON for both HTTP request and response payloads.
Success responses
Success response example where primary data is an object
{
"data": {
// ...
},
"metadata": {}
}
Success response example for a list endpoint
{
"data": [
// ...
],
"metadata": {
"pagination": {
"pageSize": 100,
"page": 0,
"totalRecords": 1234
}
}
}
Whenever the API returns a success status code (2xx
), the response payload contains a JSON object
with the following format:
Field | Type | Description |
---|---|---|
data |
Object or Array | Primary data returned from the endpoint. |
metadata |
Object | Metadata about the response |
↳ pagination |
Object | (Optional) Pagination information, is defined in list endpoints. |
↳ pageSize |
Number | Maximum number of records returned per page in this response |
↳ page |
Number | Page number to retrieve, 0-indexed |
↳ totalRecords |
Number | Total number of records available |
Error responses
Error format example
{
"error": {
"code": "insufficient-funds",
"message": "Your account does not have sufficient balance to carry out this operation.",
"context": {
"requiredBalance": "123.45",
"availableBalance": "100.00",
"currency": "EUR"
}
},
"sessionId": "ABC123ABC1234"
}
Default error payload for
401 Unauthorized
{
"error": {
"code": "invalid-authentication",
"message": "Authentication failed",
"context": {}
},
"sessionId": "ABC123ABC1234"
}
Default error payload for
404 Not Found
{
"error": {
"code": "not-found",
"message": "The requested resource was not found",
"context": {}
},
"sessionId": "ABC123ABC1234"
}
Whenever the API returns an error status code (4xx
for client errors, 5xx
for server errors),
the response payload contains a JSON object with the following format (See example to the right):
Field | Type | Description |
---|---|---|
error |
Object | Object describing the error that occurred. |
↳ code |
String | Machine-readable error code. |
↳ message |
String | Human-friendly error message. |
↳ context |
Object | Additional information related to the error. Object structure depends on the error code . Empty object if nothing. |
sessionId |
String | (Optional) session ID (also known as correlation ID) for the action. null if error occurred in such a way that an ID could not be generated (never expected to happen). |
The Januar API uses the following HTTP error codes:
Error Code | Meaning |
---|---|
400 Bad Request |
Bad Request -- Your request is invalid. |
401 Unauthorized |
Unauthorized -- Your authentication details are invalid. See Authentication section for more information |
403 Forbidden |
You are not allowed to access the specified resource. |
404 Not Found |
The specified resource could not be found. |
500 Internal Server Error |
We had a problem with our server. Try again later. |
503 Service Unavailable |
We're temporarily offline for maintenance. Please try again later. |
Common data types
This section lists common data types that will be used throughout the API:
Amount
All amounts are decimal numbers encoded as strings to avoid implicit precision errors when encoding/decoding the amounts.
An example is "203.10"
.
Country
All countries are represented by their * ISO 3166-1 alpha-2 country code*.
Examples include "DE"
for Germany, and "DK"
for Denmark.
Currency
All fiat currencies are represented by their ISO 4217 currency code.
Examples include "EUR"
for Euro, and "DKK"
for Danish Krone.
IBAN
IBANs (International Bank Account Number) are defined in the ISO 13616 standard (Wikipedia IBAN page).
An example of a Danish IBAN is "DK8589000099106422"
.
BIC code
BICs (Business Identifier Code) are represented by their * ISO 9362 code*.
An example of a Danish BIC is "SXPYDKKKXXX"
.
Timestamp
All timestamps are represented by a *ISO 8601 timestamp *.
An example is "2022-09-05T09:28:36Z"
, meaning the timestamp 09:28:36 (UTC timezone) on September
5th, 2022.
Timestamps may include millisecond precision where applicable: "2022-09-05T09:28:36.420Z"
Authentication
Example
Authorization
header:
Authorization: JanuarAPI apikey="e871abb0-8a8d-4f6a-8551-7d34927af641", nonce="1660895358165", signature="oEp4bQXaYnRWG2XrbGfqeuGPEef6fokPjq9mA+gzBbE="
You must obtain an API key and secret pair to access our API. This key and secret pair must be used in the construction of every HTTP request to authenticate towards our API.
In order to authenticate an HTTP request, it must include the following information in the Authorization
HTTP header:
apikey
: API keynonce
: An integer that must increase with every successful request. It's common to use current Unix timestamp with millisecond precision for this.signature
:HMAC-SHA256
signature of request using API secret as key, encoded using base64
Signature generation
To generate a valid
Authorization
header, use this code:
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
String method="POST";
String accountId="cd74be8b-9f34-456e-86ee-15fa46a2a8b7";
String path=URLEncoder.encode("/accounts/"+accountId+"/transactions/payout","UTF-8");
String payload="{\"amount\": \"12.45\", \"currency\": \"DKK\", \"iban\": \"LU044080000020017267\", \"paymentTime\": \"2023-05-25T11:43:00Z\", \"message\": \"Transfer to Acme customer\", \"name\": \"James Robert\", \"internalNote\": \"message to myself\"}";
String apiKey="e871abb0-8a8d-4f6a-8551-7d34927af641";
String apiSecret="d39e5f5d-281e-4917-a878-8392dedaaf55";
SecretKeySpec secretKey=new SecretKeySpec(apiSecret.getBytes("UTF-8"),"HmacSHA256");
long nonce=1660895358165L; // // Use System.currentTimeMillis() to get current Unix timestamp
String messageToSign=nonce+"|"+method+"|"+path+"|"+payload;
Mac sha256_HMAC=Mac.getInstance("HmacSHA256");
sha256_HMAC.init(secretKey);
String signature=new String(Base64.encodeBase64(sha256_HMAC.doFinal(messageToSign.getBytes("UTF-8"))));
String authHeader="Authorization: JanuarAPI apikey=\""+apiKey+"\", nonce=\""+nonce+"\", signature=\""+signature+"\"";
System.out.println(authHeader);
// Outputs:
// Authorization: JanuarAPI apikey="e871abb0-8a8d-4f6a-8551-7d34927af641", nonce="1660895358165", signature="3hhU/isW55nkONRRi0rPoBwv6+MP0LDtIkgXLCxeiRI="
import crypto from 'crypto';
const method = 'POST';
const accountId = 'cd74be8b-9f34-456e-86ee-15fa46a2a8b7'
const path = encodeURIComponent(
'/accounts/' + accountId + '/transactions/payout');
const payload = JSON.stringify(
{
"amount": "12.45",
"currency": "DKK",
"iban": "LU044080000020017267",
"paymentTime": "2023-05-25T11:43:00Z",
"message": "Transfer to Acme customer",
"name": "James Robert",
"internalNote": "message to myself"
});
const apiKey = 'e871abb0-8a8d-4f6a-8551-7d34927af641';
const apiSecret = 'd39e5f5d-281e-4917-a878-8392dedaaf55';
const nonce = 1660895358165; // Use Date.now() to get current Unix timestamp
const messageToSign = nonce + '|' + method + '|' + path + '|' + payload;
const signature = crypto.createHmac('sha256', apiSecret).update(messageToSign).digest('base64');
const authHeader = `Authorization: JanuarAPI apikey="${apiKey}", nonce="${nonce}", signature="${signature}"`;
// Outputs:
// Authorization: JanuarAPI apikey="e871abb0-8a8d-4f6a-8551-7d34927af641", nonce="1660895358165", signature="3hhU/isW55nkONRRi0rPoBwv6+MP0LDtIkgXLCxeiRI="
console.log(authHeader);
import base64
import hmac
import json
import time
import urllib.parse
from hashlib import sha256
method = 'POST'
account_id = 'cd74be8b-9f34-456e-86ee-15fa46a2a8b7'
path = '/accounts/' + account_id + '/transactions/payout'
encoded_path = urllib.parse.quote(path, safe='')
payload = {
"amount": "12.45",
"currency": "DKK",
"iban": "GB15CLYD82663220400952",
"paymentTime": "2023-05-25T11:43:00Z",
"message": "Transfer to Acme customer",
"name": "James Robert",
"internalNote": "message to myself"
}
api_key = "e871abb0-8a8d-4f6a-8551-7d34927af641"
api_secret = "d39e5f5d-281e-4917-a878-8392dedaaf55"
nonce = 1660895358165 # use int(time.time() * 1000) for current Unix timestamp
message_to_sign = f"{nonce}|{method}|{encoded_path}|{json.dumps(payload)}".encode(
"utf-8")
sha256_HMAC = hmac.new(api_secret.encode("utf-8"), message_to_sign,
digestmod=sha256)
signature = base64.b64encode(sha256_HMAC.digest()).decode()
auth_header = f'Authorization: JanuarAPI apikey="{api_key}", nonce="{nonce}", signature="{signature}"'
print(auth_header)
# Output
# Authorization: JanuarAPI apikey="e871abb0-8a8d-4f6a-8551-7d34927af641", nonce="1660895358165", signature="3Cr1HxM7ZNnAIFNehJ4FLbbHPvFFdE0xi8cFJ4tGiOE="
Make sure to replace
apiKey
andapiSecret
with your API key and secret pair.
A valid request signature signs over the following parts of an HTTP request:
- Nonce
- Method:
GET
,POST
, etc - Path including query string:
e.g.
/accounts/340975fd-fc40-4011-8f21-c8d6abd4a124/transactions?page=0&pageSize=1000
- Body: e.g.
{"action":"pay"}
. If the request does not have a body, an empty string is used.
The signature is a HMAC-SHA256 of the concatenation of the nonce, method (uppercased), path (including query string) and body (if no body, empty string), separated by pipe character (|
), using the API secret as signing key, encoded with base64.
Authentication error
Authentication error object (HTTP status code will be
401 Unauthorized
)
{
"code": "IDENTITY_ACCESS_MANAGEMENT_CUSTOMER_UNAUTHORIZED",
"message": "Customer is not authorized to access this resource",
"context": {}
}
In case the Authorization
header is missing, api key doesn't exist, or the signature validation fails, any request will fail with a 401 Unauthorized
HTTP status code.
Accounts
The Accounts API also has Swagger/OpenAPI documentation available here
Terminology
This section aims to provide a high-level overview of the different entities and concepts in the Accounts API
Concept | Description |
---|---|
Account | An account holds your balances in one or more currencies. |
Balance | A balance is the amounts of total, available and reserved money in a single currency of a given account. |
Transaction | A transaction in its basic form represents a group of account movements happening as one unit. It is specialized in multiple different sub types detailing individual interactions that can happen on your account, e.g. a payout (See Types of transactions below). |
Types of transactions
Type | Description |
---|---|
Payin | A payin transaction is when money is received in your account from an external account. |
Returned payin | A returned payin transaction is when a previously received payin transaction was returned to the sender. |
Payout | A payout transaction is when money is sent from your account to an external account. |
Returned payout | A returned payout transaction is when a previously sent payout transaction was returned to your account. |
Currency conversion | A currency conversion transaction is when you convert money from one currency in your account to another currency in the same account. |
Fee | A fee transaction is when your account is charged a stand-alone fee. |
Returned fee | A returned fee transaction is when a previously paid fee transaction was returned to your account. |
List accounts
Example
200 OK
response forGET /accounts
{
"data": [
{
"id": "f27cd81e-27ef-43fd-9aaf-22abe65dd0c7",
"name": "My account",
"status": "active",
"defaultCurrency": "EUR",
"currencies": {
"DKK": {
"balance": "1175023.15"
},
"EUR": {
"balance": "996225.43"
}
},
"accountNumbers": [
{
"iban": "DK8589000099106422",
"country": "DK",
"defaultCurrency": "EUR",
"bank": {
"name": "BANKING CIRCLE",
"bic": "SXPYDKKKXXX",
"address": [
{
"street": "Amerika Plads 38",
"zip": "2100",
"city": "København Ø",
"region": "Hovedstaden",
"country": "DK"
}
]
},
"bankIdentifier": "8900",
"accountNumber": "0099106422"
}
]
}
],
"metadata": {}
}
This endpoint retrieves all your accounts.
HTTP Request
GET /accounts
HTTP Response
200 OK
The endpoint returns a list of account objects
Get account
Example
200 OK
response forGET /accounts/:accountId
{
"data": {
"id": "f27cd81e-27ef-43fd-9aaf-22abe65dd0c7",
"name": "My account",
"status": "active",
"defaultCurrency": "EUR",
"currencies": {
"DKK": {
"balance": "1175023.15"
},
"EUR": {
"balance": "996225.43"
}
},
"accountNumbers": [
{
"iban": "DK8589000099106422",
"country": "DK",
"defaultCurrency": "EUR",
"bank": {
"name": "BANKING CIRCLE",
"bic": "SXPYDKKKXXX",
"address": [
{
"street": "Amerika Plads 38",
"zip": "2100",
"city": "København Ø",
"region": "Hovedstaden",
"country": "DK"
}
]
}
}
]
},
"metadata": {}
}
This endpoint retrieves an account.
HTTP Request
GET /accounts/:accountId
Path Parameters
Parameter | Description |
---|---|
accountId |
ID of the account to be retrived. |
HTTP Response
200 OK
The endpoint returns an account object
List transactions
This endpoint lists all transactions for a particular account, sorted by newest first.
Example
200 OK
response forGET /accounts/75db7319-d2fd-4610-98c2-201fbe49e6f3/transactions
{
"data": [
{
"id": "814b3ab1-b997-40a3-8c63-5593518fb619",
"accountId": "75db7319-d2fd-4610-98c2-201fbe49e6f3",
"type": "PAYOUT",
"currency": "EUR",
"status": "COMPLETED",
"amount": "-123.45",
"feeAmount": "-0.10",
"message": "Transfer to Acme customer",
"internalNote": "message to myself",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
},
"initiatedTime": "2022-08-17T11:31:43.868328Z",
"paymentTime": "2022-08-31T10:00:00Z"
},
{
// ... more transactions
}
],
"metadata": {
"pagination": {
"pageSize": 100,
"page": 0,
"totalRecords": 61
}
}
}
HTTP Request
GET /accounts/:accountId/transactions
Path Parameters
Parameter | Description |
---|---|
accountId |
ID of account to list transactions for. |
Query Parameters
Parameter | Default | Description |
---|---|---|
types |
[] |
If set, only return transactions of the given types |
pageSize |
100 |
Positive integer determining how many transactions to return per page, max 1000 |
page |
0 |
Page number to retrieve, 0-indexed |
statuses |
[] |
List of payout Payout statuses to query. As statuses only apply to payouts, adding a status filter to the query, will result in only payouts will be returned. If not provided, all types will be queried |
dateFrom |
null |
Determines the earliest transactionTime of the transactions queried. Format YYYY-MM-DD |
dateTo |
null |
Determines the latest transactionTime of the transactions queried. Format YYYY-MM-DD |
amountFrom |
null |
Determines the inclusive lower limit for the transaction amount |
amountTo |
null |
Determines the inclusive upper limit for the transaction amount |
currencies |
[] |
List of currencies code to query. If not provided, all transaction currencies will be queried |
text |
null |
Search term. Will query in following fields message , counterparty.accountNumber , counterparty.name , internalNote |
HTTP Response
200 OK
The endpoint returns a list of transactions
Possible errors
HTTP Status code | error.code |
Description | context |
---|---|---|---|
404 Not Found |
ACCOUNT_NOT_FOUND |
Account with ID :accountId not found on customer: :customerId |
None |
400 Bad Request |
BAD_REQUEST |
Invalid value: :value for field: :field |
None |
400 Bad Request |
BAD_REQUEST |
Type mismatch | None |
400 Bad Request |
CURRENCY_NOT_SUPPORTED |
Invalid currency: :currency |
None |
Get transaction
This endpoint retrieves a transaction for a particular account.
Example
200 OK
responsefor
GET /accounts/75db7319-d2fd-4610-98c2-201fbe49e6f3/transactions/814b3ab1-b997-40a3-8c63-5593518fb619
{
"data": {
"id": "814b3ab1-b997-40a3-8c63-5593518fb619",
"accountId": "75db7319-d2fd-4610-98c2-201fbe49e6f3",
"type": "PAYOUT",
"completedTime": "2023-03-26T01:00:08.806Z",
"currency": "EUR",
"status": "COMPLETED",
"amount": "-123.45",
"feeAmount": "0.00",
"message": "Transfer to Acme customer",
"internalNote": "message to myself",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
},
"initiatedTime": "2023-03-21T10:51:40.415604Z",
"paymentTime": "2023-03-26T11:51:40Z"
},
"metadata": {}
}
HTTP Request
GET /accounts/:accountId/transactions/:transactionId
Path Parameters
Parameter | Description |
---|---|
accountId |
ID of the account to list the transaction. |
transactionId |
ID of the transaction to be retrieved. |
HTTP Response
200 OK
The endpoint returns a transaction
Possible errors
HTTP Status code | error.code |
Description | context |
---|---|---|---|
404 Not Found |
ACCOUNT_NOT_FOUND |
Account with ID :accountId not found on customer: :customerId |
None |
400 Bad Request |
BAD_REQUEST |
Type mismatch | None |
Initiate payout
This endpoint enables you to initiate a single payout.
HTTP Request
POST /accounts/:accountId/transactions/payout
Example request for initiating a payout at
POST /accounts/:accountId/transactions/payout
{
"amount": "10.01",
"currency": "EUR",
"paymentTime": "2022-09-16T06:00:00Z",
"message": "Payment ref: #abcdef",
"internalNote": "Payment for goods",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
}
}
Path Parameters
Parameter | Description |
---|---|
accountId |
ID of account to initiate the payout for. |
Request body
Field | Type | Description |
---|---|---|
amount |
Amount | The amount of the payout. Note the fee amount will be visible on the initiated payout instance. |
currency |
Currency | Currency of the payout. |
paymentTime |
Timestamp | (Optional) The future timestamp of when this payout should happen. If not specified it should happen now. |
message |
String | Message to the receiver. |
internalNote |
String | (Optional) Note only visible to the creator of the payout. |
counterparty |
Counterparty | Counterparty information. |
↳ name |
String | Name of the receiver of this payout |
↳ accountNumber |
String | Account number of the reciever - this can be an IBAN(ISO 13616:2020) or BBAN |
↳ accountNumberType |
String | Type of the account number - either IBAN or BBAN |
↳ accountNumberCountryCode |
String | (Optional for IBANs) Country code of the account number |
HTTP Response
Example
201 Created
response from initiate payout
{
"data": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"accountId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "PAYIN",
"completedTime": "2022-11-12T12:34:56Z",
"currency": "EUR",
"status": "PENDING",
"amount": "10.01",
"feeAmount": "0.51",
"message": "Payment ref: #abcdef",
"internalNote": "Payment for goods",
"initiatedTime": "2022-11-12T12:34:56Z",
"paymentTime": "2022-11-12T12:34:56Z",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
}
},
"metadata": {}
}
201 Created
The endpoint returns a payout transaction
Possible errors
HTTP Status code | error.code |
Description | context |
---|---|---|---|
400 Bad Request |
invalid-format |
There was a formatting error in the request. See error message for details. | None |
400 Bad Request |
invalid-iban |
Invalid IBAN specified. | None |
400 Bad Request |
insufficient-funds |
There is insufficient funds available on the account to initiate the payout. | requiredBalance : the required balance for the payoutavailableBalance : the available balancecurrency : currency for the balances |
400 Bad Request |
invalid-payment-time |
The paymentTime must be in the future. |
None |
400 Bad Request |
unsupported currency |
Specified currency is not supported by the account. | None |
404 Not found |
account-not-found |
Account with ID :accountId could not be found. |
None |
Cancel payout
Example request for cancelling a payout at
PUT /accounts/:accountId/transactions/payout/:payoutId/cancel
Example
200 OK
response from canceled payout
{
"data": {
"id": "67f8cbd2-166a-48b2-86e1-f0c46a426aa3",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"type": "PAYOUT",
"currency": "EUR",
"status": "CANCELLED",
"amount": "-123.45",
"feeAmount": "-0.10",
"message": "Transfer to Acme customer",
"internalNote": "message to myself",
"initiatedTime": "2022-09-05T10:45:12Z",
"paymentTime": "2022-09-16T06:00:00Z",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
}
},
"metadata": {}
}
This endpoint enables you to cancel payouts.
HTTP Request
PUT /accounts/:accountId/transactions/payout/:payoutId/cancel
Path Parameters
Parameter | Description |
---|---|
accountId |
ID of account to initiate the payout for. |
payoutId |
ID of the payout to cancel |
Request body
The request body should be left empty
HTTP Response
200 OK
The endpoint returns a payout transaction with a
CANCELLED
status
Possible errors
HTTP Status code | error.code |
Description | context |
---|---|---|---|
404 Not Found |
ACCOUNT_NOT_FOUND |
Account with ID :accountId not found on customer: :customerId |
None |
404 Not Found |
PAYOUT_NOT_FOUND |
Payout with ID :payoutId could not be found. |
None |
400 Bad Request |
payout-not-cancelable |
The specified payout is not cancelable as it is in a final state | None |
400 Bad Request |
BAD_REQUEST |
Type mismatch | None |
Data model
This section describes the data model of each type of entity in the Accounts API:
Account
Example account object
{
"id": "f27cd81e-27ef-43fd-9aaf-22abe65dd0c7",
"name": "My account",
"status": "active",
"defaultCurrency": "EUR",
"currencies": {
"DKK": {
"balance": "1175023.15"
},
"EUR": {
"balance": "996225.43"
}
},
"accountNumbers": [
{
"iban": "DK8589000099106422",
"country": "DK",
"defaultCurrency": "EUR",
"bank": {
"name": "BANKING CIRCLE",
"bic": "SXPYDKKKXXX",
"address": [
{
"street": "Amerika Plads 38",
"zip": "2100",
"city": "København Ø",
"region": "Hovedstaden",
"country": "DK"
}
]
},
"bankIdentifier": "8900",
"accountNumber": "0099106422"
}
]
}
An account holds your balances in one or more currencies.
Field | Type | Description |
---|---|---|
id |
String (UUID) | Unique identifier for the account |
name |
String | Name of account |
status |
String | Either active or inactive |
defaultCurrency |
Currency | Currency code for account's default currency. Always corresponds to a key in the currencies object. |
currencies |
Object | Map of currencies supported by the account. Each key is a supported currency. |
↳ currency |
Object | Single currency supported by the account. |
↳ balance |
String | Balance for specific currency in the account. |
accountNumbers |
Array | Account numbers associated with the account |
↳ [] |
Object | A single account number object |
↳ iban |
IBAN | IBAN (International Bank Account Number) |
↳ country |
Country | Country of account number |
↳ defaultCurrency |
Currency | Default currency of account number. |
↳ bank |
Bank | Bank providing the account number |
Transaction
Example transaction object of type
PAYIN
.Note that the
id
,accountId
,type
, andcompletedTime
fields are present for all types of transactions, while the rest of the fields are specific for thePAYIN
transaction type.
{
"id": "780e39f3-4fde-49c8-bd25-2ec2364fd01e",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"type": "PAYIN",
"completedTime": "2022-08-15T11:45:32Z",
"currency": "EUR",
"amount": "123.45",
"feeAmount": "-0.10",
"message": "Transfer from Acme customer",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
}
}
A transaction in its basic form represents a group of account movements happening as one unit. It is specialized in multiple different sub types detailing individual interactions that can happen on your account, e.g. a payout.
A transaction has a number of base fields which are always included for any transaction type, as well as a number of fields which are type-specific. The base fields are defined first, and subsequently each specific transaction type is documented:
Field | Type | Description |
---|---|---|
id |
String (UUID) | Unique identifier for the transaction. |
accountId |
String (UUID) | Reference to the account that this transaction belongs to. |
type |
String | Type of transaction. This value should be used to determine which type-specific fields are included. See transaction types below. |
completedTime |
Timestamp | (Optional) Timestamp when the transaction was completed. |
Transaction types
For a brief overview of the different transaction types, please refer to the terminology section above.
type |
Transaction type |
---|---|
PAYIN |
Payin |
RETURNED_PAYIN |
Returned Payin |
PAYOUT |
Payout |
RETURNED_PAYOUT |
Returned Payout |
CURRENCY_CONVERSION |
Currency conversion |
FEE |
Fee |
RETURNED_FEE |
Returned Fee |
Payin transaction (PAYIN
)
Example payin transaction object
{
"id": "314b54a3-eb06-4dba-9032-9c06618763aa",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"type": "PAYIN",
"completedTime": "2022-08-15T11:45:32Z",
"currency": "EUR",
"amount": "123.45",
"feeAmount": "-0.10",
"message": "Transfer from Acme customer",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
}
}
A payin transaction is when money is received in your account from an external account. The account
balance increases with the amount specified in the amount
field (subtracted an
optional feeAmount
).
Field | Type | Description |
---|---|---|
currency |
Currency | Currency code for this payin |
amount |
Amount | Positive amount indicating the money received in the account. |
feeAmount |
Amount | Zero or negative amount indicating the amount deducted as a fee of this transaction. |
message |
String | Free-text description from the sender. |
counterparty |
Counterparty | Counterparty information. |
↳ name |
String | Name of the receiver of this payout |
↳ accountNumber |
String | Account number of the reciever - this can be an IBAN(ISO 13616:2020) or BBAN |
↳ accountNumberType |
String | Type of the account number - either IBAN or BBAN |
↳ accountNumberCountryCode |
String | (Optional for IBANs) Country code of the account number |
Returned Payin transaction (RETURNED_PAYIN
)
Example returned payin transaction object
{
"id": "c16f5074-132b-4d41-b5d7-c7ffdb8217e6",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"payinId": "314b54a3-eb06-4dba-9032-9c06618763aa",
"type": "RETURNED_PAYIN",
"completedTime": "2022-08-15T11:45:32Z",
"currency": "EUR",
"amount": "-123.45",
"feeAmount": "0.10"
}
A returned payin transaction is when a previously received payin transaction was returned to the sender.
Field | Type | Description |
---|---|---|
payinId |
String (UUID) | Id of the original payin transaction that this transaction returns. |
currency |
Currency | Currency code for this returned payin |
amount |
Amount | Negative amount indicating the money subtracted from the account. |
feeAmount |
Amount | Zero or positive amount indicating the amount added to the account. |
Payout transaction (PAYOUT
)
Example payout transaction object
{
"id": "67f8cbd2-166a-48b2-86e1-f0c46a426aa3",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"type": "PAYOUT",
"completedTime": "2022-08-15T11:45:32Z",
"paymentTime": "2022-08-15T11:40:12Z",
"initiatedTime": "2022-08-15T11:40:12Z",
"currency": "EUR",
"status": "COMPLETED",
"amount": "-123.45",
"feeAmount": "-0.10",
"message": "Transfer to Acme customer",
"internalNote": "message to myself",
"counterparty": {
"name": "Januar Aps",
"accountNumber": "DE68500105178297336485",
"accountNumberType": "IBAN",
"accountNumberCountryCode": "DE"
},
"initiator": {
"type": "user",
"user": {
"name": "John Doe",
"email": "john.doe@company.com"
}
},
"approver": {
"type": "user",
"user": {
"name": "Jane Doe",
"email": "jane.doe@company.com"
}
},
"approvalNote": "LGTM!",
"events": [
{
"type": "initiated",
"timestamp": "2022-11-11T12:34:56Z"
},
{
"type": "approved",
"timestamp": "2022-11-12T12:34:56Z"
},
{
"type": "processed",
"timestamp": "2022-11-131T12:34:56Z"
},
{
"type": "sent-to-recipient"
},
{
"type": "completed"
}
]
}
A payout transaction is a payout from the account to an external account. The account balance
decreased with the amount specified in the amount
field (including an optional feeAmount
).
Field | Type | Description |
---|---|---|
currency |
Currency | Currency code for this payout |
status |
Payout status | Status of this payout |
amount |
Amount | Negative amount indicating the amount deducted from the account for this transaction. |
feeAmount |
Amount | Zero or negative amount indicating the fee amount deducted from the account. |
message |
String | Free-text message to the receiver. |
internalNote |
String | (Optional) Free-text internal note to oneself. |
counterparty |
Counterparty | Counterparty information. |
↳ name |
String | Name of the receiver of this payout |
↳ accountNumber |
String | Account number of the reciever - this can be an IBAN(ISO 13616:2020) or BBAN |
↳ accountNumberType |
String | Type of the account number - either IBAN or BBAN |
↳ accountNumberCountryCode |
String | (Optional for IBANs) Country code of the account number |
initiatedTime |
Timestamp | Timestamp of when the payout was initiated in the account. |
paymentTime |
Timestamp | Timestamp of when the payout was set to happen (payout can be delayed for some reason). |
initiator |
Object | Reference to initiator of payout |
↳ type |
String | Type of initiator. Possible values are api and user . |
↳ user |
Object | (Only present if initiator.type is user ) Initiator user data |
↳ name |
String | Initiator name |
↳ email |
String | Initiator email |
approver |
Object | (Optional) Reference to approver of payout. Only present if payout was manually approved |
↳ type |
String | Type of approver. Only possible value is user . |
↳ user |
Object | Approver user data |
↳ name |
String | Approver name |
↳ email |
String | Approver email |
approvalNote |
String | (Optional) Approver's note. Only present if payout was manually approved |
rejector |
Object | (Optional) Reference to rejector of payout. Only present if payout was manually rejected |
↳ type |
String | Type of rejector. Only possible value is user . |
↳ user |
Object | Rejector user data |
↳ name |
String | Rejector name |
↳ email |
String | Rejector email |
rejectionNote |
String | (Optional) Approver's note. Only present if payout was manually rejected |
events |
Array | List of events related to the payout. Sorted by oldest first |
↳ type |
String | Type of event. Possible values are initiated , approved , processed , sent-to-recipient , completed . |
↳ timestamp |
Timestamp | (Optional) Timestamp of event. Is absent if event has not yet occurred. |
Payout statuses
A PAYOUT
transaction can have the following status
codes:
Status code | Description | Final state? |
---|---|---|
AWAITING_CONFIRMATION |
The payout is awaiting confirmation from initiator. Only used when initiating from the web interface | No |
AWAITING_APPROVAL |
The payout is awaiting approval from an approver | No |
PENDING |
The payout is pending completion | No |
CANCELLED |
The payout was cancelled before it could complete | Yes |
REJECTED |
The payout was rejected | Yes |
COMPLETED |
The payout was successfully executed | Yes |
Returned Payout transaction (RETURNED_PAYOUT
)
Example returned payout transaction object
{
"id": "158315d3-3263-4906-839d-b755ef13498a",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"payoutId": "67f8cbd2-166a-48b2-86e1-f0c46a426aa3",
"type": "RETURNED_PAYOUT",
"completedTime": "2022-08-15T11:45:32Z",
"currency": "EUR",
"amount": "123.45",
"feeAmount": "0.10"
}
A returned payout transaction is when a previously sent payout transaction was returned to your account.
Field | Type | Description |
---|---|---|
payoutId |
String (UUID) | Id of the original payout transaction that it returns. |
currency |
Currency | Currency code for this payout |
amount |
Amount | Positive amount indicating the amount added to the account as part of this returned payout. |
feeAmount |
Amount | Zero or positive amount indicating the fee amount returned as part of this returned payout. |
Currency conversion transaction (CURRENCY_CONVERSION
)
Example currency conversion transaction object
{
"id": "0223f4bd-3072-4387-9c46-b9f927ee756c",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"type": "CURRENCY_CONVERSION",
"completedTime": "2022-08-15T11:45:32Z",
"sellCurrency": "EUR",
"sellAmount": "-1000.00",
"sellRate": "7.44123",
"buyCurrency": "DKK",
"buyAmount": "7441.23"
}
A currency conversion transaction is when you convert money from one currency (the sell currency) in your account to another currency (the buy currency) in the same account.
Field | Type | Description |
---|---|---|
sellCurrency |
Currency | Currency code of the sell amount. |
sellAmount |
Amount | Negative amount indicating the amount deducted from the account. |
sellRate |
String | Rate of the currency conversion. |
buyCurrency |
Currency | Currency code of the buy amount. |
buyAmount |
Amount | Positive number indicating the buy amount added to the account. |
Fee transaction (FEE
)
Example fee transaction object
{
"id": "d4450c67-80a1-4244-9ed3-9ae07aa7c686",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"type": "FEE",
"completedTime": "2022-08-15T11:45:32Z",
"currency": "EUR",
"amount": "-99.90",
"message": "Acme monthly subscription fee"
}
A fee transaction is when your account is charged a stand-alone fee.
Field | Type | Description |
---|---|---|
currency |
Currency | Currency code for this fee. |
amount |
Amount | Negative amount indicating the amount deducted from the account from this fee transaction. |
message |
String | Message describing the fee to the receiver. |
Returned Fee transaction (RETURNED_FEE
)
Example returned fee transaction object
{
"id": "f3507542-edcf-4e8a-959d-3771fef2a380",
"accountId": "3fa8bac8-e173-4d49-8f68-18ec2bd52b2a",
"feeId": "90aac3f6-584b-4d3e-9d9c-a6c1332c74f5",
"type": "RETURNED_FEE",
"completedTime": "2022-08-15T11:45:32Z",
"currency": "EUR",
"amount": "99.90"
}
A returned fee transaction is when a previously paid fee transaction was returned to your account.
Field | Type | Description |
---|---|---|
feeId |
String (UUID) | Id of the fee transaction that it returns. |
currency |
Currency | Currency code for this fee. |
amount |
Amount | Positive amount indicating the amount added to the account because of this returned fee transaction. |
Bank
Example bank object
{
"name": "BANKING CIRCLE",
"bic": "SXPYDKKKXXX",
"address": {
"street": "Amerika Plads 38",
"zip": "2100",
"city": "København Ø",
"region": "Hovedstaden",
"country": "DK"
}
}
A reference to a bank.
Field | Type | Description |
---|---|---|
name |
String | Bank name |
bic |
BIC | BIC (Business Identifier Code) for bank |
address |
Address | Bank address |
Address
Example address object
{
"street": "Gothersgade 14",
"zip": "1123",
"city": "København",
"region": "Hovedstaden",
"country": "DK"
}
A reference to a physical address.
Field | Type | Description |
---|---|---|
street |
String | Street address |
zip |
String | (Optional) Zip code |
city |
String | City |
region |
String | (Optional) Region country |
country |
Country | Country code. |
Notifications
Terminology for notifications
This section aims to provide a high-level overview of the different entities and concepts for notifications
The overall concept of notifications is to subscribe to get updates on specific events. The triggering events are defined below under Available Channels. This platform currently supports notifications via webhooks or email. To enable notifications, simply create a new notification via the Post Notifications endpoint. To disable notifications, simply delete any existing notifications.
Concept | Description |
---|---|
Webhook | A Webhook is a HTTP POST initiated from januar to the given endpoint carrying a payload of data. |
An Email is a simple email containing relevant info regarding the triggering event from. | |
Channel | A Channel is the entity on which to subscribe to a given available notification. See list of available channels below. |
Destination | A Destination is either an HTTP endpoint for Webhooks or an email address for Emails |
Label | A Label is simply a human readable label for any given notification |
Available Channels and destination types:
Channel | Destination type | Description |
---|---|---|
WEBHOOK_FIAT_ALL | A HTTP(s) endpint | Subscribes to all updates on FIAT transactions, ie everytime a FIAT transactions changes state, a webhook is triggered. |
List notifications
Example
200 OK
response forGET /notifications
{
"data": [
{
"id": "b7acbf16-7c23-4ef9-89c9-c1223dfe9a17",
"channel": "WITHDRAWAL_ADDRESS_UPDATE_EMAIL",
"destination": "test@test.com",
"label": "label"
}
],
"metadata": {}
}
This endpoint returns a list of active notifications.
HTTP Request
GET /notifications
HTTP Response
The endpoint returns a list of notification objects.
Create notification
Example request for submitting a new notification at POST /notifications
{
"channel": "WITHDRAWAL_ADDRESS_UPDATE_EMAIL",
"destination": "test@test.com",
"label": "label"
}
Example
201 Created
response from submit notification
{
"data": [
{
"id": "b7acbf16-7c23-4ef9-89c9-c1223dfe9a17",
"channel": "WITHDRAWAL_ADDRESS_UPDATE_EMAIL",
"destination": "test@test.com",
"label": "label"
}
],
"metadata": {}
}
This endpoints allows you to submit a new notification.
HTTP Request
POST /notifications
Request Body
Parameter | Type | Description | Validation rules |
---|---|---|---|
channel |
String | Channel, see available list above | required |
destination |
String | email or endpoint | required |
label |
String | Human readable label | required |
HTTP Response
The endpoint returns a notification object.
Possible errors
HTTP Status code | Error Code | Description |
---|---|---|
400 Bad Request |
VALIDATION |
Request body had invalid input |
400 Bad Request |
NOTIFICATION_INVALID |
The destination is already defined |
Update notification
Example request for submitting a new notification at PUT /notifications/:notificationid
{
"channel":"WITHDRAWAL_ADDRESS_UPDATE_EMAIL",
"destination":"test@test.com",
"label":"label"
}
Example
201 Created
response from submit notification
{
"data": [
{
"id": "b7acbf16-7c23-4ef9-89c9-c1223dfe9a17",
"channel": "WITHDRAWAL_ADDRESS_UPDATE_EMAIL",
"destination": "test@test.com",
"label": "label"
}
],
"metadata": {}
}
This endpoints allows you to update an existing notification.
HTTP Request
PUT /notifications/:notificationid
Path Parameters
Parameter | Type | Description |
---|---|---|
notificationid |
UUID | ID of notification to be updated |
Request Body
Parameter | Type | Description | Validation rules |
---|---|---|---|
channel |
String | Channel, see available list above | required |
destination |
String | email or endpoint | required |
label |
String | Human readable label | required |
HTTP Response
The endpoint returns a notification object.
Possible errors
HTTP Status code | Error Code | Description | context |
---|---|---|---|
400 Bad Request |
VALIDATION |
Request body had invalid input | |
400 Bad Request |
NOTIFICATION_NOT_FOUND |
The notification can not be found |
Delete notification
This endpoint allows you to delete a given notification.
HTTP Request
DELETE /notifications/:notificationid
Path Parameters
Parameter | Type | Description |
---|---|---|
notificationid |
UUID | ID of notification to be deleted |
HTTP Response
The endpoint returns a 204 No Content
response with an empty body.
Possible errors
HTTP Status code | Error Code | Description |
---|---|---|
404 Not Found |
NOTIFICATION_NOT_FOUND |
The given notification was not found |
Notification Data Model
Example Notification object
{
"id": "b7acbf16-7c23-4ef9-89c9-c1223dfe9a17",
"channel": "WITHDRAWAL_ADDRESS_UPDATE_EMAIL",
"destination": "test@test.com",
"label": "Withdrawal address email recipient"
}
Field | Type | Description |
---|---|---|
id |
UUID | The unique identifier of the notification |
channel |
String | The channel of the wallet |
destination |
String | Either email or HTTP endpoint |
label |
String | Human readable label. |