સેલર્સ માટેબીટા

ઓર્ડર API અને વેબહૂક

તમારી પોતાની વેબસાઇટ કે ERP માંથી ઓર્ડર Production Floor પર મોકલો, અને લાઇનો મેપ થાય, જૉબ આગળ વધે અને ઓર્ડર શિપ થાય ત્યારે સાઇન કરેલા વેબહૂક મેળવો.

જો તમારા ઓર્ડર Shopify કે WooCommerce ને બદલે તમારી પોતાની વેબસાઇટ કે ERP માં હોય, તો તમારું સૉફ્ટવેર તેમને સીધા તમારા Production Floor પર મોકલી શકે છે, અને કામ આગળ વધે તેમ Yantra Bhavan તમારા સૉફ્ટવેરને પાછી જાણ કરી શકે છે: જ્યારે કોઈ લાઇન મેપ થાય, જ્યારે કોઈ જૉબની સ્થિતિ બદલાય અને જ્યારે તે શિપ થાય.

ઓર્ડર મોકલવા

તમારા સૉફ્ટવેરને ઓર્ડર ઍક્સેસ ધરાવતું થર્ડ-પાર્ટી ક્રેડેન્શિયલ જોઈએ. Owner કે Manager Integrations ખોલે છે, Connect → Third-party software પસંદ કરે છે, અને Can create orders પર ટિક કરે છે. તે ટિક વિનાનું ક્રેડેન્શિયલ કોટેશન વાંચી શકે છે, પણ ઓર્ડર રૂટ પર નકારવામાં આવે છે. ક્રેડેન્શિયલ ઍક્સેસ ટોકન કેવી રીતે બને છે તે ઇન્ટિગ્રેશન બનાવવું માં છે. ઓર્ડર ઇનટેક માટે એવો પ્લાન જોઈએ જેમાં ઇન્ટિગ્રેશન અને Production Floor બંને હોય.

curl -X POST "https://shriganesh.yantrabhavan.com/api/v1/integration/orders" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Idempotency-Key: 9b2f6c1e-3d4a-4f7b-8c55-0e1a2b3c4d5e" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "SO-10442",
    "number": "#10442",
    "version": 1760342400000,
    "dueAt": "2026-10-20T00:00:00Z",
    "lines": [
      { "lineId": "L1", "sku": "BRACKET-PLA-01",
        "title": "Mounting bracket, black PLA", "quantity": 4, "unitPrice": 120 }
    ]
  }'
  • Idempotency-Key જરૂરી છે: તમે મોકલો તે દરેક ઓર્ડર માટે એક નવું રેન્ડમ મૂલ્ય (એક UUID). જો વિનંતી ટાઇમ આઉટ થાય, તો તેને એ જ કી અને બોડી સાથે ફરી મોકલો — તમને મૂળ જવાબ પાછો મળશે અને બીજો ઓર્ડર નહીં બને. એ જ કી અલગ બોડી સાથે મોકલવાથી 422 સાથે નકારવામાં આવે છે. કી 30 દિવસ સુધી યાદ રાખવામાં આવે છે.
  • externalId તમારો ઓર્ડર ID છે. તેને (નવી કી સાથે) ફરી મોકલવાથી નવો ઓર્ડર બનાવવાને બદલે એ જ ઓર્ડર અપડેટ થાય છે. વધતું version મોકલો — ઉદાહરણ તરીકે મિલિસેકન્ડમાં તમારો updated-at સમય — જેથી મોડું પહોંચેલું જૂનું અપડેટ અવગણાય. રદ કરવા માટે cancelled ને true પર સેટ કરો.
  • નવા ઓર્ડર માટે જવાબ 201 અને અપડેટ માટે 200 હોય છે, જેમાં ઓર્ડરની ઇનટેક સ્થિતિ અને, દરેક લાઇન માટે, તે મેપ થઈ છે કે નહીં અને તેના કયા જૉબ છે તે હોય છે. GET …/orders/ પછીથી આ જ માળખું પાછું આપે છે.
  • ઓર્ડર તમારા Shopify અને WooCommerce ઓર્ડરની સાથે Store orders માં આવે છે. જે લાઇનના SKU માટે નિયમ છે તે આપમેળે ફ્લોર પર જાય છે; બીજી દરેક લાઇન તમે એક વાર મેપ કરો તેની રાહ જુએ છે — તમારા ઓનલાઇન સ્ટોરના ઓર્ડર જુઓ.

