OneBasket

Asynchronous operations

How to handle requests that return a notification id, and how to poll for their result.

Some requests cannot finish immediately, because OneBasket has to call a provider system to complete them. Adding a product to a basket is an example. OneBasket has to add the product to the basket in the provider's system and wait for the provider to respond.

These requests return straight away with a notificationId:

{ "notificationId": "..." }

You then poll the Notifications API with that id to learn the outcome.

Notification status

GET /notifications/{notificationId} returns a notification:

{
  "status": "complete",
  "payload": { }
}
statusMeaningWhat to do
pendingThe request is still being processed.Wait, then poll again.
completeThe request succeeded. payload holds the result, if the operation has one.Read the updated resource, for example Get a basket.
failedThe request did not succeed. payload describes the failure, if details are available.Show an error to the customer. Read the resource again before you retry.

Which requests are asynchronous

An endpoint is asynchronous when its response schema in the API reference is NotificationResponse or AcceptedNotificationResponse.

In the Baskets API, every request that changes a basket is asynchronous. Only Create a basket, Get a basket and Delete a basket return the basket directly.

EndpointResponse
Add a product to a basket200 with a notification id
Select seats200 with a notification id
Select time slot200 with a notification id
Update a line item200 with a notification id
Update line item quantity200 with a notification id
Delete line item200 with a notification id
Set delivery method200 with a notification id
Assign contact200 with a notification id
Add voucher and Remove voucher200 with a notification id, or 204 when no processing was needed
Set customer details202 with a notification id, or 204 when no processing was needed
Create a payment intent200 with the payment intent, or 202 with a notification id
Cancel a payment intent200 with a notification id

Check the status code of each response, because some endpoints have both a synchronous and an asynchronous response.

Polling example

wait-for-notification.ts
type Notification = {
  status: 'pending' | 'complete' | 'failed';
  payload?: Record<string, unknown>;
};

export async function waitForNotification(
  notificationId: string,
  { intervalMs = 500, timeoutMs = 30_000 } = {},
): Promise<Notification> {
  const deadline = Date.now() + timeoutMs;

  while (Date.now() < deadline) {
    const response = await fetch(
      `${process.env.ONEBASKET_API_URL}/notifications/${notificationId}`,
      { headers: { 'x-api-key': process.env.ONEBASKET_API_KEY! } },
    );
    if (!response.ok) throw new Error(`Notification request failed: ${response.status}`);

    const notification = (await response.json()) as Notification;
    if (notification.status !== 'pending') return notification;

    await new Promise((resolve) => setTimeout(resolve, intervalMs));
  }

  throw new Error(`Notification ${notificationId} was still pending after ${timeoutMs} ms`);
}

Recommendations:

  • Poll no more often than twice per second.
  • Always set a timeout, and show the customer a retry option when it is reached.
  • Disable the control that started the request until the notification is no longer pending. This stops the customer from sending the same change twice.

On this page