TPP · Banking · ATMs

ATMs — API Guide 2 min read

The ATM API exposes a single endpoint — GET/atms — that returns the details of all ATMs managed by the LFI.

01 Prerequisites

What you need before calling the ATM API

Before calling the ATM API, ensure the following requirements are met:

  • Registered Application — the application must be created within the Trust Framework and assigned the BDSP role as defined in Roles.
  • Valid Transport Certificate — an active transport certificate must be issued and registered in the Trust Framework to establish secure mTLS communication with the LFI.
  • Valid Signing Certificate — an active signing certificate must be issued and registered in the Trust Framework for client authentication.
  • Understanding of Tokens & Assertions — you should understand how client authentication works with private_key_jwt before calling the token endpoint.
02 API Sequence Flow

End-to-end ATM request

Sequence diagramATM API FlowClick to expand
03 Step 1 — Build a Client Assertion

Prove your application's identity

The ATM API uses the OAuth 2.0 client credentials grant with scope=atm.

Use the signJWT() helper to build a client assertion proving your application's identity:

typescript
import crypto from 'node:crypto'
import { signJWT } from './sign-jwt'

const CLIENT_ID = process.env.CLIENT_ID!
const ISSUER    = process.env.LFI_ISSUER!   // from the LFI's .well-known/openid-configuration

const clientAssertion = await signJWT({
  iss: CLIENT_ID,
  sub: CLIENT_ID,
  aud: ISSUER,
  jti: crypto.randomUUID(),
})

See Client Assertion for the full claims reference.

04 Step 2 — Token Request

Exchange the assertion for an access token

POST to the LFI's token endpoint with scope=atm:

typescript
const TOKEN_ENDPOINT = process.env.LFI_TOKEN_ENDPOINT!

const params = new URLSearchParams({
  grant_type:            'client_credentials',
  scope:                 'atm',
  client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
  client_assertion:      clientAssertion,
})

const tokenResponse = await fetch(TOKEN_ENDPOINT, {
  method:  'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body:    params.toString(),
  // agent: new https.Agent({ cert: transportCert, key: transportKey }),
})

const { access_token } = await tokenResponse.json()
05 Step 3 — GET /atms

Retrieve the ATM directory

GET/atms

Call the endpoint with the access token. Include x-fapi-interaction-id on every request. See Request Headers.

x-fapi-customer-ip-address is not required for ATMs — the data is static and public, so no customer is involved in the call.

LFI_API_BASE is the LFI's API Hub resource server — https://rs1.<lfiCode>.apihub.openfinance.ae (production) or https://rs1.<lfiCode>.sandbox.apihub.openfinance.ae (sandbox). Resolve the <lfiCode> from the Trust Framework Directory. See API Resources for the full endpoint format.

typescript
import crypto from 'node:crypto'

const API_BASE = process.env.LFI_API_BASE!

const response = await fetch(`${API_BASE}/open-finance/atm/v2.1/atms`, {
  method: 'GET',
  headers: {
    'Authorization':         `Bearer ${access_token}`,
    'x-fapi-interaction-id': crypto.randomUUID(),
  },
  // agent: new https.Agent({ cert: transportCert, key: transportKey }),
})

const { Data, Meta } = await response.json()
// Data — array of ATM records
// Meta.TotalRecords — total count
// Meta.LastUpdatedDateTime — when the data was last refreshed

Response structure

response bodyjson
{
  "Data": [
    {
      "ATMId": "ATM-001",
      "LFIId": "ADCB",
      "LFIBrandId": "ADCB",
      "SupportedCurrencies": ["AED"],
      "SupportedLanguages": ["en", "ar"],
      "Services": ["CashWithdrawal", "Balance", "MiniStatement", "PINChange"],
      "Accessibility": ["WheelchairAccess", "AudioCashMachine"],
      "IsAccess24Hour": true,
      "Availability": {
        "Status": "Available"
      },
      "MinimumPossibleAmount": { "Amount": "20.00", "Currency": "AED" },
      "MaximumPossibleAmount": { "Amount": "5000.00", "Currency": "AED" },
      "Location": {
        "LocationCategory": ["BranchExternal"],
        "PostalAddress": {
          "StreetName": "Corniche Road",
          "TownName": "Abu Dhabi",
          "CountrySubDivision": "AbuDhabi",
          "Country": "AE"
        },
        "GeoLocation": {
          "Latitude": "24.4539",
          "Longitude": "54.3773"
        }
      }
    }
  ],
  "Meta": {
    "TotalRecords": 1,
    "LastUpdatedDateTime": "2025-03-21T08:00:00Z"
  }
}

See the GET /atms API reference for the full response schema.