Signing

TL:DR On signing requests

Why we need signing

For some API calls we want to make sure the content tampered with. For instance making a payment, you would not want anyone to be able to change the amount or receiving party. Adding a signature allows bunq to detect whether the request body has been tampered with.

When do you need signing

Any request that creates or accepts a payment. If you forget to sign it we'll tell you with error 466

What is a signature?

A signature is nothing more than a extra header: X-Bunq-Client-Signature that you add to your API call. You'll need to write some code in your application that takes in the request body and your private key (some examples are mentioned below)

When Do You Need to Sign Requests?

Most API calls don’t need signing, but any request that creates or accepts a payment does. If you forget to sign it, you’ll get a 466 error—so keep an eye out for that!

How It Works

  • You sign the request body (not the whole request).

  • We verify the signature on our end.

  • We sign our response, so you can verify it too.

What You Need

  • A private key (which you generate when installing your API connection).

  • The public key we send you, which you’ll use to verify our responses.

Example Curl request

This is a payment to Sugardaddy for €0,10. As you can see in the header we added the X-Bunq-Client-Signature header. This is just a Base64 encoded representation of the request body.

curl --location 'https://public-api.sandbox.bunq.com/v1/user/1800297/monetary-account/1989601/payment' \
--header [other headers]' \
--header 'X-Bunq-Client-Signature: eMymd9ynLx+j5tpcoPMlaJ7vEyxIZAXWInXIRxIOyP24KF7lpvNIwElB/wiQqVXr99pua4+onqvJUNiuceInAtohJnSGDEd58GjeBthz2OHTG5I0GZyJ9S8XAuBJYbqPgFaIk2m0VelPmjAHbiA3WSH0ASMDvcht/p4n60Y1GMVESXFovU2jUWX2X2k5QhowitIBJnsf4fkvYknbispFvUTn4ESU8QQVBgwR9QJ8DpxObGYbsTKQCyTzXoKNLM1mkw3pMwHn1EZ+AmOTx5iR/xXZLvvXWDmj9rEZWms7G1+drmhkK5aV8PuvR6s11mS6laRxyS1eoCaOcqeOZs1EcQ==' \
--data-raw '{
    "amount": {
        "value": "0.10",
        "currency": "EUR"
    },
    "counterparty_alias": {
        "type": "EMAIL",
        "value": "[email protected]",
        "name": "Sugar Daddy"
    },
    "description": "My payment description :)"
}'

Request signing example

Consider the following request, a POST to /v1/user/126/monetary-account/222/payment (the JSON is formatted with newlines and indentations to make it more readable - be careful to account for that when creating your signature):

Header
Value

Cache-Control:

no-cache

User-Agent:

bunq-TestServer/1.00 sandbox/0.17b3

X-Bunq-Client-Authentication:

f15f1bbe1feba25efb00802fa127042b54101c8ec0a524c36464f5bb143d3b8b

{
    "amount": {
        "value": "12.50",
        "currency": "EUR"
    },
    "counterparty_alias": {
        "type": "EMAIL",
        "value": "[email protected]"
    },
    "description": "Payment for drinks."
}

Let's sign that request. First create a variable $dataToSign containing the body of the request:

{
    "amount": {
        "value": "12.50",
        "currency": "EUR"
    },
    "counterparty_alias": {
        "type": "EMAIL",
        "value": "[email protected]"
    },
    "description": "Payment for drinks."
}

Next, create the signature of $dataToSign using the SHA256 algorithm and the private key $privateKey of the Installation's key pair. In PHP, use the following to create a signature. The signature will be passed by reference into $signature.

openssl_sign($dataToSign, $signature, $privateKey, OPENSSL_ALGO_SHA256);

Encode the resulting $signature using base64, and add the resulting value to the request under the X-Bunq-Client-Signature header. You have just signed your request, and can send it!

Troubleshooting

If you are getting error 466 for invalid signatures then it's best to test these things:

Check list:

If you run into issues, double-check these points—or just use our SDKs, which handle all of this for you.

Standards and formats

To ensure secure and valid request and response signatures, you should use the following standards: First, apply SHA256 as the cryptographic hash function to hash the data (either the request body or response body). For the signing process, use the private key with PKCS #1 v1.5 padding for RSA encryption to generate the signature. Once the signature is created, it must be base64-encoded to ensure proper transmission in HTTP headers. This ensures that the integrity and authenticity of the data are preserved, and the signature can be verified by the recipient using the corresponding public key.

Response Signatures

In some cases you might also want to validate whether responses are actually sent by bunq. Here you can do the same thing. If you stored the public key of the bunq server (you received this during installation) you can verify the response sent by bunq and validate that the response body matches the signature.

Last updated

Was this helpful?