डिजिटल वस्तुओं का थोक मंच

B2B Order API में Duplicate-Safe Ordering 2026: Status-Check Pattern

FoxReload API में Idempotency-Key header नहीं है। Duplicate orders से बचने का सही तरीका: retry से पहले GET /api/orders/{id} status check + client-side dedup। Engineer-level guide।

B2B Order API में Duplicate-Safe Ordering 2026: Status-Check Pattern

FoxReload Public API में Idempotency-Key header नहीं है। इसका मतलब यह नहीं कि duplicate orders inevitable हैं — बस pattern अलग है। यह article वह engineering patterns cover करता है जो FoxReload Orders API (POST /api/orders) को retry-safe बनाते हैं।

1. क्यों single retry दो orders बना सकता है

Simple sequence: आपका ERP POST /api/orders issue करता है। FoxReload order create करता है, delivery start करता है, पर TCP response खो जाती है (network blip)। आपका HTTP client 30s के बाद retry करता है — FoxReload नया request देखता है, दूसरा order बनाता है, balance दूसरी बार debit करता है। Result: duplicate।

Idempotency-Key नहीं है — इसलिए server-side dedup नहीं होगा। Solution: retry से पहले status check।

2. Status-Check Before Retry Pattern

async function createOrderSafe(
  payload: OrderPayload,
  clientRef: string  // आपका internal unique reference
): Promise<Order> {

  // Step 1: क्या पहले से ऑर्डर बना? अपने DB में check करें
  const existing = await db.orderAttempts.findByClientRef(clientRef);
  if (existing?.foxreloadOrderId) {
    // FoxReload पर status verify करें
    const order = await foxreloadGet(`/api/orders/${existing.foxreloadOrderId}`);
    return order; // already exists — return करें, duplicate मत बनाओ
  }

  // Step 2: नया order attempt record करें (UNIQUE constraint से concurrent duplicates रुकेंगे)
  await db.orderAttempts.insert({ clientRef, status: 'pending' });

  try {
    const order = await foxreloadPost('/api/orders', payload);
    await db.orderAttempts.update(clientRef, { foxreloadOrderId: order.id, status: 'created' });
    return order;
  } catch (err) {
    if (isNetworkTimeout(err)) {
      // Order बना या नहीं? Recent orders check करें
      const recentOrders = await foxreloadGet('/api/orders/?limit=5');
      const match = recentOrders.find(o => matchesOurPayload(o, payload));
      if (match) {
        await db.orderAttempts.update(clientRef, { foxreloadOrderId: match.id, status: 'created' });
        return match;
      }
    }
    await db.orderAttempts.update(clientRef, { status: 'failed' });
    throw err;
  }
}

clientRef को request issue करने से पहले DB में persist करें। Retry पर वही ref read करें — नई generate नहीं करें।

3. Client-Side Dedup Storage

// DB schema
CREATE TABLE order_attempts (
  client_ref TEXT PRIMARY KEY,           -- आपका unique reference (e.g., UUIDv4)
  foxreload_order_id TEXT,               -- FoxReload का order UUID (populate होने पर)
  status TEXT NOT NULL DEFAULT 'pending', -- pending | created | failed
  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);

Storage backends comparison:

Storage Throughput Latency TTL Cost
Redis (SETNX) 200k/s <1ms Custom $0.40/M
Postgres UNIQUE 30k/s 5–8ms $0.10/M
DynamoDB ConditionExpression 100k/s 8–12ms Custom $1.25/M

ज़्यादातर use cases के लिए Postgres UNIQUE index sufficient है — persistent, audit-friendly।

4. Timeout Recovery Flow

async function handleTimeout(clientRef: string, payload: OrderPayload): Promise<Order | null> {
  // Option A: अगर order_id था तो directly check करें
  const attempt = await db.orderAttempts.findByClientRef(clientRef);
  if (attempt?.foxreloadOrderId) {
    return foxreloadGet(`/api/orders/${attempt.foxreloadOrderId}`);
  }

  // Option B: Recent orders scan
  const orders = await foxreloadGet('/api/orders/?limit=10&statuses=active,paid,processing,completed');
  const match = orders.find(o => createdRecently(o) && matchesAmount(o, payload));

  if (match) {
    // Found — record करें और return करें
    await db.orderAttempts.update(clientRef, { foxreloadOrderId: match.id, status: 'created' });
    return match;
  }

  // Order नहीं बना — safe to retry
  return null;
}

FoxReload API Reference

# Order list (recent orders check)
curl "https://public-api.foxreload.com/api/orders/?statuses=active,paid,processing,completed&limit=10" \
  -H "X-API-Key: YOUR_API_KEY"

# Specific order check
curl "https://public-api.foxreload.com/api/orders/{order_id}" \
  -H "X-API-Key: YOUR_API_KEY"

Summary

FoxReload API में idempotency keys नहीं हैं — यह Stripe-style feature यहाँ exist नहीं करता। Engineering value यह है:

  1. Client-side dedup: हर attempt को unique client_ref के साथ अपने DB में track करें।
  2. Status-check before retry: Timeout पर GET /api/orders/{id} से verify करें — duplicate बनाने से पहले।
  3. Recent order scan: order_id नहीं पता तो GET /api/orders/ list से identify करें।

यह pattern 99%+ duplicate prevention देता है बिना server-side idempotency keys के। Access request करें और production-ready integration बनाएं।

अक्सर पूछे जाने वाले प्रश्न

FoxReload API में idempotency keys क्यों नहीं हैं?
FoxReload Public API में Idempotency-Key header support नहीं है। Duplicate prevention की ज़िम्मेदारी client पर है। Pattern: हर order attempt को अपने DB में unique client reference के साथ track करें; retry से पहले उस reference से existing order check करें।
Network timeout पर order बना या नहीं — कैसे जानें?
दो तरीके: (1) अगर order_id मिला था तो GET /api/orders/{order_id} call करें। (2) अगर order_id नहीं मिला तो GET /api/orders/?limit=5 से recent orders check करें और अपना order identify करें। Confirm होने के बाद ही नया order बनाएं।
GET requests पर dedup चाहिए?
नहीं। GET definition से safe है — repeat करने से कोई side effect नहीं होता। Dedup सिर्फ POST /api/orders पर चाहिए।
Client-side dedup के लिए storage क्या use करें?
Redis SETNX (fast, TTL support) या Postgres UNIQUE index (persistent, unlimited TTL)। हर attempt create करने से पहले unique client_ref insert करें — duplicate insert fail होगा और पता चल जाएगा कि already exists।
FoxReload API एक्सेस पाएं

संबंधित लेख