• Developers
  • Getting started with Bunq API through cURL - a step-by-step tutorial

Being inspired by the Bunq Update 13 simplified API update, I figured I'd attempt it out. This turns out to be quite more difficult than initially thought!

As per https://together.bunq.com/d/7867-google-spreadsheets-support-with-google-scripts-and-bunq-api/13 I wanted to import data into Google Sheets through the API-Connector plugin. In order to find out what's needed, I wanted to start with accessing the API through simple cURL commands.

In order to save some time for anyone who would like to do the same, this is how I managed to get things started on the Sandbox. Note, by default the transaction overview is empty and one needs to add money manually (last item below).

I am using the Raw outputs and keys specifically created for this tutorial.

I hope this helps. This is my initial experience with the Bunq API so I'm not sure if I can be really useful in further assistance :)

Step 1: Request Sandbox User api_key
curl https://public-api.sandbox.bunq.com/v1/sandbox-user -X POST --header "Content-Type: application/json" --header "Cache-Control: none" --header "User-Agent: curl-request" --header "X-Bunq-Client-Request-Id: $(date)randomId" --header "X-Bunq-Language: nl_NL" --header "X-Bunq-Region: nl_NL" --header "X-Bunq-Geolocation: 0 0 0 0 000"

{"Response":[{"ApiKey":{"api_key":"sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5"}}]}

Remember api_key "sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5"

Step 2: Generate Private and Public keys
openssl genrsa -out private2.pem 2048
openssl rsa -in private2.pem -outform PEM -pubout -out public2.pem

Step 3: Create an installation
The the content from public.pem as per the example. Note, it will be one-line and enters have been replaced with \n

curl --request POST \
--url https://public-api.sandbox.bunq.com/v1/installation \
--header 'Content-Type: application/json' \
--header 'Cache-Control: no-cache' \
--header 'User-Agent: bunq-TestServer/1.00 sandbox/0.17b3' \
--header 'X-Bunq-Client-Request-Id: $(date)randomId' \
--header 'X-Bunq-Geolocation: 0 0 0 0 000' \
--header 'X-Bunq-Language: nl_NL' \
--header 'X-Bunq-Region: nl_NL' \
--header 'cache-control: no-cache' \
--data '{"client_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmX/QqID9Fm1ia13bpzF1\nHf6N5ZgEvBJCIBJOH+ehroWj3OEjC3+t7Ce3y23omG6r062+KXxM/HYM5FNLKnT/\n6X316PMv5A65nX+XMvh9g29z3uLKX1KxY+h4YvPS2+jZ9MkAj9E6qs2E+yvTgUlv\nQo/pZb6UbDjuqVF0hSD5kkd6lh2D/DzXspROWiYu9JLceQlKEQ9KWHMNY1SVaByN\nKdR/6rKMtfS1X8njzlnMxfo6imnIIq+hBh0sI3I9wbk4fAowuVfIQHx/14O6WeGd\n1MGSr9lXU1uhXQTL/OEGsbJLcG80DuJQ3SYiAHzyXUARD1ms+zkfTuXpM/SqB6V8\nQQIDAQAB\n-----END PUBLIC KEY-----"}'

