Recipes
The integrations our customers build most, step by step — which APIs and webhooks to use, in which order.
- Send approved purchase orders to your accounting app
- Bring web-store orders into KERN ERP as Buyer POs
- Keep your web store's stock up to date
- Send website enquiries to KERN CRM as leads
- Record production from the shop floor
- Keep your own database in step with KERN
Every recipe starts the same way: create an API client with the scopes shown, try it with a sandbox key, then switch to a live key.
Send approved purchase orders to your accounting app
API client needs: erp.procurement.purchase_orders:read
- Add a webhook for the client with the event
purchase_order.approvedand press Send test. - When an event arrives, check its signature, then fetch the full purchase order from
links.api. - Create the bill / purchase in your accounting app. Store the KERN PO id against it so a repeated event (same
Kern-Event-Id) is ignored.
GET /cedge/public/v1/procurement/purchase-orders/128
Authorization: Bearer kern_live_…
→ data: { "poNum": "PO-2026-0128", "vendorName": "…", "lines": [ … ], "grandTotal": … }Add grn.posted as well to record goods received against the bill.
Bring web-store orders into KERN ERP as Buyer POs
API client needs: erp.sales.buyer_pos:write, erp.products.products:read, erp.masters.vendors:read
- Look up the customer (
GET /public/v1/masters/vendors?search=…) and each product / SKU (GET /public/v1/products/products?search=…) once, and keep their KERN ids. - Create the Buyer PO. Use your own order number as the
Idempotency-Key— if your store sends the order twice, KERN creates it once.
POST /cedge/public/v1/sales/buyer-pos
Authorization: Bearer kern_live_…
Idempotency-Key: webshop-order-100245
Content-Type: application/json
{ "vendorId": 31, "poNo": "100245", "txnDate": "2026-10-09", "deliveryDate": "2026-10-20",
"lines": [ { "productId": 812, "sizeCode": "M", "qty": 4 } ] }Subscribe to buyer_po.approved and packing_slip.shipped to update the order in your store as it moves.
Keep your web store's stock up to date
API client needs: erp.inventory.fg_stock:read, erp.packing.packing_slips:read
- Once a night, read finished-goods stock page by page and update your store.
- In between, listen for
packing_slip.shippedandstore_transfer.receivedand re-read the SKUs involved.
GET /cedge/public/v1/inventory/fg-stock?page=0&size=200
→ data: { "content": [ { "sku": "TSH-NVY-M", "qty": 140, … } ], "totalPages": 7 }Mind the rate limit: read pages one after another and respect Retry-After if you get 429.
Send website enquiries to KERN CRM as leads
API client needs: crm.leads.leads:write
- When someone fills in your contact form, create a lead in KERN CRM from your server (never from the browser — the key must stay secret).
- Optionally add a webhook for
lead.createdto notify your team chat.
POST /cedge-crm/public/v1/leads/leads
Authorization: Bearer kern_live_…
Idempotency-Key: form-7f3a…
Content-Type: application/json
{ "name": "Asha Rao", "company": "Rao Garments", "email": "asha@example.com",
"phone": "+919800000000", "source": "Website" }A duplicate phone or email is refused with a clear message — show it, or add "allowDuplicate": true on purpose.
Record production from the shop floor
API client needs: erp.production.runs:write
- Read the run and its stages:
GET /public/v1/production/runs/{id}. - Before posting, check what each stage can take:
GET /public/v1/production/runs/stages/{runStageId}/available-input. - Post the day's figures per size. KERN checks them against what the earlier stage produced and moves the run on.
POST /cedge/public/v1/production/runs/stages/551/daily-entries
Idempotency-Key: line3-2026-10-09-stage551
Content-Type: application/json
{ "entryDate": "2026-10-09", "sizes": [ { "sizeCode": "M", "inputQty": 120, "outputQty": 116, "rejectQty": 4 } ] }Add a webhook for production_run.completed to know when the run is done.
Keep your own database in step with KERN
API client needs: read scopes for the resources you copy, e.g. erp.procurement.*:read, erp.sales.*:read
- First run: call
GET /public/v1/changes?since=…with the date you want to start from. - For each change, fetch the record from its
pathand save it in your database byresource+id(insert or update). - After each page, save
nextCursor. WhilehasMoreis true, ask again withcursor=that value. - From then on, run it every few minutes (or when a webhook arrives) with the saved cursor — you only get what changed.
GET /cedge/public/v1/changes?cursor=MTc5MTQ4…&resources=procurement.purchase_orders,sales.invoices
→ data: { "changes": [ { "resource": "sales.invoices", "id": 77, "path": "/public/v1/sales/invoices/77", … } ],
"nextCursor": "MTc5MTQ5…", "hasMore": false }Deleted records aren't listed — if you need to notice them, re-check your copy against the list APIs now and then.