વેબહૂક એન્ડપોઇન્ટ ઉમેરવું

Integrations માં, Webhooks હેઠળ, Owner કે Manager તે URL ઉમેરે છે જેને Yantra Bhavan એ કૉલ કરવો જોઈએ અને જોઈતા ઇવેન્ટ પસંદ કરે છે. URL પ્રમાણભૂત પોર્ટ પર https:// હોવું જોઈએ અને સાર્વજનિક ઇન્ટરનેટ સુધી પહોંચવું જોઈએ — ખાનગી નેટવર્કની અંદરના સરનામાં નકારવામાં આવે છે, સેવ કરતી વખતે પણ અને દરેક ડિલિવરી વખતે પણ.

  • quotation.requested — કોઈ ખરીદદારે તમારી દુકાન પાસે કોટેશન માંગ્યું.
  • external_order.line_mapped — કોઈ સ્ટોર અથવા API ઓર્ડર લાઇનને પ્રોસેસ આપવામાં આવી — SKU નિયમથી અથવા હાથથી.
  • production_job.status_changed — કોઈ પ્રોડક્શન જૉબ એક સ્થિતિમાંથી બીજીમાં ગયો (કતારમાં, ચાલુ, પૂર્ણ…).
  • shipment.created — તમારા કોઈ ઓર્ડર માટે કેરિયર અને ટ્રેકિંગ સાથે શિપમેન્ટ બનાવવામાં આવ્યું.

ડિલિવરી કેવી દેખાય છે

દરેક ઇવેન્ટ એક JSON POST છે. બોડીમાં ID, સ્થિતિઓ અને ટ્રેકિંગ હોય છે — તમારા ખરીદદારની સંપર્ક વિગતો ક્યારેય નહીં. જ્યારે ઓર્ડર તમારી સિસ્ટમમાંથી આવ્યો હોય, ત્યારે external_id અને line_id તમારા પોતાના ID હોય છે, જેથી તમે શોધ્યા વિના તેને મેળવી શકો.

{
  "id": "0d6f2b1e-7c1a-4b8e-9a51-3f2e4d5c6b7a",
  "type": "production_job.status_changed",
  "created_at": "2026-10-13T09:30:00.000Z",
  "shop_id": "…",
  "data": {
    "job_id": "…", "from": "READY", "to": "IN_PROGRESS",
    "order_id": "…", "order_item_id": "…", "source": "API",
    "external_id": "SO-10442", "line_id": "L1"
  }
}
  • X-YB-Event-Id — ઇવેન્ટ ID, બોડીમાંના id જેવો જ.
  • X-YB-Event-Type — ઇવેન્ટનો પ્રકાર.
  • X-YB-Timestamp — તે ક્યારે સાઇન થયું, Unix સેકન્ડમાં.
  • X-YB-Signature — v1= પછી ટાઇમસ્ટેમ્પ, એક પૂર્ણવિરામ (.) અને રૉ બોડીનો hex HMAC-SHA256, જેની કી તમારું આખું whsec_ સિક્રેટ છે.

ડિલિવરી તપાસવી

