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.
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_jwtbefore calling the token endpoint.
End-to-end ATM request
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:
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.
Exchange the assertion for an access token
POST to the LFI's token endpoint with scope=atm:
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()
Retrieve the ATM directory
/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.
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
{
"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.
