Idempotency

This page discusses how to implement idempotency in our API to ensure that multiple identical requests produce the same result. By following these guidelines, you can maintain the integrity and consistency of operations, preventing duplicate actions and side effects.


What is Idempotency?

Idempotency ensures that performing the same operation multiple times results in the same outcome, preventing unintended side effects from repeated requests. In the context of APIs, it guarantees that even if a client sends the same request multiple times, the server's state remains consistent, providing reliability and preventing duplicate operations such as repeated charges or redundant data creation.

How Idempotency works in Ascenda?

🚧

Feature in Alpha Development across Endpoints

By end January 2025 you can expect to see an updated list of endpoints supporting this Idempotency Key header in stable version.

For forwards compatibility, you can already incorporate the use of the Idempotency-Keyvalue in your integration.

See the section below for achieving Forwards Compatibility in Idempotency when designing your workflows. (in advance of this Alpha feature)

When you use an Idempotency-Key header, our APIs will do the record keeping required to prevent duplicate operations. Ascenda caches the response of the 1st successful request tied to the Idempotency-Key value sent and returns that response the next time you send a duplicate request.

⚠️ If you do not send in the Idempotency-Key header, then the Idempotent response will not be applied (and a randomly assigned value will be used in lieu)

You can safely retry requests that include an Idempotency-Key header as long as the second request occurs within 24 hours from when you first receive the key (keys expire out of Ascenda's APIs after 24 hours).

For example, if a request to create an object doesn’t respond because of a network connection error, a client can retry the request with the same idempotency key to guarantee that no more than one object is created.

Examples of values you can use for Idempotency-Key value

  • Generates a token with sufficient randomness, such as UUID v4/ v7
  • Use the value off a user/ workflow-attached object, like your shopping cart ID. This is an easy way to protect against duplicate request submissions

Response Codes handled

Ascenda will cache and deal with only HTTP 2XX and 4XX errors that are deterministic in nature.

HTTP Code

What does this mean?

What do you do?

200

OK

Everything worked as expected.

201

Resource Created

Everything worked as expected.

400

Bad Request

Request not accepted, likely due to invalid parameters.

401

Unauthorized

Request not authorized, due to bad credentials or lack of access for the credentials being used.

404

Resource not Found

Request not accepted because it isn't found

409

Resource conflict

Request conflicts with another likely concurrent request.

429

Too many Requests

Rate-limit exceeded. Please check the rate limits assigned to you and retry again after your retry interval limits

500

Unexpected Error

An error on Ascenda's end. This is indeterministic.

See Indeterminate Error handling advisory below on how you should deal with this

502, 503, 504

Unexpected Connection Error

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 on how you should deal with this

Disclaimer: We may not cache the response for concurrent requests with the same Idempotency-Keyvalue. In the event that the requests complete in Ascenda's APIs at the same time then a 409 resource conflict should be expected for the marginally slower request


Workflow Advisory: Retrying Transient Errors (within 24 hours)

If the network connection fails before the client has received a response from the Ascenda endpoint:

You do not know at what point the request failed, so you must regard its status as indeterminate. The request may have completed successfully, may have failed while the server was processing it, or may not have been received by the endpoint.

  • Idempotent Cache maximum: 24 hours
    • Exponential knockback retries maximum recommended (in the 24 hours window): 15 times
      You should retry the request using a retry mechanism that incorporates an exponential backoff schedule and a limit on the number of retries and/or the maximum duration between retries up to 24 hours.

Recommended: Querying our Records to Automate Retry Successes


To minimize unwanted side effects when idempotent requests are duplicated, you can take the following steps with Ascenda's endpoints

  1. Query for Outcomes: Our POST endpoints are typically accompanied by an equivalent GET resource endpoint. These endpoints provide the same API response outcome as when the POST request is made. Our idempotent-supported endpoints glossary below detail the options you have to reconcile transient errors 2. Observe for Outcomes (with Webhooks): Some endpoints like CreateOrder support webhook events as a mechanism for observing changes in the record's status. Refer to the idempotent-supported endpoints glossary for the endpoints with webhooks you can observe for

Workflow Advisory: Handling Indeterminate Errors (HTTP 5XX errors or Retries fail after 24 hours)


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.


Indeterminate HTTP 5XX error handling (with retries)


All POST requests accept idempotency keys. Ascenda's GET and DELETE requests are idempotent by definition.


You can automatically retry these errors in a 5XX scenario

  • GET requests are idempotent by definition
    • DELETE requests are idempotent by definition. Any future duplicate requests already processed in Ascenda will lead to rejection of the requests
      • POST requests for endpoints that do not impact your customer journey can be retried. However in the case of indeterminate HTTP 500 errors we should not retry for critical endpoints that may impact the user's experience/ points balance or cash deductions (See the next section below for detailed information)
        See the above guidelines on retrying transient errors . Note: When maximum retries have been exhausted with no deterministic outcome, please reach out to Ascenda support. Refer to the next section below on gracefully handling indeterminate errors.

Indeterminate HTTP 500 error handling for Critical Endpoints


For the following critical endpoints listed below, you should hold the transactions on your end in a recommended pending status the very first time you observe a HTTP 500 and verify the outcomes with Ascenda support

EndpointDescription
Create orderIn case points or cash has been deducted to the customer or billed to your account, we want to evaluate the situation before proceeding with future retries.
Add/ Subtract pointsIn case points has been deducted / accrued to the customer account or billed to your account, we want to evaluate the situation before proceeding with future retries.

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 to evaluate the issue with us before retrying the transaction.

Ascenda's engineers will evaluate the problem and where the endpoint comes with webhooks subscription (for notifying transaction outcomes) we will try to roll forward on the fixes.

🚧

Treat these requests that return 500 errors as indeterminate and hold them in a pending status. Ascenda tries to reconcile our partial state in the most appropriate manner and also fire webhooks for new objects that are created


We will try to fix and then replay the webhooks to you (on your subscribed webhooks endpoints)

To allow your integration to handle the widest range of 5XXs, configure webhook handlers to receive event objects that you never receive in normal API responses.

It is recommended you have a recovery process in place, either by logging these instances for manual review and reconciliation, or automatically reconciling by pulling the transaction details via a matching GET request and using the reference_id property to utilize any client-side data you attached to the transaction for reference.

For the latest in system issues on the Ascenda network please refer to our Status Page

Retries for Transactions when Ascenda Rolls backwards

In the event that the transaction has not been received or processed by Ascenda's endpoints it may be easier for you to retry the transaction after Ascenda Support has advised this to you

In such cases, to maximise operational flexibility, you should have tooling that allows you to store then retry the transactions here against Ascendas APIs after.

Idempotency in Ascenda APIs

Where applicable, Ascenda ensures that our POST APIs support idempotency in your application. This means that you are able to simplify your error handling - and simply retry the API call without fear that the operation would be executed more than once.

GET and DELETE requests

Ascenda's endpoints for retrieval and deletion of entities are idempotent. You can retry them safely.

We do not observe for Idempotency-Keywhen you're using these endpoints.

Endpoints with Mandatory Idempotent Key checks

The table below documents the expected behaviour for idempotent endpoints. You must provide an Idempotency-Key header.

EndpointDuplicate Error Check?Description
Create orderYesIdempotent outcomes is supported by the GET /orders/:id endpoint

Workflow: Designing for Forwards Compatibility in this feature

📘

Applicable for Ascenda Clients integrating our endpoints before January 2025

This is for Ascenda Clients designing or developing Idempotent request handling pre-January 2025

You will want to inject the Idempotency-Key header in advance and plan in your workflows the handling needed for dealing with transient request failures

Before Idempotency-Key support

Ascenda's endpoints will reject you with a duplicate record if it is already processed. In such a scenario, you should query for the outcome of the transaction.

In advance (of Jan '2025), you can inject in the header first but be ready to handle the duplicate error rejection.


After Idempotency-Key support is enabled

Post January 2025, once the Idempotency Key header support is enabled. As long as you enable retries for the endpoints mentioned above. You will benefit from a consistent response.

This way, as long as you're already sending in an Idempotency-Key value (ahead of January 2025), you'll be forwards compatible to when this feature is enabled