API Keys & Integration
Connect your website or app to NavYour delivery APIs. Create test orders, verify your connection, and go live safely.
Test API Key
Use the Test API key while integrating your website. Test orders appear in this page and do not create real deliveries.
Never place this key in frontend JavaScript, HTML, mobile app public code, or GitHub. Store it only in your backend/server .env.
Create a test key and copy it once. Stored keys are shown only as prefix and last four characters.
Live API Key
Live API creates real NavYour delivery orders and may deduct delivery fees from your wallet.
Complete the missing go-live items below before creating a Live API key.
Live API is locked until the checklist is complete.
Test Orders / Connection Test
Send a test order from your website/backend using your Test API key. If the integration is correct, the test order will appear below within a few seconds.
How to connect your website to NavYour
Do not send old orders. Do not create a bulk sync. One local order = one NavYour delivery.
Call NavYour only when one new local order has just been confirmed. Store NavYour sync status on that local order and use the same Idempotency-Key when retrying that same order.
Click Create Test API Key. Copy it once and save it in your backend .env. Start with exactly one new checkout test order.
# Production NAVYOUR_API_BASE_URL=https://api.navyour.in/v1 NAVYOUR_API_KEY=sk_test_nv_xxxxx # Local development only NAVYOUR_API_BASE_URL=http://localhost:3000/v1 NAVYOUR_API_KEY=sk_test_nv_xxxxx
Add backend code after checkout/order confirmation only. Send one complete payload for the current local order to POST /integration/orders. Do not call NavYour from frontend.
{
"orderReference": "STORE-ORDER-1001",
"orderSource": "business_website",
"customer": {
"name": "Rahul Sharma",
"phone": "+919876543210",
"email": "rahul@example.com"
},
"delivery": {
"addressLine1": "Paona Bazaar",
"addressLine2": "Near Ima Market",
"city": "Imphal",
"state": "Manipur",
"pincode": "795001",
"landmark": "Near main gate",
"latitude": 24.8072,
"longitude": 93.9368,
"fullAddress": "Paona Bazaar, near Ima Market, Imphal, Manipur 795001"
},
"pickup": {
"businessName": "Fresh Store",
"contactName": "Nashei H",
"phone": "+919876543210",
"addressLine1": "MG Avenue",
"city": "Imphal",
"state": "Manipur",
"pincode": "795001",
"fullAddress": "MG Avenue, Shop No. 12, Imphal, Manipur 795001"
},
"package": {
"description": "Customer grocery order",
"items": [{ "name": "Rice bag", "quantity": 1, "pricePaise": 80000 }],
"totalItems": 1,
"weightKg": 5,
"fragile": false
},
"payment": {
"paymentType": "cod",
"orderValuePaise": 130000,
"deliveryFeePaise": 4000,
"codAmountPaise": 134000,
"prepaidAmountPaise": 0,
"currency": "INR"
}
}Copy the backend integration prompt and give it to your developer. It explicitly forbids old-order sync, bulk-sync jobs, startup sync, admin-dashboard sync, and duplicate NavYour delivery creation.
After order creation, configure webhooks so NavYour can update delivery status. Webhooks must only update existing local orders; never create customer orders from webhook payloads.
Create a Live API key only after one new test order appears, no old orders were sent, duplicate retry was tested, failure retry was tested, profile is complete, subscription is active, wallet is funded, and webhooks are configured if needed.
Your website decides the delivery fee and sends deliveryFeePaise to NavYour. NavYour validates this amount and deducts the same delivery fee from your NavYour wallet for live orders.
Customer pays your business. Your NavYour wallet pays NavYour delivery fee.
codAmountPaise is the exact cash amount the driver must collect from the customer. If your checkout total includes delivery fee, include delivery fee inside codAmountPaise.
Test orders do not deduct wallet balance and do not assign drivers.
async function createNavYourDelivery(savedOrder) {
if (savedOrder.navyourOrderId || savedOrder.navyourTrackingCode || savedOrder.navyourSyncStatus === "created") {
return {
alreadyCreated: true,
navyourOrderId: savedOrder.navyourOrderId,
trackingCode: savedOrder.navyourTrackingCode,
trackingUrl: savedOrder.navyourTrackingUrl,
};
}
if (savedOrder.navyourSyncStatus === "creating") {
throw new Error("NavYour sync already in progress for this order");
}
const idempotencyKey = `${process.env.WEBSITE_NAME || "website"}-${savedOrder.id}`;
await markNavYourSyncCreating(savedOrder.id, {
navyourSyncStatus: "creating",
navyourLastSyncAttemptAt: new Date(),
});
const payload = {
orderReference: String(savedOrder.id),
orderSource: "business_website",
customer: {
name: savedOrder.customerName,
phone: savedOrder.customerPhone,
email: savedOrder.customerEmail || null,
},
delivery: {
addressLine1: savedOrder.shippingAddressLine1,
addressLine2: savedOrder.shippingAddressLine2 || null,
city: savedOrder.shippingCity,
state: savedOrder.shippingState,
pincode: savedOrder.shippingPincode,
landmark: savedOrder.shippingLandmark || null,
latitude: savedOrder.deliveryLatitude || null,
longitude: savedOrder.deliveryLongitude || null,
fullAddress: savedOrder.shippingFullAddress,
},
pickup: {
businessName: process.env.STORE_NAME,
contactName: process.env.STORE_CONTACT_NAME,
phone: process.env.STORE_PHONE,
addressLine1: process.env.STORE_ADDRESS_LINE1,
addressLine2: process.env.STORE_ADDRESS_LINE2 || null,
city: process.env.STORE_CITY,
state: process.env.STORE_STATE,
pincode: process.env.STORE_PINCODE,
landmark: process.env.STORE_LANDMARK || null,
latitude: process.env.STORE_LATITUDE ? Number(process.env.STORE_LATITUDE) : null,
longitude: process.env.STORE_LONGITUDE ? Number(process.env.STORE_LONGITUDE) : null,
fullAddress: process.env.STORE_FULL_ADDRESS,
},
package: {
description: savedOrder.packageDescription || "Customer order package",
items: savedOrder.items.map((item) => ({
name: item.name,
quantity: item.quantity,
pricePaise: item.pricePaise,
})),
totalItems: savedOrder.items.length,
weightKg: savedOrder.weightKg || null,
fragile: Boolean(savedOrder.fragile),
specialInstructions: savedOrder.deliveryInstructions || null,
},
payment: {
paymentType: savedOrder.paymentMode === "COD" ? "cod" : "prepaid",
orderValuePaise: savedOrder.orderValuePaise,
deliveryFeePaise: savedOrder.deliveryFeePaise,
codAmountPaise: savedOrder.paymentMode === "COD" ? savedOrder.codAmountPaise : 0,
prepaidAmountPaise: savedOrder.paymentMode === "COD" ? 0 : savedOrder.paidAmountPaise,
currency: "INR",
},
notes: {
customerNote: savedOrder.customerNote || null,
internalNote: savedOrder.internalNote || null,
},
};
const response = await fetch(`${process.env.NAVYOUR_API_BASE_URL}/integration/orders`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.NAVYOUR_API_KEY}`,
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify(payload),
});
const data = await response.json().catch(() => null);
if (!response.ok) {
await markNavYourSyncFailed(savedOrder.id, {
navyourSyncStatus: "failed",
navyourSyncError: data?.message || "NavYour delivery creation failed",
navyourLastSyncAttemptAt: new Date(),
});
throw new Error(data?.message || "NavYour delivery creation failed");
}
await saveNavYourTracking(savedOrder.id, {
navyourOrderId: data.id || data.navyourOrderId,
navyourTrackingCode: data.trackingCode,
navyourTrackingUrl: data.trackingUrl,
navyourDeliveryStatus: data.status,
navyourSyncStatus: "created",
navyourSyncError: null,
});
return data;
}Bulk sync risk: never fetch all confirmed orders, send old orders, or run NavYour sync on startup.
401 Invalid API key: check the backend env value and never use frontend code.
403 Live API locked: complete profile, activate subscription, fund wallet, or continue using test key.
400 Missing deliveryFeePaise: send the delivery fee amount in paise.
400 Missing customer/delivery details: send full customer and delivery address.
402 Wallet balance low: top up wallet before live orders.
409 Duplicate orderReference: use the existing tracking code or retry safely with the same Idempotency-Key.
Safe production integration prompt
This prompt must be connected to your backend's new order confirmed flow. Do not use it to bulk-sync old orders, fetch all confirmed orders, run on server startup, run from an admin dashboard, or send all existing orders to NavYour. One local order should create one NavYour delivery order.
You are working in this website backend. Integrate NavYour delivery creation into the existing checkout/order-confirmation flow.
CRITICAL GOAL:
When ONE NEW customer order is successfully confirmed in this website, create exactly ONE NavYour delivery order from the backend, store the returned tracking details on that same local order, and make retries safe.
DO NOT CREATE BULK SYNC:
- Do not fetch all orders from the database and send them to NavYour.
- Do not send old/historical orders.
- Do not run NavYour sync on server startup.
- Do not run NavYour sync from an order list page, admin dashboard, GET endpoint, seed script, or cron unless explicitly asked later.
- Do not create a general “sync all confirmed orders” job.
- This integration must run only for the single local order that was just created/confirmed.
- If a one-time backfill is ever needed, it must be a separate explicit script with date filters and already-synced checks. Do not implement backfill now.
TEST MODE FIRST:
First use the NavYour Test API key only.
Do not switch to Live until a test order appears in:
NavYour Business Portal -> API Keys -> Test Orders.
NavYour API:
- Base URL env: NAVYOUR_API_BASE_URL
- API key env: NAVYOUR_API_KEY
- Endpoint: POST {NAVYOUR_API_BASE_URL}/integration/orders
- Auth header: Authorization: Bearer {NAVYOUR_API_KEY}
- Idempotency header: Idempotency-Key: use this website's immutable local order id/reference
- Content-Type: application/json
Required env example:
NAVYOUR_API_BASE_URL=https://api.navyour.in/v1
NAVYOUR_API_KEY=sk_test_nv_xxxxx
Security rules:
- Store NAVYOUR_API_KEY only in backend/server environment variables.
- Never expose the key in frontend JavaScript, HTML, mobile app code, logs, analytics, error trackers, GitHub, or API responses.
- Do not call NavYour from the browser.
- Only this website backend may call NavYour.
- Redact Authorization and NAVYOUR_API_KEY from logs.
- Never log full customer sensitive data unnecessarily.
Database changes/checks:
Add or reuse these fields on the local orders table:
- navyourOrderId nullable string
- navyourTrackingCode nullable string
- navyourTrackingUrl nullable string
- navyourDeliveryStatus nullable string
- navyourSyncStatus: not_started | creating | created | failed
- navyourSyncError nullable text
- navyourLastSyncAttemptAt nullable datetime
Duplicate prevention:
- Add a database-level unique guard if using a separate NavYour sync/integration table.
- The same local order must not be able to create multiple NavYour deliveries.
- Before calling NavYour, check:
- if navyourOrderId exists, return existing NavYour details
- if navyourTrackingCode exists, return existing NavYour details
- if navyourSyncStatus is "created", return existing NavYour details
- if navyourSyncStatus is "creating", do not start a second request; return/throw a safe “sync already in progress” result
- Set navyourSyncStatus = "creating" and navyourLastSyncAttemptAt before making the NavYour API request.
- Use a transaction or row lock if this backend supports it, so parallel requests cannot create duplicate delivery orders.
When to call NavYour:
- Call only after this website has successfully saved and confirmed the local order.
- Never create a NavYour delivery before local order confirmation.
- Never create a NavYour delivery before online payment confirmation if this website requires payment first.
- For COD orders, call after COD order is confirmed.
- For prepaid orders, call only after payment is successful/captured.
- The call must happen for the current local order only.
Never hardcode sample order data:
- Do not use ORDER-1001 in production logic.
- Do not reuse the same orderReference for multiple orders.
- Do not send static customer/product/address data.
- All payload fields must come from the actual current local order.
Payload requirements:
Send a complete JSON payload with:
- orderReference: this website's stable unique local order id/reference
- orderSource: "business_website"
- customer.name
- customer.phone
- customer.email if available
- delivery full address and address fields
- pickup store/business address and contact fields
- package description/items/totalItems/weightKg/fragile/specialInstructions
- payment.paymentType
- payment.orderValuePaise
- payment.deliveryFeePaise
- payment.codAmountPaise
- payment.prepaidAmountPaise
- payment.currency: "INR"
- notes.customerNote and notes.internalNote when available
Money rules:
- deliveryFeePaise is required and must be greater than 0.
- This website decides deliveryFeePaise and sends it to NavYour.
- In Live mode, NavYour deducts deliveryFeePaise from this business's NavYour wallet.
- Customer payment belongs to this business.
- NavYour wallet pays the NavYour delivery fee.
- For COD, codAmountPaise must be the exact cash amount the driver collects from the customer.
- If this website checkout total includes delivery fee, include that delivery fee inside codAmountPaise.
- For prepaid orders, prepaidAmountPaise is the amount already collected by this website.
Idempotency:
- Idempotency-Key must be stable and unique for this local order.
- Recommended: WEBSITE_NAME + "-" + localOrderId
- Use the same Idempotency-Key on every retry for the same local order.
- Use the same orderReference on every retry for the same local order.
- Treat 409 duplicate/order already exists as recoverable only if NavYour returns or can recover the tracking details.
Failure behavior:
- If NavYour fails, do not delete or cancel the customer order.
- Save navyourSyncStatus = "failed".
- Save a safe error message in navyourSyncError.
- Save navyourLastSyncAttemptAt.
- Allow retry only for that specific failed order using the same orderReference and Idempotency-Key.
- Do not retry in an uncontrolled loop.
- Do not retry all old orders automatically.
- Surface a clear internal error for operations, but do not expose API keys or raw sensitive headers.
Expected success response handling:
Parse JSON response and save:
- data.id or data.navyourOrderId -> navyourOrderId
- data.trackingCode -> navyourTrackingCode
- data.trackingUrl -> navyourTrackingUrl
- data.status -> navyourDeliveryStatus
- navyourSyncStatus = "created"
- clear navyourSyncError
Webhook receiver:
- Create POST /api/navyour/webhook in this website backend.
- Store NAVYOUR_WEBHOOK_SECRET only in backend .env.
- Verify NavYour-Signature with raw body before parsing JSON.
- Signature payload is NavYour-Timestamp + "." + rawBody.
- Update the local order using event.order.orderReference or event.order.trackingCode.
- Return HTTP 200 quickly.
- Do heavy work after response if needed.
- Handle at least:
- driver.assigned
- order.picked_up
- order.out_for_delivery
- order.delivered
- order.failed
- order.cancelled
- cod.collected
- cod.handed_over
- cod.settled
- Never create customer orders from webhook payloads.
- Webhook only updates delivery status after API order creation.
Testing steps:
1. Put the NavYour Test API key in backend .env as NAVYOUR_API_KEY.
2. Set NAVYOUR_API_BASE_URL=https://api.navyour.in/v1.
3. Place exactly one new real test checkout/order through this website flow.
4. Confirm backend sends exactly one POST /integration/orders for that one local order.
5. Confirm the request includes Authorization Bearer and Idempotency-Key.
6. Confirm no old orders were sent.
7. Confirm the order appears in NavYour Business Portal -> API Keys -> Test Orders.
8. Confirm NavYour returns a TEST tracking code.
9. Confirm this website order stores trackingCode and trackingUrl.
10. Trigger retry for the same local order and confirm it does not create a second NavYour delivery.
11. Force a NavYour failure and confirm this website marks only that order as failed.
12. Retry only that failed order and confirm it uses the same Idempotency-Key.
13. Configure NavYour webhook URL and signing secret.
14. Send test webhook and verify signature handling.
15. Confirm webhook events update local order delivery status.
Go-live checklist:
- One new test order appears successfully in NavYour Business Portal.
- No old orders were sent during testing.
- The local order stores NavYour tracking details.
- Duplicate retry has been tested.
- Failure/retry behavior has been tested.
- Webhook endpoint is configured and test webhook succeeded.
- Business profile, subscription, and wallet are ready in NavYour.
- Only then replace the Test API key with the Live API key in backend .env.
Implement this using the existing backend framework, existing order model/service patterns, existing logger, and existing environment config style in this repository.
Add focused tests for:
- payload construction from one current order
- no sync if already created
- creating status guard
- idempotency key generation
- success persistence
- failure persistence
- no bulk old-order syncWebhook Next Step
After test order appears, configure webhook to receive delivery updates automatically.
