Backend Integration
Integrate your own services with Kadaikodi via the GraphQL API. This guide covers service-to-service authentication, common patterns, and environment selection.
Authentication
Service-to-service calls use OAuth2 client credentials (M2M / app auth):
Node SDK
const result = await sdk.auth.authenticateApp(clientId, clientSecret);
Python SDK
# Use client_id + client_secret in KadaikodiSDK constructor
sdk = KadaikodiSDK(client_id="my-app", client_secret="...")
await sdk.auth.authenticate_app()
CLI
kadaikodi auth login --client-credentials \
--client-id <id> --client-secret <secret>
Raw GraphQL
curl -X POST https://graphqlworkspaces.burdenoff.com/workspaces/graphql \
-H "content-type: application/json" \
-H "authorization: Bearer <m2m-token>" \
-H "x-workspace-id: <workspace-id>" \
-d '{"query": "query { kadaikodiHealth }"}'
Environment selection
All integrations default to production. Override with BURDENOFF_ENV or explicit endpoint variables:
| Variable | Production default |
|---|---|
KADAIKODI_WORKSPACE_ENDPOINT | https://graphqlworkspaces.burdenoff.com/workspaces/graphql |
KADAIKODI_GLOBAL_ENDPOINT | https://graphql.burdenoff.com/global/graphql |
See Environment Selection for the full mapping.
Common patterns
Webhook receiver
Configure a webhook in the Kadaikodi developer portal to receive order events:
import { createHmac } from "crypto";
import express from "express";
const app = express();
app.use(express.raw({ type: "application/json" }));
app.post("/kadaikodi-webhook", (req, res) => {
const sig = req.headers["x-kadaikodi-signature"] as string;
// Verify HMAC-SHA256 signature with your webhook secret
const expected = createHmac("sha256", process.env.WEBHOOK_SECRET!)
.update(req.body.toString())
.digest("hex");
if (sig !== expected) return res.sendStatus(401);
const payload = JSON.parse(req.body.toString());
// Process order.created, order.status_changed, etc.
res.sendStatus(200);
});
app.listen(8080);
Polling for order status
async function pollOrderStatus(orderId: string, targetStatus: string) {
for (let i = 0; i < 30; i++) {
const order = await sdk.kadaikodi.orders.get(orderId);
if (order.status === targetStatus) return order;
await new Promise(r => setTimeout(r, 10000));
}
throw new Error("Timeout waiting for status");
}
Bulk import offerings
const offerings = await readCSV("./offerings.csv");
for (const row of offerings) {
await sdk.kadaikodi.offerings.create({
name: row.name,
category: row.category,
price: parseFloat(row.price),
stock: parseInt(row.stock),
fulfillmentTypes: ["PICKUP", "DELIVERY"],
});
}
Rate limits
The public gateway enforces workspace-level rate limits. For high-volume integrations, consider:
- Batching mutations where the schema supports it
- Using the internal gateway for M2M traffic (requires network access)
- Caching read queries with appropriate TTL
Error handling
Always handle these error classes:
AuthenticationError— token expired or invalid; refresh and retryAuthorizationError— the app lacks permission for the operationValidationError— input violates schema constraintsRateLimitError— back off and retry with exponential jitterNetworkError— transient; retry with exponential backoff