An order is ready at a pharmacy in Wuse 2, Abuja. The customer opens your app to check on delivery. Your backend has created a Relay task, but no rider accepts the offer. If your screen still says “finding a rider,” the customer has no idea what is happening, and your operations team has no clear next step.
What you'll build
You'll handle the no-rider branch: store the task ID, observe its terminal state, and show a customer message that your app can actually support. Start by rehearsing it with a test key:
import { RelayClient } from '@relay-sdk/sdk-node';
const relay = new RelayClient({ apiKey: process.env.RELAY_API_KEY! }); // sk_test_... only
const { task } = await relay.tasks.create({
taskType: 'PACKAGE_DELIVERY',
autoAssign: true,
simulationOutcome: 'NO_RIDERS',
stages: [
{
type: 'PICKUP',
location: { latitude: 9.0579, longitude: 7.4951, address: 'Demo pickup, Wuse 2, Abuja' },
instructions: 'Simulation only',
items: [{ name: 'Demo parcel', estimatedValue: 100000,
estimatedWeight: 'LIGHT', estimatedSize: 'BOX' }],
},
{
type: 'DROPOFF',
location: { latitude: 9.0765, longitude: 7.3986, address: 'Demo dropoff, Abuja' },
instructions: 'Simulation only',
items: [],
},
],
});
// Persist task.id with your order. Later, reconcile from Relay:
const latest = await relay.tasks.get(task.id);
console.log(latest.task.status, latest.task.failureReason);
The addresses and coordinates are demonstration inputs. estimatedValue is the parcel's value in kobo, not the delivery fee. NO_RIDERS works with sk_test_... keys; test mode simulates the lifecycle and does not dispatch a real rider or move real money. Follow the Node SDK guide and simulation outcomes for setup.
What happens when nobody accepts?
In the live auto-assignment path, Relay looks for eligible nearby riders in configured offer tiers. A tier can find no eligible riders, receive no deliverable offers, or reach its decision deadline without an accepted assignment. The workflow checks for an assignment before ending the search. If none remains, it marks the task FAILED with reason NO_RIDERS_AVAILABLE and emits a task-failed event.
That distinction matters in your app. OFFERED is still in progress; FAILED is terminal. Don't promise a rider while an offer is pending, and don't keep showing a spinner after the failure. A webhook can synchronize your backend; GET /tasks/{taskId} lets you reconcile state when a webhook is delayed or your service restarts. Relay also supports WebSocket updates for a connected UI. See the task lifecycle and webhook guide.
Give the customer and your team a useful next step
Back in Wuse 2, your customer should see a plain status such as: “We couldn't find a rider for this delivery. We're checking another option.” That wording is your product choice, not an automatic Relay message. Your operations view should show the failed task and its reason so a person can decide whether to adjust the order, contact the customer, or create a new task. Do not silently treat the failed task as delivered.
If you retry from your backend, use the documented task-creation idempotency behavior to avoid duplicate task creation from network retries. A new dispatch attempt is a product decision: review the current task state and your payment flow first. Relay's live failure path refunds a wallet-funded task and attempts to void a card preauthorization before publishing failure; your UI should still use the task and payment records as its source of truth rather than promising an instant bank refund.
Rehearse the failure branch
-
Get a test API key and create a task with
simulationOutcome: 'NO_RIDERS'. - Save the returned
task.idagainst your order. - Listen for the task-failed webhook and verify its signature; keep the handler idempotent.
- Retrieve the task by ID to reconcile the final status. Check
FAILEDand the failure reason before updating your order and customer UI. - Repeat with
TIER_3_TIMEOUTto exercise the full timeout path. The simulation matrix lists the expected outcomes.
When your test task fails, check the customer screen and operations view together. Both should reflect the same failed task before anyone decides what to do with the order. Create a Relay account and get API keys, then use the task creation guide to run the scenario.

Top comments (0)