B2B platform for digital goods

Multi-Source Fulfilment Routing 2026: Order Routing Across Suppliers

Production multi-source routing algorithms: latency-weighted, stock-aware, cost-optimised, and failover for B2B fulfilment.

Multi-Source Fulfilment Routing 2026: Order Routing Across Suppliers

Production B2B digital-goods fulfilment cannot depend on a single supplier. An exclusive supplier is a single point of failure: one outage and every order fails. The correct architectural pattern is multi-source routing with automatic selection of the best option per request.

This guide covers routing logic in your own system. When FoxReload is one of your suppliers, you call POST /api/orders after your routing layer selects it. Retrieve results by polling GET /api/orders/{order_id} — FoxReload does not push webhook callbacks, so design your routing layer to poll for completion.

1. Latency-weighted routing

The simplest variant is to pick the supplier with the lowest p95 delivery latency. Store historical metrics in a Redis sliding window:

type SupplierStats = { p95Ms: number; failureRate: number; stock: number };

async function pickSupplier(productId: string): Promise<string> {
  const candidates = await getSuppliersForProduct(productId);
  const stats = await Promise.all(
    candidates.map(s => redis.hgetall(`sup:${s.id}:stats`))
  );
  const scored = candidates.map((s, i) => ({
    id: s.id,
    score: 1 / (parseFloat(stats[i].p95Ms) + 1),
  }));
  return scored.sort((a, b) => b.score - a.score)[0].id;
}

This covers 80% of scenarios. Latency metrics refresh every 30 seconds from real order completion times recorded in your tracking layer.

2. Stock-aware routing

If a supplier's inventory is below buffer (e.g., <50 codes for a popular product), avoid using it as primary even with good latency. The stock buffer prevents the race condition "4 concurrent orders for 3 codes".

function isViableSupplier(s: SupplierStats, qty: number): boolean {
  const buffer = Math.max(50, qty * 3); // 3x safety margin
  return s.stock >= buffer && s.failureRate < 0.05;
}

For FoxReload specifically, check GET /api/products/{id_or_slug} to verify the product is still listed and active before routing orders there.

3. Cost-optimised routing

If SLA allows (e.g., fulfilment within 5 minutes is normal for B2B), optimise on wholesale cost. Formula:

score = (1 / wholesale_cost) * sla_multiplier
where sla_multiplier = 1 if p95 < target else 0

This gives a hard SLA guarantee plus minimum cost. At scale (>10k orders/day) it saves 1.5–3% on marginal cost.

4. Failover and circuit breaker

Health-check pattern:

Signal Threshold Action
5xx rate over 5 min >5% Mark DEGRADED
Timeout rate >2% Mark DEGRADED
Heartbeat fail 3 in a row Mark DOWN
Recovery 5 successful Mark HEALTHY

Circuit breaker pattern (Polly/resilience4j-style):

import CircuitBreaker from 'opossum';

const breaker = new CircuitBreaker(callSupplier, {
  timeout: 8000,
  errorThresholdPercentage: 50,
  resetTimeout: 120000, // 2 min
});

breaker.fallback(() => fallbackSupplier());

In open state 100% of traffic moves to fallback — 2-minute cooldown, then a half-open canary check, then recovery.

5. Polling after order placement

When FoxReload is the selected supplier, after calling POST /api/orders your routing layer must poll for completion:

async function placeAndWait(items: OrderItem[], apiKey: string): Promise<string[]> {
  const res = await fetch('https://public-api.foxreload.com/api/orders', {
    method: 'POST',
    headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
    body: JSON.stringify({ items }),
  });
  const order = await res.json();

  // Poll until terminal state
  let delay = 5_000;
  while (true) {
    await sleep(delay);
    const statusRes = await fetch(
      `https://public-api.foxreload.com/api/orders/${order.id}`,
      { headers: { 'X-API-Key': apiKey } },
    );
    const latest = await statusRes.json();
    if (latest.status === 'completed') {
      return latest.items.flatMap((i: any) => i.externalData ?? []);
    }
    if (['cancelled', 'failed'].includes(latest.status)) {
      throw new Error(`Order ${order.id} ended with status ${latest.status}`);
    }
    delay = Math.min(delay * 1.5, 30_000);
  }
}

CTA

FoxReload provides a single REST API with a large product catalog. Get access and plug it into your multi-source routing layer.

Frequently asked questions

What routing algorithm should I use by default?
A weighted score works well: 50% current stock availability, 30% p95 latency, 20% wholesale cost. Suppliers with >5% failure rate over 15 minutes should be removed from the pool automatically.
What happens if the primary supplier goes down?
Health checks run every 10 seconds (heartbeat + sample order). After 3 consecutive failures the supplier is flagged DEGRADED and traffic shifts to secondary. Recovery requires 5 consecutive successful checks.
Can I pin a product to a specific supplier?
In a multi-supplier architecture, yes — implement a routing policy in your own layer that maps product IDs to preferred suppliers. Useful for exclusive contracts or regional compliance requirements.
How does multi-source affect end-customer latency?
It adds 80–120ms for the routing decision (internal lookup) but reduces p99 delivery by 40–60% thanks to failover. Without multi-source p99 = 90s; with multi-source p99 = 38s.
Get FoxReload API access

Related articles