Skip to main content

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:

VariableProduction default
KADAIKODI_WORKSPACE_ENDPOINThttps://graphqlworkspaces.burdenoff.com/workspaces/graphql
KADAIKODI_GLOBAL_ENDPOINThttps://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 retry
  • AuthorizationError — the app lacks permission for the operation
  • ValidationError — input violates schema constraints
  • RateLimitError — back off and retry with exponential jitter
  • NetworkError — transient; retry with exponential backoff

Next steps