Account Information
Integrate providers, account access, authorization, and risk reports.
Goal: Obtain customer consent for read access to their bank data, then optionally generate a risk report.
Estimated time: 30 minutes
Prerequisites
- Sandbox credentials (
appId,apiKey, tenantUAE) - An AIS subscription enabled on your Spare account (see Coverage)
Concept first
Read Account Information for the providers β account access β authorize β report model before integrating.
Account Information in the UAE follows a core path: list providers, create account access, complete bank authorization, then optionally generate a risk report. All calls use Authorization: Bearer and x-tenant: UAE.
Authenticate
Exchange your API credentials for a Bearer access token. See Quick Start Setup or the Authentication reference.
curl -X POST https://api.sandbox.tryspare.ae/auth/api-keys/sessions \
-H "x-tenant: UAE" \
-H "app-id: $SPARE_APP_ID" \
-H "x-api-key: $SPARE_API_KEY"const response = await fetch("https://api.sandbox.tryspare.ae/auth/api-keys/sessions", {
method: "POST",
headers: {
"x-tenant": "UAE",
"app-id": process.env.SPARE_APP_ID!,
"x-api-key": process.env.SPARE_API_KEY!,
},
});
const { data } = await response.json();
const accessToken = data.accessToken as string;import os
import requests
response = requests.post(
"https://api.sandbox.tryspare.ae/auth/api-keys/sessions",
headers={
"x-tenant": "UAE",
"app-id": os.environ["SPARE_APP_ID"],
"x-api-key": os.environ["SPARE_API_KEY"],
},
)
response.raise_for_status()
access_token = response.json()["data"]["accessToken"]var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.tryspare.ae/auth/api-keys/sessions"))
.header("x-tenant", "UAE")
.header("app-id", System.getenv("SPARE_APP_ID"))
.header("x-api-key", System.getenv("SPARE_API_KEY"))
.POST(HttpRequest.BodyPublishers.noBody())
.build();
var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.sandbox.tryspare.ae/auth/api-keys/sessions");
request.Headers.Add("x-tenant", "UAE");
request.Headers.Add("app-id", Environment.GetEnvironmentVariable("SPARE_APP_ID"));
request.Headers.Add("x-api-key", Environment.GetEnvironmentVariable("SPARE_API_KEY"));
var response = await client.SendAsync(request);req, _ := http.NewRequest(http.MethodPost,
"https://api.sandbox.tryspare.ae/auth/api-keys/sessions", nil)
req.Header.Set("x-tenant", "UAE")
req.Header.Set("app-id", os.Getenv("SPARE_APP_ID"))
req.Header.Set("x-api-key", os.Getenv("SPARE_API_KEY"))
resp, err := http.DefaultClient.Do(req)List providers
List live banks for the UAE. Use a returned id as providerId in the next step.
curl "https://api.sandbox.tryspare.ae/providers?countryCode=AE" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-tenant: UAE"const response = await fetch(
"https://api.sandbox.tryspare.ae/providers?countryCode=AE",
{
headers: {
Authorization: `Bearer ${accessToken}`,
"x-tenant": "UAE",
},
},
);
const { data: providers } = await response.json();response = requests.get(
"https://api.sandbox.tryspare.ae/providers",
params={"countryCode": "AE"},
headers={
"Authorization": f"Bearer {access_token}",
"x-tenant": "UAE",
},
)
response.raise_for_status()
providers = response.json()["data"]var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.tryspare.ae/providers?countryCode=AE"))
.header("Authorization", "Bearer " + accessToken)
.header("x-tenant", "UAE")
.GET()
.build();using var request = new HttpRequestMessage(
HttpMethod.Get,
"https://api.sandbox.tryspare.ae/providers?countryCode=AE");
request.Headers.Add("Authorization", $"Bearer {accessToken}");
request.Headers.Add("x-tenant", "UAE");req, _ := http.NewRequest(
http.MethodGet,
"https://api.sandbox.tryspare.ae/providers?countryCode=AE",
nil,
)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("x-tenant", "UAE")
resp, err := http.DefaultClient.Do(req)See Providers.
Create account access
Create the account-information request and consent in one call. Store referenceCustomerId and the returned consentId for later steps. Redirect the customer to the authorizationLink returned in the response.
consentExpiryDate,consentTransactionsFromDate,consentTransactionsToDate,successRedirectUrlandfailureRedirectUrlare optional.- When you omit
consentExpiryDate, Spare sets expiry to one week from today's date.
curl -X POST https://api.sandbox.tryspare.ae/data/account-access \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-tenant: UAE" \
-H "Content-Type: application/json" \
-d '{
"referenceCustomerId": "merchant-cust-1",
"customerEmail": "customer@example.com",
"providerId": "00000000-0000-0000-0000-000000000001",
"requestedPermissions": [
"ReadAccountsBasic",
"ReadAccountsDetail",
"ReadBalances",
"ReadTransactionsBasic",
"ReadTransactionsDetail"
],
"consentExpiryDate": "2026-12-31T23:59:59.000Z",
"consentTransactionsFromDate": "2026-01-01T00:00:00.000Z",
"consentTransactionsToDate": "2026-12-31T23:59:59.000Z",
"successRedirectUrl": "https://example.com/ais/success",
"failureRedirectUrl": "https://example.com/ais/failure"
}'const response = await fetch("https://api.sandbox.tryspare.ae/data/account-access", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"x-tenant": "UAE",
"Content-Type": "application/json",
},
body: JSON.stringify({
referenceCustomerId: "merchant-cust-1",
customerEmail: "customer@example.com",
providerId: "00000000-0000-0000-0000-000000000001",
requestedPermissions: [
"ReadAccountsBasic",
"ReadAccountsDetail",
"ReadBalances",
"ReadTransactionsBasic",
"ReadTransactionsDetail",
],
consentExpiryDate: "2026-12-31T23:59:59.000Z",
consentTransactionsFromDate: "2026-01-01T00:00:00.000Z",
consentTransactionsToDate: "2026-12-31T23:59:59.000Z",
successRedirectUrl: "https://example.com/ais/success",
failureRedirectUrl: "https://example.com/ais/failure",
}),
});
const { data: accountAccess } = await response.json();response = requests.post(
"https://api.sandbox.tryspare.ae/data/account-access",
headers={
"Authorization": f"Bearer {access_token}",
"x-tenant": "UAE",
},
json={
"referenceCustomerId": "merchant-cust-1",
"customerEmail": "customer@example.com",
"providerId": "00000000-0000-0000-0000-000000000001",
"requestedPermissions": [
"ReadAccountsBasic",
"ReadAccountsDetail",
"ReadBalances",
"ReadTransactionsBasic",
"ReadTransactionsDetail",
],
"consentExpiryDate": "2026-12-31T23:59:59.000Z",
"consentTransactionsFromDate": "2026-01-01T00:00:00.000Z",
"consentTransactionsToDate": "2026-12-31T23:59:59.000Z",
"successRedirectUrl": "https://example.com/ais/success",
"failureRedirectUrl": "https://example.com/ais/failure",
},
)
response.raise_for_status()
account_access = response.json()["data"]var body = """
{"referenceCustomerId":"merchant-cust-1","customerEmail":"customer@example.com",
"providerId":"00000000-0000-0000-0000-000000000001",
"requestedPermissions":["ReadAccountsBasic","ReadAccountsDetail","ReadBalances","ReadTransactionsBasic","ReadTransactionsDetail"],
"consentExpiryDate":"2026-12-31T23:59:59.000Z",
"consentTransactionsFromDate":"2026-01-01T00:00:00.000Z","consentTransactionsToDate":"2026-12-31T23:59:59.000Z",
"successRedirectUrl":"https://example.com/ais/success","failureRedirectUrl":"https://example.com/ais/failure"}
""";
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.tryspare.ae/data/account-access"))
.header("Authorization", "Bearer " + accessToken)
.header("x-tenant", "UAE")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();var payload = new {
referenceCustomerId = "merchant-cust-1",
customerEmail = "customer@example.com",
providerId = "00000000-0000-0000-0000-000000000001",
requestedPermissions = new[] {
"ReadAccountsBasic", "ReadAccountsDetail", "ReadBalances",
"ReadTransactionsBasic", "ReadTransactionsDetail",
},
consentExpiryDate = "2026-12-31T23:59:59.000Z",
consentTransactionsFromDate = "2026-01-01T00:00:00.000Z",
consentTransactionsToDate = "2026-12-31T23:59:59.000Z",
successRedirectUrl = "https://example.com/ais/success",
failureRedirectUrl = "https://example.com/ais/failure",
};
using var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.sandbox.tryspare.ae/data/account-access");
request.Headers.Add("Authorization", $"Bearer {accessToken}");
request.Headers.Add("x-tenant", "UAE");
request.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");body := strings.NewReader(`{"referenceCustomerId":"merchant-cust-1","customerEmail":"customer@example.com",
"providerId":"00000000-0000-0000-0000-000000000001",
"requestedPermissions":["ReadAccountsBasic","ReadAccountsDetail","ReadBalances","ReadTransactionsBasic","ReadTransactionsDetail"],
"consentExpiryDate":"2026-12-31T23:59:59.000Z",
"consentTransactionsFromDate":"2026-01-01T00:00:00.000Z","consentTransactionsToDate":"2026-12-31T23:59:59.000Z",
"successRedirectUrl":"https://example.com/ais/success","failureRedirectUrl":"https://example.com/ais/failure"}`)
req, _ := http.NewRequest(http.MethodPost, "https://api.sandbox.tryspare.ae/data/account-access", body)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("x-tenant", "UAE")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)Complete authorization
Send the customer to the authorizationLink returned on Create Account Access. After they approve access at their bank, Spare completes the bank callback.
Wait until the customer reaches successRedirectUrl before creating a risk report. If you omitted successRedirectUrl, poll GET /consent/account/:consentId until the consent is authorized. consentId is on the Create Account Access response.
See Authorization and Create Account Access.
Generate a risk report
A risk report turns authorized account data into a scored assessment you can review in your app or share as a PDF. Use it when you need a structured view of a customer's financial profile after they approve access. The flow has four parts: create the report, wait until it is ready, read the results, and optionally download a PDF copy.
5.1 Create a risk report
Ask Spare to build a report for the same referenceCustomerId you sent on Create Account Access. You receive a reportId to track progress. Pass consentIds from the Create Account Access consentId to limit the report to that consent.
curl -X POST https://api.sandbox.tryspare.ae/report/risk-reports \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-tenant: UAE" \
-H "Content-Type: application/json" \
-d '{
"referenceCustomerId": "merchant-cust-1",
"consentIds": ["$CONSENT_ID"]
}'const createResponse = await fetch("https://api.sandbox.tryspare.ae/report/risk-reports", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"x-tenant": "UAE",
"Content-Type": "application/json",
},
body: JSON.stringify({
referenceCustomerId: "merchant-cust-1",
consentIds: [accountAccess.consentId],
}),
});
const { data: reportJob } = await createResponse.json();
const reportId = reportJob.reportId as string;response = requests.post(
"https://api.sandbox.tryspare.ae/report/risk-reports",
headers={"Authorization": f"Bearer {access_token}", "x-tenant": "UAE"},
json={
"referenceCustomerId": "merchant-cust-1",
"consentIds": [account_access["consentId"]],
},
)
response.raise_for_status()
report_id = response.json()["data"]["reportId"]var body = String.format("{\"referenceCustomerId\":\"merchant-cust-1\",\"consentIds\":[\"%s\"]}", accountAccessConsentId);
var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.tryspare.ae/report/risk-reports"))
.header("Authorization", "Bearer " + accessToken)
.header("x-tenant", "UAE")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();var payload = new { referenceCustomerId = "merchant-cust-1", consentIds = new[] { accountAccessConsentId } };
using var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.sandbox.tryspare.ae/report/risk-reports");
request.Headers.Add("Authorization", $"Bearer {accessToken}");
request.Headers.Add("x-tenant", "UAE");
request.Content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json");body := strings.NewReader(fmt.Sprintf(`{"referenceCustomerId":"merchant-cust-1","consentIds":["%s"]}`, accountAccessConsentId))
req, _ := http.NewRequest(http.MethodPost, "https://api.sandbox.tryspare.ae/report/risk-reports", body)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("x-tenant", "UAE")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)5.2 Poll the risk report status
Report generation runs asynchronously. Poll this endpoint until the status shows the report is ready, or until it fails so you can retry.
curl -X GET "https://api.sandbox.tryspare.ae/report/risk-reports/YOUR_REPORT_ID/status" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-tenant: UAE"const statusResponse = await fetch(
`https://api.sandbox.tryspare.ae/report/risk-reports/${reportId}/status`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"x-tenant": "UAE",
},
},
);
const { data: reportStatus } = await statusResponse.json();response = requests.get(
f"https://api.sandbox.tryspare.ae/report/risk-reports/{report_id}/status",
headers={"Authorization": f"Bearer {access_token}", "x-tenant": "UAE"},
)
response.raise_for_status()
report_status = response.json()["data"]var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.tryspare.ae/report/risk-reports/" + reportId + "/status"))
.header("Authorization", "Bearer " + accessToken)
.header("x-tenant", "UAE")
.GET()
.build();using var request = new HttpRequestMessage(
HttpMethod.Get,
$"https://api.sandbox.tryspare.ae/report/risk-reports/{reportId}/status");
request.Headers.Add("Authorization", $"Bearer {accessToken}");
request.Headers.Add("x-tenant", "UAE");
var response = await client.SendAsync(request);req, _ := http.NewRequest(
http.MethodGet,
"https://api.sandbox.tryspare.ae/report/risk-reports/"+reportId+"/status",
nil,
)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("x-tenant", "UAE")
resp, err := http.DefaultClient.Do(req)5.3 Get a risk report
When the report is ready, fetch the full scored result (affordability signals, account summaries, and related fields) as JSON for display in your application.
curl -X GET "https://api.sandbox.tryspare.ae/report/risk-reports/YOUR_REPORT_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-tenant: UAE"const reportResponse = await fetch(
`https://api.sandbox.tryspare.ae/report/risk-reports/${reportId}`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"x-tenant": "UAE",
},
},
);
const { data: report } = await reportResponse.json();response = requests.get(
f"https://api.sandbox.tryspare.ae/report/risk-reports/{report_id}",
headers={"Authorization": f"Bearer {access_token}", "x-tenant": "UAE"},
)
response.raise_for_status()
report = response.json()["data"]var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.tryspare.ae/report/risk-reports/" + reportId))
.header("Authorization", "Bearer " + accessToken)
.header("x-tenant", "UAE")
.GET()
.build();using var request = new HttpRequestMessage(
HttpMethod.Get,
$"https://api.sandbox.tryspare.ae/report/risk-reports/{reportId}");
request.Headers.Add("Authorization", $"Bearer {accessToken}");
request.Headers.Add("x-tenant", "UAE");
var response = await client.SendAsync(request);req, _ := http.NewRequest(
http.MethodGet,
"https://api.sandbox.tryspare.ae/report/risk-reports/"+reportId,
nil,
)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("x-tenant", "UAE")
resp, err := http.DefaultClient.Do(req)5.4 Export a risk report to PDF
Download a PDF copy of the report for archival, email, or offline review. The response is a file attachment, not JSON.
curl -X GET "https://api.sandbox.tryspare.ae/report/risk-reports/YOUR_REPORT_ID/export" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-tenant: UAE" \
-o risk-report.pdfconst pdfResponse = await fetch(
`https://api.sandbox.tryspare.ae/report/risk-reports/${reportId}/export`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"x-tenant": "UAE",
},
},
);
const pdfBuffer = await pdfResponse.arrayBuffer();response = requests.get(
f"https://api.sandbox.tryspare.ae/report/risk-reports/{report_id}/export",
headers={"Authorization": f"Bearer {access_token}", "x-tenant": "UAE"},
)
response.raise_for_status()
with open("risk-report.pdf", "wb") as pdf_file:
pdf_file.write(response.content)var request = HttpRequest.newBuilder()
.uri(URI.create("https://api.sandbox.tryspare.ae/report/risk-reports/" + reportId + "/export"))
.header("Authorization", "Bearer " + accessToken)
.header("x-tenant", "UAE")
.GET()
.build();
var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofByteArray());
Files.write(Path.of("risk-report.pdf"), response.body());using var request = new HttpRequestMessage(
HttpMethod.Get,
$"https://api.sandbox.tryspare.ae/report/risk-reports/{reportId}/export");
request.Headers.Add("Authorization", $"Bearer {accessToken}");
request.Headers.Add("x-tenant", "UAE");
var response = await client.SendAsync(request);
await File.WriteAllBytesAsync("risk-report.pdf", await response.Content.ReadAsByteArrayAsync());req, _ := http.NewRequest(
http.MethodGet,
"https://api.sandbox.tryspare.ae/report/risk-reports/"+reportId+"/export",
nil,
)
req.Header.Set("Authorization", "Bearer "+accessToken)
req.Header.Set("x-tenant", "UAE")
resp, err := http.DefaultClient.Do(req)
// read resp.Body and write to risk-report.pdfSee Risk Reports and the Risk Report guide page.
Key takeaways
- The UAE AIS flow is list providers β create account access β authorize β risk report.
- Every call requires
Authorization: Bearerandx-tenant: UAE. - Account Information endpoints integrate over REST today; official SDK coverage for AIS is planned after the SDK review completes.