Error Handling

This guide explains the various HTTP status codes and error codes returned by our API and provides guidance on how to handle different types of errors effectively. By understanding these status codes, you can implement robust error handling in your applications, ensuring smooth and reliable interactions with our API.


HTTP Status Codes

Ascenda's API uses standard HTTP response codes:

HTTP Status Code

Description

200 OK

Request is valid and data is returned as expected

201 Created

Request is valid and the resource (e.g. user) has been created successfully on our platform

400 Bad Request

The request parameters are invalid. Please double check the error response for detailed information on the error.

401 Unauthorized

Invalid M2M token provided. Please check the error response for detailed information on the error.

404 Not Found

The requested resource is not found. (e.g. Providing an invalid resource ID in an update request)

409 Conflict

In the context of users API, the status of a user account maybe in process

422 Unprocessable

Processing failed. Repeating the request without modification will fail with the same error. You can raise this issue to Ascenda Support if this leads to an unhandled outcome for your end-user.

429 Too Many Requests

Rate limit hit. Please throttle your requests to Ascenda's platform and retry again.

500 Internal Server Error

An unexpected error has occured on Ascenda's end. These are generally rare and we have robust alerting and monitoring to catch this.

This is indeterministic. See Indeterminate Error handling advisory below on how you should deal with this.

Connection Errors


502 Bad Gateway
503 Service Unavailable 504 Gateway Timeout

An error connecting to Ascenda's endpoint. This is indeterministic. You can retry automatically in the first 24h in the event of a connection error.

However if this is a chronic error, you should pause processing the transaction. See Indeterminate Error handling advisory below.



Error Codes

Along with the standard HTTP status codes, the response includes a list of specific error codes and messages to help you debug errors more easily. The response will be a JSON-encoded string containing an array of one or more errors with three fields: id, code and message. The following is an example:

{
  "errors": [
    {
      "id":"12345678-abcd-0000-0000-000000000000",
      "code": "XXX",
      "message": "description of first error"
    },
    {
      "id":"23456789-abcd-0000-0000-000000000000",
      "code": "YYY",
      "message": "description of second error"
    }
  ]
}

You can find details about possible errors for each endpoint, but here are some examples of error code and possible messages:

Error Code

Possible Error Message/s

NN1002

Route not found

GH1003

Invalid Token

GH1006

Partner User Id must be a string Invalid params Email must be a string

LE0001

DB model error

LE0001

User is already being processed

LE1001

user_id: Multiple points accounts found for the given user id: id, this is currently not supported transaction.user_id: must be a string

LE2001

No account to writeoff for user id: id



Notes and Tips

Tracing Errors using Request IDs

To facilitate tracing of requests, Ascenda's API platform supports accepting a request ID via the request headers. You can set this value (GUID) via the request header X-Request-ID, and we return this value in the response headers, under X-Request-Id. If you need to contact us about a specific request, providing the request identifier will ensure the fastest possible resolution and allow our team to trace the request/response effectively.

The following are examples of setting a hypothetical GUID of 12345678-0000-0000-0000-000000000000 as the value for X-Request-ID:

curl --request GET \
     --url https://api.us.ascenda.com/api/users/id \
     --header 'accept: application/json' \
     --header 'Authorization: Bearer ee6xxxxxxxxxxxxxxx598' \
     --header 'X-Request-ID: 12345678-0000-0000-0000-000000000000'