{"Response":[{"Id":{"id":101889}},{"Token":{"id":1460683,"created":"2020-01-30 15:31:56.634092","updated":"2020-01-30 15:31:56.634092","token":"a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d"}},{"ServerPublicKey":{"server_public_key":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyvMMhu+MIrYrZ0uY7Kb6\nd2rYYO5jaAUdPNT6nFX1cv47rQq3gL\/Rm9B4J\/fpeifp3fO9iqyVkKj+CfZZ9PtP\nx6lC40StckojPIQ7TcWZMp0NkDzipmJoZtGudLlm4TZhiyB17hxbSA6tqI3nK0z1\nMu+DsoL6wgapOJ\/zm2OqU1NdkzbwJO83sMwRKrqzCKG+om2qDCWTWxAcKXfRykUb\n4s0L1PU6alankELwA2B4cDwpeG+U2voZ9UwAq9BgrD4ts13i1GGmpa9rciUAywUi\n4OjCZdA63jtgldjzZhiQdTVudjWQkQJumWB28p0w1hB\/LqbKm7BbS7rizTKC1d+H\nUwIDAQAB\n-----END PUBLIC KEY-----\n"}}]}

Remember the token "a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d"

Step 4: Create a Device-server
Use your noted token as "X-Bunq-Client-Authentication:" and noted api_key as "secret".
Replace 1.2.3.4 with your own IP.

curl --request POST \
--url 'https://public-api.sandbox.bunq.com/v1/device-server' \
--header 'X-Bunq-Client-Authentication: a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d' \
--data '{"description": "Daxy rPI test","secret": "sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5","permitted_ips": ["1.2.3.4","*"]}'

{"Response":[{"Id":{"id":55523}}]}

Step 5: Create session

User your noted api_key as "secret"

echo -n '{"secret":"sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5"}'| openssl dgst -sha256 -sign private2.pem | base64 -w0

Use the output as "X-Bunq-Client-Signature" and your api_key as secret.
Use the previously used token for "X-Bunq-Client-Authentication".

curl --request POST \
--url 'https://public-api.sandbox.bunq.com/v1/session-server' \
--header 'X-Bunq-Client-Authentication: a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d' \
--header 'X-Bunq-Client-Signature: OIyexw9rIKP0TWrzVZdK5BDRqw4UfQ8Mx+3wrXiGQl3Z+YAAhl47yljJCg8V7BFJttUcMplXk4Yf0AC3uxii8t/bCRTajXEwIRTi+GQfkFdt9x68Yo4vacV9Vj7KtLnMppN4HUhPLw0PuVA3R29rHn5BLn3er790YHx+ZmJ9vHHNEs65Xw25oy16PStiFEn+H49mYev21hr66bQYPe7CkmmjWyLluAZDq9j83p7gW+91KFgSA/0LwY8dDGrEAzbQg6A8wjtSikIOP/C1FKtKxyZ4kNhWdq8Up8CpkYdyhkntEKVFtBV8YKZT8T19SRwIj/BKO1SkwZoyvi0ZZuAqWQ==' \
--data '{"secret":"sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5"}'

{"Response":[{"Id":{"id":1460735}},{"Token":{"id":1460735,"created":"2020-01-30 15:33:07.844404","updated":"2020-01-30 15:33:07.844404","token":"24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac"}},{"UserPerson":{"id":27790,"created":"2020-01-30 15:28:14.893439","updated":"2020-01-30 15:28:14.894949","alias":[{"type":"PHONE_NUMBER","value":"+31610398094","name":"+31610398094"},{"type":"EMAIL","value":"thijs-test+1580398094@bunq.com","name":"thijs-test+1580398094@bunq.com"}],"avatar":{"uuid":"9debf55b-70b1-4d43-8d51-d6e7bd42fb5b","image":[{"attachment_public_uuid":"4b7e0d1d-9167-48ac-990a-70e342c87812","height":126,"width":200,"content_type":"image\/jpeg"}],"anchor_uuid":"ad408872-def8-45d1-abc9-b883dca0b339"},"status":"ACTIVE","sub_status":"NONE","public_uuid":"ad408872-def8-45d1-abc9-b883dca0b339","display_name":"T. Rozemeijer","public_nick_name":"Thijs","language":"de_DE","region":"de_DE","session_timeout":604800,"daily_limit_without_confirmation_login":{"currency":"EUR","value":"250.00"}, <output snipped>

Remember the token from the output, this will be used as "X-Bunq-Client-Authentication" going forward: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac

Step 6: Run API commands from CLI
curl --request GET \
--header 'X-Bunq-Client-Authentication: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac' \
--url 'https://public-api.sandbox.bunq.com/v1/user'

{"Response":[{"UserPerson":{"id":27790,"created":"2020-01-30 15:28:14.893439","updated":"2020-01-30 15:28:14.894949","alias":[{"type":"PHONE_NUMBER","value":"+31610398094","name":"+31610398094"},{"type":"EMAIL","value":"thijs-test+1580398094@bunq.com","name":"thijs-test+1580398094@bunq.com"}],"avatar":{"uuid":"9debf55b-70b1-4d43-8d51-d6e7bd42fb5b","image":[{"attachment_public_uuid":"4b7e0d1d-9167-48ac-990a-70e342c87812","height":126,"width":200,"content_type":"image\/jpeg"}],"anchor_uuid":"ad408872-def8-45d1-abc9-b883dca0b339"},"status":"ACTIVE","sub_status":"NONE","public_uuid":"ad408872-def8-45d1-abc9-b883dca0b339","display_name":"T. Rozemeijer","public_nick_name":"Thijs","language":"de_DE","region":"de_DE","session_timeout":604800,"daily_limit_without_confirmation_login":{"currency":"<output snipped>

curl --request GET \
--header 'X-Bunq-Client-Authentication: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac' \
--url 'https://public-api.sandbox.bunq.com/v1/user/27790/monetary-account'

You'll get a list of accounts (1 in Sandbox), use the account-ID in the next url to add funds to your account:

curl --request POST \
--url 'https://public-api.sandbox.bunq.com/v1/user/27790/monetary-account/25634/request-inquiry' \
--header 'X-Bunq-Client-Authentication: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac' \
--data '{
"amount_inquired": {
"value": "500",
"currency": "EUR"
},
"counterparty_alias": {
"type": "EMAIL",
"value": "sugardaddy@bunq.com"
},
"description": "Pls",
"allow_bunqme": true
}'

    Whoa! This does not line up with the Update 13 presentation: https://youtu.be/1rZ94F7q418?t=1124

    For example:

    I've done some prep work [...] It took me two whole minutes.

    and

    [...] we took out all the things you found complicating. We took out the signing. We took out the extra headers.

    Shouldn't there be an easier way? No way this is less than two minutes of work, and you are still signing the session request. Maybe @bunq can chime in on this one?

      @mdekker#143978 Dit is puur om de API koppeling te maken en verifiëren. Zodra die er is, kan je makkelijk API-calls maken zoals in de presentatie. Zie ook mijn laatste stap, vanaf daar is het allemaal makkelijk(er) en simpel zonder vele headers te regelen.

        In that case, thanks for going through this whole experience and sharing with us!
        It's a great tutorial, but from the presentation you'd think it would be a whole lot easier.

          @Marcel-Daxy#143935 Thanks for posting this, excellent reference!

          You can also use the hackathon tool to link transactions in a sheet. This website does the curl stuff for you and you end up with the importdata() Google sheet function instead of JavaScript macro, which is also simpler.
          https://easylist.aule.net/

            @Marcel-Daxy#143935 Hi Marcel, thanks for sharing the amazing tutorial with fellow bunqers! ❤️

            After bunq Update 13, we made it even easier to handle requests so you could save even more time. Here's how it can work now:

            Step 1: Request Sandbox User api_key

            Request

            curl https://public-api.sandbox.bunq.com/v1/sandbox-user -X POST

            Response

            {"Response":[{"ApiKey":{"api_key":"sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5"}}]}

            Step 2: Generate Private and Public keys

            openssl genrsa -out private2.pem 2048
            openssl rsa -in private2.pem -outform PEM -pubout -out public2.pem

            Step 3: Create an installation

            The the content from public.pem as per the example. Note, it will be one-line and enters have been replaced with \n

            Request

            curl --request POST \
            --url https://public-api.sandbox.bunq.com/v1/installation \
            --data '{"client_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmX/QqID9Fm1ia13bpzF1\nHf6N5ZgEvBJCIBJOH+ehroWj3OEjC3+t7Ce3y23omG6r062+KXxM/HYM5FNLKnT/\n6X316PMv5A65nX+XMvh9g29z3uLKX1KxY+h4YvPS2+jZ9MkAj9E6qs2E+yvTgUlv\nQo/pZb6UbDjuqVF0hSD5kkd6lh2D/DzXspROWiYu9JLceQlKEQ9KWHMNY1SVaByN\nKdR/6rKMtfS1X8njzlnMxfo6imnIIq+hBh0sI3I9wbk4fAowuVfIQHx/14O6WeGd\n1MGSr9lXU1uhXQTL/OEGsbJLcG80DuJQ3SYiAHzyXUARD1ms+zkfTuXpM/SqB6V8\nQQIDAQAB\n-----END PUBLIC KEY-----"}'

            Response

            {"Response":[{"Id":{"id":101889}},{"Token":{"id":1460683,"created":"2020-01-30 15:31:56.634092","updated":"2020-01-30 15:31:56.634092","token":"a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d"}},{"ServerPublicKey":{"server_public_key":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyvMMhu+MIrYrZ0uY7Kb6\nd2rYYO5jaAUdPNT6nFX1cv47rQq3gL\/Rm9B4J\/fpeifp3fO9iqyVkKj+CfZZ9PtP\nx6lC40StckojPIQ7TcWZMp0NkDzipmJoZtGudLlm4TZhiyB17hxbSA6tqI3nK0z1\nMu+DsoL6wgapOJ\/zm2OqU1NdkzbwJO83sMwRKrqzCKG+om2qDCWTWxAcKXfRykUb\n4s0L1PU6alankELwA2B4cDwpeG+U2voZ9UwAq9BgrD4ts13i1GGmpa9rciUAywUi\n4OjCZdA63jtgldjzZhiQdTVudjWQkQJumWB28p0w1hB\/LqbKm7BbS7rizTKC1d+H\nUwIDAQAB\n-----END PUBLIC KEY-----\n"}}]}


            Remember the token "a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d"

            Step 4: Create a Device-server

            Use your noted token as "X-Bunq-Client-Authentication:" and noted api_key as "secret".
            Replace 1.2.3.4 with your own IP.

            Request

            curl 'https://public-api.sandbox.bunq.com/v1/device-server' -X POST \
            --header 'X-Bunq-Client-Authentication: a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d' \
            --data '{"description": "Daxy rPI test","secret": "sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5","permitted_ips": ["1.2.3.4","*"]}'

            Response

            {"Response":[{"Id":{"id":55523}}]}

            Step 5: Create session


            User your noted api_key as "secret"

            Signing

            You might get a response from our API indicating that you should sign the request. You can use this method for that (as provided by Marcel!).

            echo -n '{"secret":"sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5"}'| openssl dgst -sha256 -sign private2.pem | base64 -w0


            Use the output as "X-Bunq-Client-Signature" and your api_key as secret.
            Use the previously used token for "X-Bunq-Client-Authentication".

            Request

            curl 'https://public-api.sandbox.bunq.com/v1/session-server' -X POST \
            --header 'X-Bunq-Client-Authentication: a9bac146dd5a3c26d0f64b99e1bb17435aa99254e9c0cfb7f52f75a08a2ed30d' \
            --data '{"secret":"sandbox_083afcba99dcd6d2e7047fa397be0b730eb7d5dd00f8edeba95fe9e5"}'

            Response

            {"Response":[{"Id":{"id":1460735}},{"Token":{"id":1460735,"created":"2020-01-30 15:33:07.844404","updated":"2020-01-30 15:33:07.844404","token":"24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac"}},{"UserPerson":{"id":27790,"created":"2020-01-30 15:28:14.893439","updated":"2020-01-30 15:28:14.894949","alias":[{"type":"PHONE_NUMBER","value":"+31610398094","name":"+31610398094"},{"type":"EMAIL","value":"thijs-test+1580398094@bunq.com","name":"thijs-test+1580398094@bunq.com"}],"avatar":{"uuid":"9debf55b-70b1-4d43-8d51-d6e7bd42fb5b","image":[{"attachment_public_uuid":"4b7e0d1d-9167-48ac-990a-70e342c87812","height":126,"width":200,"content_type":"image\/jpeg"}],"anchor_uuid":"ad408872-def8-45d1-abc9-b883dca0b339"},"status":"ACTIVE","sub_status":"NONE","public_uuid":"ad408872-def8-45d1-abc9-b883dca0b339","display_name":"T. Rozemeijer","public_nick_name":"Thijs","language":"de_DE","region":"de_DE","session_timeout":604800,"daily_limit_without_confirmation_login":{"currency":"EUR","value":"250.00"}, <output snipped>


            Remember the token from the output, this will be used as "X-Bunq-Client-Authentication" going forward: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac

            Step 6: Run API commands from CLI

            Request

            curl 'https://public-api.sandbox.bunq.com/v1/user' GET \
            --header 'X-Bunq-Client-Authentication: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac' \

            Response

            {"Response":[{"UserPerson":{"id":27790,"created":"2020-01-30 15:28:14.893439","updated":"2020-01-30 15:28:14.894949","alias":[{"type":"PHONE_NUMBER","value":"+31610398094","name":"+31610398094"},{"type":"EMAIL","value":"thijs-test+1580398094@bunq.com","name":"thijs-test+1580398094@bunq.com"}],"avatar":{"uuid":"9debf55b-70b1-4d43-8d51-d6e7bd42fb5b","image":[{"attachment_public_uuid":"4b7e0d1d-9167-48ac-990a-70e342c87812","height":126,"width":200,"content_type":"image\/jpeg"}],"anchor_uuid":"ad408872-def8-45d1-abc9-b883dca0b339"},"status":"ACTIVE","sub_status":"NONE","public_uuid":"ad408872-def8-45d1-abc9-b883dca0b339","display_name":"T. Rozemeijer","public_nick_name":"Thijs","language":"de_DE","region":"de_DE","session_timeout":604800,"daily_limit_without_confirmation_login":{"currency":"<output snipped>

            Example (List monetary accounts)

            curl 'https://public-api.sandbox.bunq.com/v1/user/27790/monetary-account' \
            --header 'X-Bunq-Client-Authentication: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac' \


            You'll get a list of accounts (1 in Sandbox), use the account-ID in the next url to add funds to your account:

            Request

            curl -X POST 'https://public-api.sandbox.bunq.com/v1/user/27790/monetary-account/25634/request-inquiry' \
            --header 'X-Bunq-Client-Authentication: 24a3f3032ffdf1e19a04a166b662c7108b5f2660c4bd0e892a8a4eafa2451aac' \
            --data '{
            "amount_inquired": {
            "value": "500",
            "currency": "EUR"
            },
            "counterparty_alias": {
            "type": "EMAIL",
            "value": "sugardaddy@bunq.com"
            },
            "description": "Pls",
            "allow_bunqme": true
            }'
              11 days later

              @Marcel-Daxy#143935 bedankt voor jouw stap-voor-stap uitleg over hoe de Bunq api te gebruiken.
              Ik ben nieuw op het gebied van API's en vraag me af waar ik bij stap 1 het request kan maken?

                @Fabio-Silver-Badger#145670 Just open the terminal application on your laptop.

                It is easier for non-techie people to use Postman (prefer it myself too 😉).

                  4 months later

                  Love this guide. Works perfect expect the inquiry. I get only an empty Response back:

                  {"Response":[],"Pagination":{"future_url":"\/v1\/user\/55350\/monetary-account\/43584\/request-inquiry?newer_id=0","newer_url":null,"older_url":null}}

                  This was my body:
                  {"amount_inquired":{"value":"100","currency":"EUR"},"counterparty_alias":{"type":"IBAN","value":"NL73ABNA8253182457","name":"Sugar Daddy"},"description":"You are the best Daddy","allow_bunqme":false}

                  Sent with Auth, Signature and all Params... If I change Accountnumber or Customer Number I get an Error that I do not have the permissions. So it seems that they are correct.

                  Any Idea?

                  Update: I solved it by myself. I made a GET call, not a POST :D

                    Write a Reply...