Getting started

The Dinero API is REST based, which is easy to work with and familiar to developers.

To use the API, you need to apply as a developer. We will send you a Client ID and a client secret, which you should use to authenticate yourself through the API.

If you want to use an API key on behalf of your account, you will also need to obtain the key for the organization. Please navigate to the API page in Dinero to generate the key. You need an active Dinero Pro subscription for the organization that you need to access. You can upgrade your subscription on the subscription page.

If the organization does not have an active Dinero Pro subscription, the request will be denied with HTTP 403 (Forbidden) and errorcode 48.

If you have any technical questions, please email us at api@dinero.dk

Base URL

https://api.dinero.dk

Authentication

Dinero uses token based authentication through OAuth2. This means that you use a token on every request to authorize yourself.

Your EncodedClientIdAndSecret and the target organizations API-key is used with the above endpoint, in exchange for a token, which you then append on every future requests.

You'll need a new token for each organization you want to access.

If your request was composed correctly, and your credentials were correct, the server will return an access_token in JSON format for you to use

Authentication endpoint

https://authz.dinero.dk/dineroapi/oauth/token

Example request

curl -X POST \
    https://authz.dinero.dk/dineroapi/oauth/token \
    -H 'authorization: Basic bXljbGllbnRpZDpYZlVXZzRrb1h0TFc5cjNFbGthTzYxQkw2Q2Y3S0Y2Y1NmR2c2ak1FODQ=' \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'grant_type=password&scope=read%20write&username=yourApiKey&password=yourApiKey'
private static async Task<AuthorizationToken> Authenticate(Uri uri, string clientId, string clientSecret, string api)
{
    using (var client = new HttpClient())
    {
        var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
        {
            new KeyValuePair("grant_type", "password"),
            new KeyValuePair("scope", "read write"),
            new KeyValuePair("username", api),
            new KeyValuePair("password", api),
        });

        var request = new HttpRequestMessage
        {
            RequestUri = uri,
            Method = HttpMethod.Post,
            Content = content,
            Headers =
            {
                { "Authorization", string.Format("Basic {0}", Base64Encode($"{clientId}:{clientSecret}")) }
            }
        };

        var result = await client.SendAsync(request).ConfigureAwait(false);

        var response = await result.Content.ReadAsStringAsync().ConfigureAwait(false);

        return JsonConvert.DeserializeObject<AuthorizationToken>(response);
    }
}

private static string Base64Encode(string plainText)
{
    var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);

    return Convert.ToBase64String(plainTextBytes);
}
const http = require("https");
const querystring = require('querystring');

const bodyParameters = querystring.stringify({
    'grant_type': 'password',
    'scope=': 'read write',
    'username': 'yourApiKey',
    'password' 'yourApiKey'
});

const options = {
  'method': 'POST',
  'hostname': 'authz.dinero.dk',
  'path': '/dineroapi/oauth/token',
  'headers': {
    'authorization': 'Basic bXljbGllbnRpZDpYZlVXZzRrb1h0TFc5cjNFbGthTzYxQkw2Q2Y3S0Y2Y1NmR2c2ak1FODQ=',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': bodyParameters.length
  }
};

new Promise((resolve) => {
    
    var req = http.request(options, (res) => {
        const chunks = [];

        res.on("data", (chunk) => {
            chunks.push(chunk);
        });

        res.on("end", function () {
            const body = Buffer.concat(chunks).toString();
            resolve(JSON.parse(body));
        });
    });

    req.write(bodyParameters);
    req.end();

}).then(tokenResponse => {

    console.log(tokenResponse);
});
function authenticate(string $uri, string $clientId, string $clientSecret, string $apiKey) {
    $data = [
        'grant_type' => 'password',
        'scope' => 'read write',
        'username' => $apiKey,
        'password' => $apiKey,
    ];

    $encodedClientAndSecret = base64_encode($clientId . ":" . $clientSecret);

    $options = [
        'http' => [
            'header' => "Authorization: Basic $encodedClientAndSecret",
            'method'  => 'POST',
            'content' => http_build_query($data)
        ]
    ];

    $context  = stream_context_create($options);

    $resultPayload = file_get_contents($uri, false, $context);
}

    POST /dineroapi/oauth/token HTTP/1.1
    Host: authz.dinero.dk
    Authorization: Basic bXljbGllbnRpZDpYZlVXZzRrb1h0TFc5cjNFbGthTzYxQkw2Q2Y3S0Y2Y1NmR2c2ak1FODQ=
    Content-Type: application/x-www-form-urlencoded
    grant_type=password&scope=read write&username=yourApiKey&password=yourApiKey

Response

{
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9(...)",
    "token_type":"Bearer",
    "expires_in":3600,
    "refresh_token":null
}
public class AuthorizationToken
{
    [JsonProperty(PropertyName = "access_token")]
    public string AccessToken { get; set; }

    [JsonProperty(PropertyName = "refresh_token")]
    public string RefreshToken { get; set; }

    [JsonProperty(PropertyName = "expires_in")]
    public long Expires { get; set; }
}
{
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9(...)",
    "token_type":"Bearer",
    "expires_in":3600,
    "refresh_token":null
}
{
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9(...)",
    "token_type":"Bearer",
    "expires_in":3600,
    "refresh_token":null
}
{
    "access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9(...)",
    "token_type":"Bearer",
    "expires_in":3600,
    "refresh_token":null
}

Usage

After obtaining an access token, you append it on every request using the following header: Authorization: Bearer [access_token]

Where [access_token] should be replaced with the token you just received.

Core resources on the left show API and description of all available endpoints

Example to create four new ledger items