કોઈપણ ડિલિવરી પર વિશ્વાસ કરતા પહેલાં તેને તપાસો. ચાર નિયમો, બધા નીચેના સ્નિપેટમાં:

  1. સિગ્નેચર રૉ રિક્વેસ્ટ બોડી પર, બાઇટ-દર-બાઇટ, બનાવો. JSON ને પાર્સ કરીને ફરી સીરિયલાઇઝ કરવાથી તે બદલાય છે, અને સિગ્નેચર મેળ નહીં ખાય.
  2. સિગ્નેચરની સરખામણી કોન્સ્ટન્ટ ટાઇમમાં કરો (crypto.timingSafeEqual, hash_equals, hmac.compare_digest), ક્યારેય == કે === થી નહીં.
  3. તમારી ઘડિયાળથી પાંચ મિનિટથી વધુ અંતરવાળો ટાઇમસ્ટેમ્પ નકારો, જેથી પકડાયેલી ડિલિવરી પછીથી ફરી ચલાવી ન શકાય.
  4. તમે સંભાળી લીધેલા ઇવેન્ટ ID યાદ રાખો અને પુનરાવર્તન છોડી દો. રીટ્રાયમાં એ જ ID હોય છે, અને ક્યારેક એક ઇવેન્ટ બે વાર પહોંચે છે.

Node.js

const crypto = require('node:crypto');

// Express: app.post('/yb-webhooks', express.raw({ type: 'application/json' }), handler)
// req.body must be the RAW bytes — re-serialised JSON will not verify.
function verifyYantraBhavan(secret, req) {
  const timestamp = req.get('X-YB-Timestamp') || '';
  const signature = req.get('X-YB-Signature') || '';
  if (!/^\d+$/.test(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected =
    'v1=' +
    crypto.createHmac('sha256', secret)
      .update(timestamp + '.')
      .update(req.body)
      .digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

PHP

<?php
$secret    = getenv('YB_WEBHOOK_SECRET');           // the whole whsec_… value
$payload   = file_get_contents('php://input');      // raw body
$timestamp = $_SERVER['HTTP_X_YB_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_YB_SIGNATURE'] ?? '';

if (!ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
    http_response_code(400);
    exit;
}
$expected = 'v1=' . hash_hmac('sha256', $timestamp . '.' . $payload, $secret);
if (!hash_equals($expected, $signature)) {
    http_response_code(400);
    exit;
}
http_response_code(204);   // accept now, do the work afterwards

Python

import hashlib
import hmac
import time

def verify_yantra_bhavan(secret: str, headers, raw_body: bytes) -> bool:
    timestamp = headers.get("X-YB-Timestamp", "")
    signature = headers.get("X-YB-Signature", "")
    if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
        return False
    mac = hmac.new(
        secret.encode(), timestamp.encode() + b"." + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest("v1=" + mac, signature)

# Flask: verify_yantra_bhavan(secret, request.headers, request.get_data())

રીટ્રાય, અને એન્ડપોઇન્ટ ક્યારે બંધ કરવામાં આવે છે

10 સેકન્ડની અંદર કોઈપણ 2xx સાથે જવાબ આપો અને ધીમું કામ પછી કરો. બાકી કંઈ પણ — એરર સ્ટેટસ, ટાઇમઆઉટ, રીડાયરેક્ટ — નિષ્ફળતા ગણાય છે, અને તે ઇવેન્ટ આઠ વખત સુધી ફરી મોકલાય છે, વચ્ચે 1, 2, 4 … 64 મિનિટ રાહ જોઈને (કુલ લગભગ બે કલાક).

જો કોઈ એન્ડપોઇન્ટ 24 કલાક સુધી સતત નિષ્ફળ જાય, તો તેને બંધ કરવામાં આવે છે અને દુકાનના માલિકને ઇમેઇલ મળે છે. Integrations માં તે Disabled દેખાય છે; રિસીવર ઠીક કરો, તેને તપાસવા Send test event નો ઉપયોગ કરો, પછી Re-enable કરો. તે બંધ હતું ત્યારના ઇવેન્ટ ફરી મોકલાતા નથી — બાકી રહેલું મેળવવા GET …/orders/ નો ઉપયોગ કરો. Recent deliveries માં દરેક પ્રયાસ તેના સ્ટેટસ કોડ અને એરર સાથે સૂચિબદ્ધ છે.