This guide demonstrates how to access customer account data using the Blink Data API.
| Environment | Base URL |
|---|---|
| Sandbox | https://sandbox.data.blinkpay.co.nz |
| Production | https://data.blinkpay.co.nz |
Request:
POST /oauth2/token HTTP/1.1
Host: sandbox.data.blinkpay.co.nz
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}
Response:
{
"access_token": "eyJhbGc...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "manage:consents read:meta read:accounts read:balances read:transactions read:party"
}
Tokens last about 1 hour (expires_in). Cache the token and reuse it for every call until it expires; request a new one only when it has expired or the API returns 401, then retry the call. Don't request a new token per request. You don't request scopes: the token carries the scopes assigned to your API client.
Request:
POST /v1/consents HTTP/1.1
Host: sandbox.data.blinkpay.co.nz
Authorization: Bearer {access_token}
Content-Type: application/json
idempotency-key: 6f1c2b8e-4a7d-4c1e-9b3f-2d5e8a9c0f14
{
"flow": {
"detail": {
"type": "redirect",
"bank": "PNZ",
"redirect_uri": "https://your-site/callback"
}
},
"permissions": [
"ReadAccounts",
"ReadBalances",
"ReadTransactions"
],
"start_date_time": "2025-10-01T00:00:00+13:00",
"end_date_time": "2026-12-31T23:59:59+13:00",
"expiration_date_time": "2026-12-31T23:59:59+13:00"
}
start_date_time and end_date_time set the window of data the consent covers: you can retrieve transactions and statements dated between them. start_date_time can't be in the future, end_date_time must be after today (New Zealand date), and the two must fall on different dates. Leave end_date_time out to read up to the latest available transaction, and change the example dates once they have passed. expiration_date_time is when access ends; it can't be on the day you create the consent or before end_date_time, and you can omit it for a consent that doesn't expire. See Consent Duration.
Response:
{
"consent_id": "c8327a00-3f1a-4d10-a27a-aece83eadabc",
"redirect_uri": "{bank_authorisation_url}"
}
For the redirect flow, redirect_uri is the bank's authorisation URL. (A gateway consent returns the BlinkPay gateway URL instead, and a decoupled consent returns only consent_id.)
Send an idempotency-key header with a UUID on each POST /v1/consents, and reuse the same key if you retry that request. The retry returns the original consent instead of creating a second one.
Redirect the customer to the redirect_uri to authorise data access at their bank. The customer chooses which accounts to share there, so a consent can cover more than one account.
Test Bank (PNZ):
user01passwordThe customer returns to your redirect URI with the consent ID in cid:
https://your-site/callback?cid=c8327a00-3f1a-4d10-a27a-aece83eadabc
If authorisation didn't succeed, BlinkPay adds status (cancelled, rejected, timeout or error; the Gateway Flow can also send pending) and error, a message you can show the customer:
https://your-site/callback?cid=c8327a00-3f1a-4d10-a27a-aece83eadabc&status=rejected&error=The+consent+has+been+rejected
There is no success value. Branch on status, never on error, and always confirm the outcome by checking the consent status (Step 5), whether or not status is present. The full table is in Return Parameters.
Request:
GET /v1/consents/{consent_id} HTTP/1.1
Host: sandbox.data.blinkpay.co.nz
Authorization: Bearer {access_token}
Response:
{
"consent_id": "c8327a00-3f1a-4d10-a27a-aece83eadabc",
"status": "Authorised",
"status_update_date_time": "2026-10-07T10:15:30+13:00",
"creation_date_time": "2026-10-07T10:14:02+13:00",
"flow": {
"detail": {
"type": "redirect",
"bank": "PNZ",
"redirect_uri": "https://your-site/callback"
}
},
"permissions": ["ReadAccounts", "ReadBalances", "ReadTransactions"],
"start_date_time": "2025-10-01T00:00:00+13:00",
"end_date_time": "2026-12-31T23:59:59+13:00",
"expiration_date_time": "2026-12-31T23:59:59+13:00",
"approved_requests": []
}
approved_requests lists the data requests made under the consent so far, each with a type (Account, Balance, Transaction, Statement or Party), an id and a creation_date_time. The response also carries hashed_customer_identifier where the consent has one.
Authorised means you can retrieve data. If the status is AwaitingAuthorisation (or GatewayAwaitingSubmission in the Gateway Flow), the customer hasn't finished yet: check again every second until it changes. Every other status is final; create a new consent if the customer wants to try again. See Consent Status for the full list.
Request:
GET /v1/accounts?consent_id={consent_id} HTTP/1.1
Host: sandbox.data.blinkpay.co.nz
Authorization: Bearer {access_token}
Response:
{
"accounts": [
{
"account_id": "eyJhY2NvdW50SWQiOiIxMjM0NTY3ODkwIn0",
"name": "Everyday Account",
"type": "current",
"currency": "NZD",
"details": {
"number": "12-3456-7890123-00",
"name": "Everyday Transactional Account"
}
}
],
"pagination": {
"page": 1,
"size": 500,
"total_pages": 1,
"total_records": 1
}
}
Request:
GET /v1/accounts/{account_id}/balances?consent_id={consent_id} HTTP/1.1
Host: sandbox.data.blinkpay.co.nz
Authorization: Bearer {access_token}
Response:
{
"balances": [
{
"account_id": "eyJhY2NvdW50SWQiOiIxMjM0NTY3ODkwIn0",
"type": "current",
"amount": {
"amount": "1234.56000",
"currency": "NZD"
},
"direction": "in",
"date_time": "2026-10-07T10:00:00+13:00"
},
{
"account_id": "eyJhY2NvdW50SWQiOiIxMjM0NTY3ODkwIn0",
"type": "available",
"amount": {
"amount": "1734.56000",
"currency": "NZD"
},
"direction": "in",
"date_time": "2026-10-07T10:00:00+13:00"
}
],
"pagination": {
"page": 1,
"size": 500,
"total_pages": 1,
"total_records": 2
}
}
Request:
GET /v1/accounts/{account_id}/transactions?consent_id={consent_id}&from_booking_date_time=2026-09-01T00:00:00Z HTTP/1.1
Host: sandbox.data.blinkpay.co.nz
Authorization: Bearer {access_token}
Date filters take a full ISO 8601 date-time with an offset (2026-09-01T00:00:00Z or 2026-09-01T00:00:00+12:00); a date on its own is rejected. The range must sit inside the consent's start_date_time to end_date_time window. Timestamps in responses are in New Zealand time (+12:00 or +13:00).
Response:
{
"transactions": [
{
"transaction_id": "txn-123",
"type": "POS",
"direction": "out",
"amount": {
"amount": "45.50000",
"currency": "NZD"
},
"status": "posted",
"date_time": "2026-09-15T14:23:00+12:00",
"description": "Coffee Shop",
"balance": {
"account_id": "eyJhY2NvdW50SWQiOiIxMjM0NTY3ODkwIn0",
"type": "current",
"amount": {
"amount": "1189.06000",
"currency": "NZD"
},
"direction": "in",
"date_time": "2026-09-15T14:23:00+12:00"
}
}
],
"pagination": {
"page": 1,
"size": 500,
"total_pages": 1,
"total_records": 1
}
}
amount.amount is never signed: direction tells you whether money went in or out. transaction_id is missing at some banks, and type is the bank's own transaction code, so its values differ by bank. See Reading Transactions before you store or categorise transactions.
To fetch new data later, call these endpoints again with the same consent_id; the customer doesn't need to authorise again until the consent expires or is revoked. See Refreshing Data.
Test Bank: PNZ (Payments NZ Mock Bank)
| Flow | Test Credentials |
|---|---|
| Redirect | Username: user01, Password: password |
| Decoupled | Phone: +64-259531933 (auto-approves) |
Any other mobile number is accepted but never authorises: the consent stays AwaitingAuthorisation until the bank's window ends, then becomes Rejected. See Sandbox Test Values for how to produce a decline and test revocation.