POST https://api.dinero.dk/v1/:organizationId/ledgeritems HTTP/1.1
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9(...)
Host: api.dinero.dk
Content-Type: application/json
Content-Length: 821
[
    {"VoucherNumber":3,"AccountNumber":1000,"AccountVatCode":"I25","Amount":-500,"BalancingAccountNumber":null,"BalancingAccountVatCode":null,"Description":"produkt, lille","VoucherDate":"2015-05-27"},
    {"VoucherNumber":3,"AccountNumber":1300,"AccountVatCode":"none","Amount":-25,"BalancingAccountNumber":null,"BalancingAccountVatCode":null,"Description":"Momsfrit fragt","VoucherDate":"2015-05-27"},
    {"VoucherNumber":3,"AccountNumber":53000,"AccountVatCode":null,"Amount":525,"BalancingAccountNumber":null,"BalancingAccountVatCode":null,"Description":"Faktura 12","VoucherDate":"2015-05-27"},
    {"VoucherNumber":4,"AccountNumber":2000,"AccountVatCode":"none","Amount":100,"BalancingAccountNumber":52000,"BalancingAccountVatCode":null,"Description":"Vareforbrug ifbm fak 12","VoucherDate":"2015-05-27"},
]

TLS Negotiation

We have removed support for TLS under 1.2. Therefore trying to create a connection to Dinero with either TLS 1.0 or 1.1 will fail. If you are running on older frameworks, this means that you will have to implement usage of higher TLS version

In .NET this can be accomplised by applying the following:

.NET 4.6 or higher
TLS 1.2 is supported by default

.NET 4.5
TLS 1.2 is supported, but is deactivated by default. It can be activated by setting: ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

.NET 4.0
TLS 1.2 is not supported. But if you have .NET 4.5 or higher installed, is can be activated by setting: ServicePointManager.SecurityProtocol = (SecurityProtocolType) 3072;

.NET 3.5 eller lavere
TLS 1.2 is not supported, and there are no workarounds

Glossary

ClientId and ClientSecret

You will receive your API credentials on email, when you have been approved as an API partner. If you have not yet applied you can do it here

Encoded ClientId and ClientSecret

Is your encoded ClientId and ClientSecret. To get the [encodedSecret] you need to base64 encoded your ClientSecret and ClientId seperated by ':', as shown here: [client_id]:[client_secret] .

API key

The API key of the organization you want to access in Dinero. This will have be provided by your customer/user of you integration. To genereate an API key, you need to be a Dinero-Pro user, as an API partner we can grant you Pro access on your test organization, just contact our support. For a guide how to create an API key, se here

Organization

"Organization" is the term we use for the users "Firma" in Dinero. If you need a test organization, here is a guide to how you can create one.

Organization id

The organization id of the organization you want to access in Dinero. This will have to be provided by your customer/user of you integration. Here is a guide to where you can find the organization id on a Dinero organization

Ledger items

Equal to the danish "kassekladde linje".

Error codes

Code Message Description

Apply

We love integrations. Do you have a software that just needs to be integrated with Dinero? Please submit your request below, and we will contact you soon.

We retain the opportunity to reject applications:

  • because of security issues,
  • the service is too close to our business,
  • other political reasons

Filters

Filters are not available on all properties, so be sure to check the endpoints queryFilter URI parameter description to see which. If the endpoint do not contain a queryFilter URI parameter, then it does not support filtering.

Each filter command is built after the structure: [PropertyName] [Operator] '[Value]'

Be aware that the [Value] is not case sensitive. And remember the ' around it.

Each filter command should be separated with: ;

Name Types Operator Example
Equals string, int, bool eq Name eq ’John Doe’
Contains string contains Name contains ’John D’

Example

https://api.dinero.dk/v1/{organizationId}/contacts?queryFilter=Name+contains+'a';IsPerson+eq+'False'

Pagination

Get methods that potentially has a very large output implements pagination. It can maximum return 1000 entries per page, if a higher pageSize is given an Exception with error code 43 is thrown. The pagination defaults to a pageSize of 100 entries, and returns the first page if left empty.

The pagination URI properties are listed below:

Name Description Type Additional information
page The 0-based page number integer Default value is 0
pageSize The maximum number of items to include in a page. Max 1000. integer Default value is 100. Max value is 1000.

Throttling

There are no limit on the number of API requests per day. However, requests will be rate-limited if too many calls are made within a short period of time. Rate limiting is considered on a per API-key basis. An organization can have multiple API-keys associated to it. Each api-key will be considered separately. There are currently no limitations on the client_id

If you hit the rate limit, this is the body of the HTTP 429 message that you will see: API calls quota exceeded! (...)

If Dinero detects that the API resources are being exhausted by a single client integration and it is evaluated by Dinero to hurt the general service of the API to other customers, Dinero can decide to revoke the access for single clients. Dinero will always strive to solve such issues in dialog with the integrating partner before any counter measures are taken.

Posting image

An example of how a post call to our files service could look like:

Example

POST https://api.dinero.dk/v1/[organization_id]/files/?fileName=sample-invoice.jpg HTTP/1.1
    Authorization: Bearer eyJ0eXAiOiJKV1QiLC....
    Accept: application/json
    Content-Type: multipart/form-data; boundary="-------abcdefg1234"
    Host: api.dinero.dk
    Content-Length: 313036
    Expect: 100-continue
    Connection: Keep-Alive

    ---------abcdefg1234
    Content-Type: image/jpeg
    Content-Disposition: form-data; name=image; filename=sample-invoice.jpg; filename*=utf-8''sample-invoice.jpg
    [ReplaceWithYourImage]
    ---------abcdefg1234--