fetch('https://api.us.ascenda.com/api/users/id', {
  method: 'GET',
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer ee6xxxxxxxxxxxxxxx598',
    'X-Request-ID': '12345678-0000-0000-0000-000000000000'
  }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
import requests

url = "https://api.us.ascenda.com/api/users/id"
headers = {
    'accept': 'application/json',
    'Authorization': 'Bearer ee6xxxxxxxxxxxxxxx598',
    'X-Request-ID': '12345678-0000-0000-0000-000000000000'
}

response = requests.get(url, headers=headers)

if response.status_code == 200:
    data = response.json()
    print(data)
else:
    print(f"Request failed with status code: {response.status_code}")
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class ApiRequest {
    public static void main(String[] args) {
        try {
            String url = "https://api.us.ascenda.com/api/users/id";
            URL obj = new URL(url);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();

            // Setting request method to GET
            con.setRequestMethod("GET");

            // Adding request headers
            con.setRequestProperty("Accept", "application/json");
            con.setRequestProperty("Authorization", "Bearer ee6xxxxxxxxxxxxxxx598");
            con.setRequestProperty("X-Request-ID", "12345678-0000-0000-0000-000000000000");

            int responseCode = con.getResponseCode();
            System.out.println("Response Code : " + responseCode);

            if (responseCode == HttpURLConnection.HTTP_OK) { // success
                BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String inputLine;
                StringBuffer response = new StringBuffer();

                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();

                // Print result
                System.out.println(response.toString());
            } else {
                System.out.println("GET request not worked");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        var client = new HttpClient();
        var request = new HttpRequestMessage(HttpMethod.Get, "https://api.us.ascenda.com/api/users/id");

        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "ee6xxxxxxxxxxxxxxx598");
        request.Headers.Add("X-Request-ID", "12345678-0000-0000-0000-000000000000");

        HttpResponseMessage response = await client.SendAsync(request);

        if (response.IsSuccessStatusCode)
        {
            string responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseBody);
        }
        else
        {
            Console.WriteLine($"Request failed with status code: {response.StatusCode}");
        }
    }
}
<?php
$url = "https://api.us.ascenda.com/api/users/id";

$ch = curl_init($url);

// Set request method to GET
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");

// Set headers
$headers = [
    'Accept: application/json',
    'Authorization: Bearer ee6xxxxxxxxxxxxxxx598',
    'X-Request-ID: 12345678-0000-0000-0000-000000000000'
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

// Return response instead of outputting
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);

if ($response === false) {
    echo 'Curl error: ' . curl_error($ch);
} else {
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if ($httpCode == 200) {
        echo 'Response: ' . $response;
    } else {
        echo 'Request failed with status code: ' . $httpCode;
    }
}

curl_close($ch);
?>
require 'net/http'
require 'uri'
require 'json'

uri = URI('https://api.us.ascenda.com/api/users/id')

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Get.new(uri.request_uri)
request['Accept'] = 'application/json'
request['Authorization'] = 'Bearer ee6xxxxxxxxxxxxxxx598'
request['X-Request-ID'] = '12345678-0000-0000-0000-000000000000'

response = http.request(request)

if response.code.to_i == 200
  puts "Response: #{response.body}"
else
  puts "Request failed with status code: #{response.code}"
end
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func main() {
    url := "https://api.us.ascenda.com/api/users/id"
    
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }

    req.Header.Add("Accept", "application/json")
    req.Header.Add("Authorization", "Bearer ee6xxxxxxxxxxxxxxx598")
    req.Header.Add("X-Request-ID", "12345678-0000-0000-0000-000000000000")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }
    defer resp.Body.Close()

    if resp.StatusCode == http.StatusOK {
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            fmt.Println("Error reading response:", err)
            return
        }
        fmt.Println("Response:", string(body))
    } else {
        fmt.Printf("Request failed with status code: %d\n", resp.StatusCode)
    }
}
import Foundation

let url = URL(string: "https://api.us.ascenda.com/api/users/id")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("Bearer ee6xxxxxxxxxxxxxxx598", forHTTPHeaderField: "Authorization")
request.setValue("12345678-0000-0000-0000-000000000000", forHTTPHeaderField: "X-Request-ID")

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else {
        print("Error: \(error?.localizedDescription ?? "Unknown error")")
        return
    }

    if let httpResponse = response as? HTTPURLResponse {
        if httpResponse.statusCode == 200 {
            let responseString = String(data: data, encoding: .utf8)
            print("Response: \(responseString ?? "No response data")")
        } else {
            print("Request failed with status code: \(httpResponse.statusCode)")
        }
    }
}

task.resume()
import axios from 'axios';

const url = 'https://api.us.ascenda.com/api/users/id';

axios.get(url, {
    headers: {
        'Accept': 'application/json',
        'Authorization': 'Bearer ee6xxxxxxxxxxxxxxx598',
        'X-Request-ID': '12345678-0000-0000-0000-000000000000'
    }
})
.then(response => {
    console.log('Response:', response.data);
})
.catch(error => {
    if (error.response) {
        console.log('Request failed with status code:', error.response.status);
    } else {
        console.log('Error:', error.message);
    }
});
use reqwest::header::{ACCEPT, AUTHORIZATION, HeaderMap, HeaderValue};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let url = "https://api.us.ascenda.com/api/users/id";

    let mut headers = HeaderMap::new();
    headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
    headers.insert(AUTHORIZATION, HeaderValue::from_static("Bearer ee6xxxxxxxxxxxxxxx598"));
    headers.insert("X-Request-ID", HeaderValue::from_static("12345678-0000-0000-0000-000000000000"));

    let client = reqwest::Client::new();
    let response = client.get(url)
        .headers(headers)
        .send()
        .await?;

    if response.status().is_success() {
        let body = response.text().await?;
        println!("Response: {}", body);
    } else {
        println!("Request failed with status code: {}", response.status());
    }

    Ok(())
}

HTTP Response Codes vs Error Codes

Remember that the HTTP response codes are different than the error codes found in the JSON response (shown as XXX and YYY in the example above). If a resource is not found, a standard 404 Not Found code will be returned as the status of the response, but the error code could be NN1002 or some other string that helps us identify the nature of and more details about the request.

HTTP 429 Too Many Requests

This is a response from the servers when rate limits have been reached for a specific defined timeframe. Given that some endpoints do not support bulk updates, for example, this can be a result when a high volume of insert or update operations are attempted. Please reach out to your Ascenda business representative or submit a support ticket.

HTTP 500 Unexpected Server Error

Due to unexpected circumstances, you may rarely encounter a 500 HTTP error when creating a transaction with Ascenda. In such cases, it's highly likely the transaction has been created in our systems but failed with some sort of unexpected partial failure downstream internally.

In cases of retries under 24 hours, you may be able to recover the transaction if Ascenda fixes the issue ahead of time. If retries fail after 24 hours, you should hold onto the transaction in a pending status and reach out to Ascenda Support through a support ticket to evaluate the issue with us before retrying the transaction.

Please refer to our workflow advisory here on handling indeterminate errors with Ascenda.