Kaniva API v1

A REST API for your store: calendar & booking, products, orders, customers, inventory, manufacturing, and webhooks. All responses are JSON. Create an API key in your store admin under Settings → API.

Getting started

Every request is authenticated with an API key and scoped to a single store. The base URL is:

https://dev.kaniva.io/api/v1

The store (tenant) is resolved from your API key — you don't pass a store slug in API URLs. Pick curl, JavaScript or PHP with the switch above; every example below follows your choice.

Authentication

Pass your secret key as a Bearer token in the Authorization header. Keys look like kn_live_… and are shown only once at creation. Mint one under Settings → API in your store admin and grant it only the scopes it needs.

curl https://dev.kaniva.io/api/v1/admin/store/summary \
  -H "Authorization: Bearer kn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/store/summary", {
  headers: {
    "Authorization": "Bearer kn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "Accept": "application/json"
  }
});
const summary = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/store/summary");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "Accept: application/json"
    ],
]);
$summary = json_decode(curl_exec($ch), true);

Missing/invalid/expired/revoked keys return 401 Unauthorized. A key missing the required scope returns 403 Forbidden.

Rate limits

Limits are enforced per API key, defaulting to 60 requests/minute (configurable per key up to 600/min). Every response includes:

HeaderMeaning
X-RateLimit-LimitYour per-minute ceiling.
X-RateLimit-RemainingRequests left in the current window.
Retry-AfterSeconds until reset (sent on 429 responses).

Exceeding the limit returns 429 Too Many Requests.

Pagination

List endpoints return a data array and a meta block. Use page to page through and per_page to size each page (default 20, maximum 100).

GET https://dev.kaniva.io/api/v1/admin/products?page=2&per_page=50
{
  "data": [ { "id": 101 }, { "id": 102 } ],
  "meta": { "current_page": 2, "last_page": 7, "per_page": 50, "total": 312 }
}

Errors

Errors return a JSON body with an error label and a human-readable message:

{
  "error": "Forbidden",
  "message": "This API key does not have the required scope(s): calendar:write",
  "required_scopes": ["calendar:write"],
  "key_scopes": ["calendar:read"]
}
StatusMeaning
200 / 201Success.
401Missing or invalid API key.
403Key lacks the scope, or the module is disabled for the store.
404Resource not found.
422Validation error.
429Rate limit exceeded.
501Not available yet — the headless cart and checkout endpoints are reserved but not live.

Scopes

Each key is granted a set of scopes. Endpoints below list the scope they require.

ScopeGrants
products:readView products and variants
products:writeCreate, update, and delete products
orders:readView orders and order details
orders:writeUpdate order status and details
orders:manageFulfill, refund, and cancel orders
customers:readView customer information
customers:writeCreate and update customers
categories:readView categories
categories:writeCreate, update, and delete categories
cart:readView cart contents (not available yet)
cart:writeAdd, update, and remove cart items (not available yet)
checkout:writeProcess checkout and create orders (not available yet)
inventory:readView inventory levels and items
inventory:writeAdjust inventory quantities
inventory:manageFull inventory control (reserve, commit, transfers)
manufacturing:readView BOMs and work orders
manufacturing:writeCreate and manage work orders
webhooks:readView webhook configurations
webhooks:writeCreate, update, and delete webhooks
blog:readView blog posts, categories and tags
blog:writeCreate, update and delete blog posts, upload their images
crm:readView CRM contacts and support tickets
crm:writeCreate and update support tickets
triage:readView AI triage results and metrics
triage:writeIngest messages for AI triage and send triaged replies
calendar:readView calendar events and availability
calendar:writeCreate, update, and delete calendar events and availability
bookings:readView bookings and available time slots
bookings:writeCreate, confirm, and cancel bookings
settings:readView shipping configuration and integration health (never secret values)

Webhooks

Subscribe to store events (GET https://dev.kaniva.io/api/v1/admin/webhooks/events lists the types) and Kaniva will POST a JSON payload to your URL. Each delivery is signed with HMAC-SHA256 of the raw body using your webhook's secret, in the X-Webhook-Signature header. Always verify it before trusting the payload.

{
  "event": "order.created",
  "created_at": "2026-11-09T14:03:00Z",
  "data": { "id": 1001, "status": "paid" }
}

Verify the signature

# Signatures are verified in your server code — see the JavaScript or PHP tab.
# Header to check: X-Webhook-Signature: sha256=<hex>
import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}
function verify(string $rawBody, string $header, string $secret): bool
{
    $expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $header);
}

Deliveries retry on failure. Inspect recent attempts with GET https://dev.kaniva.io/api/v1/admin/webhooks/{id}/deliveries and rotate a leaked secret with POST https://dev.kaniva.io/api/v1/admin/webhooks/{id}/regenerate-secret.

Calendar — Events

GET /admin/calendar/events scope: calendar:read

List calendar events.

ParameterDescription
startISO date — range start (with end)
endISO date — range end
typeFilter by type (appointment, meeting, reminder, shift, custom, …)
statusFilter by status (scheduled, confirmed, cancelled, completed)
per_pageItems per page (max 100)

Request

curl https://dev.kaniva.io/api/v1/admin/calendar/events?start=…&end=…&type=…&status=…&per_page=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/events?start=…&end=…&type=…&status=…&per_page=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/events?start=…&end=…&type=…&status=…&per_page=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/calendar/events/{id} scope: calendar:read

Get a single calendar event (includes its booking, if any).

Request

curl https://dev.kaniva.io/api/v1/admin/calendar/events/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/events/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/events/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/calendar/events scope: calendar:write

Create a calendar event.

ParameterDescription
titlerequired
start_atrequired, datetime
end_atdatetime
typerequired (appointment, meeting, …)
all_dayboolean
descriptionstring
locationstring
colorhex
reminder_minutesint
statusscheduled|confirmed|cancelled|completed

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/calendar/events \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "…",
  "start_at": "…",
  "end_at": "…",
  "type": "…",
  "all_day": "…",
  "description": "…",
  "location": "…",
  "color": "…",
  "reminder_minutes": "…",
  "status": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/events", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "title": "…",
  "start_at": "…",
  "end_at": "…",
  "type": "…",
  "all_day": "…",
  "description": "…",
  "location": "…",
  "color": "…",
  "reminder_minutes": "…",
  "status": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/events");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "title" => "…",
        "start_at" => "…",
        "end_at" => "…",
        "type" => "…",
        "all_day" => "…",
        "description" => "…",
        "location" => "…",
        "color" => "…",
        "reminder_minutes" => "…",
        "status" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/calendar/events/{id} scope: calendar:write

Update a calendar event.

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/calendar/events/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/events/{id}", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/events/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
DELETE /admin/calendar/events/{id} scope: calendar:write

Delete a calendar event.

Request

curl -X DELETE https://dev.kaniva.io/api/v1/admin/calendar/events/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/events/{id}", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/events/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "DELETE",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "deleted": true }
}

Calendar — Availability

GET /admin/calendar/availability scope: calendar:read

Get recurring weekly availability rules and blocked dates.

Request

curl https://dev.kaniva.io/api/v1/admin/calendar/availability \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/availability", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/availability");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
PUT /admin/calendar/availability scope: calendar:write

Replace weekly rules; add/remove blocked dates.

ParameterDescription
days[]{ day_of_week 0-6, is_available, start_time H:i, end_time H:i }
add_blocked[]YYYY-MM-DD dates to block
remove_blocked[]availability ids to unblock

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/calendar/availability \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "days[]": "…",
  "add_blocked[]": "…",
  "remove_blocked[]": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/availability", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "days[]": "…",
  "add_blocked[]": "…",
  "remove_blocked[]": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/availability");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "days[]" => "…",
        "add_blocked[]" => "…",
        "remove_blocked[]" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Bookings (admin)

GET /admin/calendar/bookings scope: bookings:read

List bookings, newest first.

ParameterDescription
statuspending|confirmed|cancelled
per_pageItems per page (max 100)

Request

curl https://dev.kaniva.io/api/v1/admin/calendar/bookings?status=…&per_page=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/bookings?status=…&per_page=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/bookings?status=…&per_page=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/calendar/bookings/{id} scope: bookings:read

Get a single booking with its event.

Request

curl https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/calendar/bookings/{id}/confirm scope: bookings:write

Confirm a booking and email the guest.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}/confirm \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}/confirm", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}/confirm");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/calendar/bookings/{id}/cancel scope: bookings:write

Cancel a booking.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}/cancel \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}/cancel", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/calendar/bookings/{id}/cancel");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Booking (storefront / scheduling widget)

GET /storefront/calendar/slots scope: bookings:read

Available 30-minute slots for a date.

ParameterDescription
daterequired, YYYY-MM-DD (today or later)

Request

curl https://dev.kaniva.io/api/v1/storefront/calendar/slots?date=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/storefront/calendar/slots?date=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/storefront/calendar/slots?date=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
POST /storefront/calendar/bookings scope: bookings:write

Create a booking (sends guest + admin emails).

ParameterDescription
daterequired
timerequired H:i
guest_namerequired
guest_emailrequired
guest_phoneoptional
guest_companyoptional
notesoptional

Request

curl -X POST https://dev.kaniva.io/api/v1/storefront/calendar/bookings \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "date": "…",
  "time": "…",
  "guest_name": "…",
  "guest_email": "…",
  "guest_phone": "…",
  "guest_company": "…",
  "notes": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/storefront/calendar/bookings", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "date": "…",
  "time": "…",
  "guest_name": "…",
  "guest_email": "…",
  "guest_phone": "…",
  "guest_company": "…",
  "notes": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/storefront/calendar/bookings");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "date" => "…",
        "time" => "…",
        "guest_name" => "…",
        "guest_email" => "…",
        "guest_phone" => "…",
        "guest_company" => "…",
        "notes" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Products (admin)

GET /admin/products scope: products:read

List products.

ParameterDescription
searchname or SKU
category_idfilter
is_activeboolean
per_pagemax 100

Request

curl https://dev.kaniva.io/api/v1/admin/products?search=…&category_id=…&is_active=…&per_page=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/products?search=…&category_id=…&is_active=…&per_page=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/products?search=…&category_id=…&is_active=…&per_page=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/products/{id} scope: products:read

Get a product with variants and images.

Request

curl https://dev.kaniva.io/api/v1/admin/products/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/products/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/products/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/products scope: products:write

Create a product (name and price required).

ParameterDescription
namestring
pricenumber
skustored as the part number
product_typephysical|digital|build_to_order|bundle (new products default to physical; wins over is_digital)
track_inventoryboolean
stock_quantityint
is_activeboolean
visibilitypublic|private
category_idint

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/products \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "…",
  "price": "…",
  "sku": "…",
  "product_type": "…",
  "track_inventory": "…",
  "stock_quantity": "…",
  "is_active": "…",
  "visibility": "…",
  "category_id": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/products", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "name": "…",
  "price": "…",
  "sku": "…",
  "product_type": "…",
  "track_inventory": "…",
  "stock_quantity": "…",
  "is_active": "…",
  "visibility": "…",
  "category_id": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/products");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "name" => "…",
        "price" => "…",
        "sku" => "…",
        "product_type" => "…",
        "track_inventory" => "…",
        "stock_quantity" => "…",
        "is_active" => "…",
        "visibility" => "…",
        "category_id" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/products/{id} scope: products:write

Update a product; fields left out are unchanged.

ParameterDescription
namestring
pricenumber
skustored as the part number
product_typephysical|digital|build_to_order|bundle (new products default to physical; wins over is_digital)
track_inventoryboolean
stock_quantityint
is_activeboolean
visibilitypublic|private
category_idint

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/products/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "…",
  "price": "…",
  "sku": "…",
  "product_type": "…",
  "track_inventory": "…",
  "stock_quantity": "…",
  "is_active": "…",
  "visibility": "…",
  "category_id": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/products/{id}", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "name": "…",
  "price": "…",
  "sku": "…",
  "product_type": "…",
  "track_inventory": "…",
  "stock_quantity": "…",
  "is_active": "…",
  "visibility": "…",
  "category_id": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/products/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "name" => "…",
        "price" => "…",
        "sku" => "…",
        "product_type" => "…",
        "track_inventory" => "…",
        "stock_quantity" => "…",
        "is_active" => "…",
        "visibility" => "…",
        "category_id" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/products/{id}/images scope: products:write

Upload photos (multipart). The first becomes the main photo if there is none or is_primary is true; the rest join the gallery.

ParameterDescription
imagefile (or images[] for several), max 10 MB
is_primaryboolean
alt_textstring

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/products/{id}/images \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "image": "…",
  "is_primary": "…",
  "alt_text": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/products/{id}/images", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "image": "…",
  "is_primary": "…",
  "alt_text": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/products/{id}/images");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "image" => "…",
        "is_primary" => "…",
        "alt_text" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
DELETE /admin/products/{id} scope: products:write

Delete a product.

Request

curl -X DELETE https://dev.kaniva.io/api/v1/admin/products/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/products/{id}", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/products/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "DELETE",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "deleted": true }
}

Orders (admin)

GET /admin/orders scope: orders:read

List orders.

Request

curl https://dev.kaniva.io/api/v1/admin/orders \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/orders/{id} scope: orders:read

Get an order with items, customer, shipment boxes (label + per-box tracking), and a refund_gate block (refundable_amount, is_shipped, has_label, can_cancel, can_refund).

Request

curl https://dev.kaniva.io/api/v1/admin/orders/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/orders/{id}/status scope: orders:write

Update order status only. Tracking fields sent here are not saved; the response lists them in ignored_fields with a warnings message. Use POST /admin/orders/{id}/shipments for tracking.

ParameterDescription
statusrequired — pending|processing|shipped|delivered|cancelled

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/orders/{id}/status \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders/{id}/status", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "status": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders/{id}/status");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "status" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/orders/{id}/fulfillment scope: orders:manage

Mark shipped/delivered and record tracking. Stamps shipped_at / delivered_at, registers the number with Shippo and PayPal when carrier + number are given.

ParameterDescription
fulfillment_statusrequired — pending|processing|partially_shipped|labeled|shipped|delivered
tracking_carriere.g. usps, ups, fedex
tracking_numberstring
tracking_urlurl
tracking_modeadd (the only mode; numbers are appended, never replaced)
notify_customerboolean, default false

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/orders/{id}/fulfillment \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "fulfillment_status": "…",
  "tracking_carrier": "…",
  "tracking_number": "…",
  "tracking_url": "…",
  "tracking_mode": "…",
  "notify_customer": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders/{id}/fulfillment", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "fulfillment_status": "…",
  "tracking_carrier": "…",
  "tracking_number": "…",
  "tracking_url": "…",
  "tracking_mode": "…",
  "notify_customer": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders/{id}/fulfillment");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "fulfillment_status" => "…",
        "tracking_carrier" => "…",
        "tracking_number" => "…",
        "tracking_url" => "…",
        "tracking_mode" => "…",
        "notify_customer" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/orders/{id}/shipments scope: orders:manage

Record a package shipped outside Kaniva as its own shipment (box) with its carrier, tracking number, link and items. Never changes tracking already on the order. The order becomes partially_shipped until every item is shipped, then shipped. Posting the same tracking number again returns the existing shipment (200, not 201). 422 for cancelled/refunded/local-pickup orders, drop-ship lines, or more than is left to ship.

ParameterDescription
carrierrequired — e.g. usps, ups, fedex, dhl
tracking_numberrequired — one number
tracking_urlurl
itemsarray of {order_item_id, quantity}; omit to ship everything not yet in a shipment
notify_customerboolean, default false

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/orders/{id}/shipments \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "carrier": "…",
  "tracking_number": "…",
  "tracking_url": "…",
  "items": "…",
  "notify_customer": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders/{id}/shipments", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "carrier": "…",
  "tracking_number": "…",
  "tracking_url": "…",
  "items": "…",
  "notify_customer": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders/{id}/shipments");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "carrier" => "…",
        "tracking_number" => "…",
        "tracking_url" => "…",
        "items" => "…",
        "notify_customer" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/orders/{id}/refund scope: orders:manage

Refund at the payment provider (Stripe/PayPal), full or partial. Only completed, processing, or partially refunded orders; never more than refund_gate.refundable_amount. 502 and no change if the provider call fails.

ParameterDescription
amountdecimal — omit for the full refundable balance
reasonstring, max 500
notify_customerboolean, default true
forceboolean — record the refund even if the provider call fails

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/orders/{id}/refund \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "amount": "…",
  "reason": "…",
  "notify_customer": "…",
  "force": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders/{id}/refund", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "amount": "…",
  "reason": "…",
  "notify_customer": "…",
  "force": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders/{id}/refund");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "amount" => "…",
        "reason" => "…",
        "notify_customer" => "…",
        "force" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/orders/{id}/step scope: orders:manage

Move an order to one of the store's order steps (Settings → Order steps). Moving to the Shipped step marks it shipped; Delivered completes it. Order responses include step and next_step.

ParameterDescription
steprequired — a step key, e.g. packed, shipped, delivered, or the store's own
notify_customerboolean, default false — send the step email if the step has one

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/orders/{id}/step \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "step": "…",
  "notify_customer": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders/{id}/step", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "step": "…",
  "notify_customer": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders/{id}/step");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "step" => "…",
        "notify_customer" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/orders/{id}/cancel scope: orders:manage

Cancel a pending or processing order (revokes downloads; does not move money — use refund).

ParameterDescription
reasonstring, max 500
notify_customerboolean, default true

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/orders/{id}/cancel \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "…",
  "notify_customer": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/orders/{id}/cancel", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "reason": "…",
  "notify_customer": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/orders/{id}/cancel");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "reason" => "…",
        "notify_customer" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Settings & integration health (admin)

GET /admin/settings/shipping scope: settings:read

Shipping configuration: ship-from address, rate source (Shippo or fallback formula), allowed countries, local pickup/delivery radii, label printing and address validation flags. Secrets are reported as configured booleans only.

Request

curl https://dev.kaniva.io/api/v1/admin/settings/shipping \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/settings/shipping", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/settings/shipping");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/integrations/health scope: settings:read

checkout_ready plus configured flags for payments (Stripe Connect / keys / PayPal), shipping, Shippo, PrintNode, Google Maps, Stripe webhook secret, and the go-live checklist.

Request

curl https://dev.kaniva.io/api/v1/admin/integrations/health \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/integrations/health", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/integrations/health");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}

Customers (admin)

GET /admin/customers scope: customers:read

List customers.

Request

curl https://dev.kaniva.io/api/v1/admin/customers \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/customers", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/customers");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/customers/{id} scope: customers:read

Get a customer.

Request

curl https://dev.kaniva.io/api/v1/admin/customers/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/customers/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/customers/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/customers scope: customers:write

Create a customer.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/customers \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/customers", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/customers");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/customers/{id} scope: customers:write

Update a customer.

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/customers/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/customers/{id}", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/customers/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Categories (admin)

GET /admin/categories scope: categories:read

List categories.

Request

curl https://dev.kaniva.io/api/v1/admin/categories \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/categories", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/categories");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/categories/{id} scope: categories:read

Get a category.

Request

curl https://dev.kaniva.io/api/v1/admin/categories/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/categories/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/categories/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/categories scope: categories:write

Create a category.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/categories \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/categories", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/categories");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/categories/{id} scope: categories:write

Update a category.

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/categories/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/categories/{id}", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/categories/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
DELETE /admin/categories/{id} scope: categories:write

Delete a category.

Request

curl -X DELETE https://dev.kaniva.io/api/v1/admin/categories/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/categories/{id}", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/categories/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "DELETE",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "deleted": true }
}

Inventory (admin)

GET /admin/inventory/items scope: inventory:read

List inventory items.

Request

curl https://dev.kaniva.io/api/v1/admin/inventory/items \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/inventory/items", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/inventory/items");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/inventory/items/{id} scope: inventory:read

Get an inventory item.

Request

curl https://dev.kaniva.io/api/v1/admin/inventory/items/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/inventory/items/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/inventory/items/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/inventory/adjust scope: inventory:write

Adjust stock quantity.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/inventory/adjust \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/inventory/adjust", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/inventory/adjust");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Manufacturing — Work Orders (admin)

GET /admin/work-orders scope: manufacturing:read

List work orders (operator pick-list).

ParameterDescription
statusdraft|in_progress|completed|cancelled, or "active" (draft+in_progress)
prioritylow|normal|high|urgent
overdueboolean
work_centerMachine queue — matches the WO or an active operation
assigned_toUser id
order_item_idFilter to a build-to-order line
parent_onlyboolean — top-level WOs only
searchWO number or item name/SKU
due_beforeISO date
due_afterISO date
sortdue_date (default), priority, created_at
per_pageItems per page (max 100)

Request

curl https://dev.kaniva.io/api/v1/admin/work-orders?status=…&priority=…&overdue=…&work_center=…&assigned_to=…&order_item_id=…&parent_only=…&search=…&due_before=…&due_after=…&sort=…&per_page=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders?status=…&priority=…&overdue=…&work_center=…&assigned_to=…&order_item_id=…&parent_only=…&search=…&due_before=…&due_after=…&sort=…&per_page=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders?status=…&priority=…&overdue=…&work_center=…&assigned_to=…&order_item_id=…&parent_only=…&search=…&due_before=…&due_after=…&sort=…&per_page=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/work-orders/{id} scope: manufacturing:read

Get a work order with operations, components, jobs, and a production reconciliation block.

ParameterDescription
bySet to "number" to look up a scanned work_order_number instead of id

Request

curl https://dev.kaniva.io/api/v1/admin/work-orders/{id}?by=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}?by=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}?by=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/start scope: manufacturing:write

Start a work order (checks component stock; auto-creates operation jobs).

ParameterDescription
operator_nameOptional — recorded on the WO

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/start \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "operator_name": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/start", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "operator_name": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/start");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "operator_name" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/complete scope: manufacturing:write

Complete a work order — consumes components, produces finished goods, advances any linked order build stage.

ParameterDescription
operator_nameOptional

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/complete \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "operator_name": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/complete", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "operator_name": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/complete");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "operator_name" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/cancel scope: manufacturing:write

Cancel a work order.

ParameterDescription
reasonOptional — appended to notes

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/cancel \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "reason": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/cancel", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "reason": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/cancel");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "reason" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/pause scope: manufacturing:write

Pause the work order (closes the open labour-time segment; the WO stays in progress).

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/pause \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/pause", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/pause");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/resume scope: manufacturing:write

Resume the work order (opens a new labour-time segment).

ParameterDescription
operator_nameOptional
operation_idOptional — tag the segment to an operation

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/resume \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "operator_name": "…",
  "operation_id": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/resume", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "operator_name": "…",
  "operation_id": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/resume");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "operator_name" => "…",
        "operation_id" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/production scope: manufacturing:write

Log produced/good/scrap quantities against the work order.

ParameterDescription
quantity_goodrequired, int ≥0
quantity_scrapint ≥0
scrap_reasonstring
operation_idOptional — target a specific operation
complete_operationboolean — also complete the targeted operation
operator_nameOptional

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/production \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "quantity_good": "…",
  "quantity_scrap": "…",
  "scrap_reason": "…",
  "operation_id": "…",
  "complete_operation": "…",
  "operator_name": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/production", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "quantity_good": "…",
  "quantity_scrap": "…",
  "scrap_reason": "…",
  "operation_id": "…",
  "complete_operation": "…",
  "operator_name": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/production");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "quantity_good" => "…",
        "quantity_scrap" => "…",
        "scrap_reason" => "…",
        "operation_id" => "…",
        "complete_operation" => "…",
        "operator_name" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/operations/{operationId}/start scope: manufacturing:write

Start an operation (enforces routing order).

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/start \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/start", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/start");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/operations/{operationId}/complete scope: manufacturing:write

Complete an operation and its job.

ParameterDescription
quantity_goodint
quantity_scrapint
notesstring

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/complete \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "quantity_good": "…",
  "quantity_scrap": "…",
  "notes": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/complete", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "quantity_good": "…",
  "quantity_scrap": "…",
  "notes": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/complete");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "quantity_good" => "…",
        "quantity_scrap" => "…",
        "notes" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/work-orders/{id}/operations/{operationId}/skip scope: manufacturing:write

Skip an operation.

ParameterDescription
notesstring

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/skip \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "notes": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/skip", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "notes": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/work-orders/{id}/operations/{operationId}/skip");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "notes" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Blog & how-to articles (admin)

GET /admin/blog/posts scope: blog:read

List posts (newest first).

ParameterDescription
statusdraft or published
categoryCategory id or slug
searchTitle or slug contains
per_page1–100, default 25

Request

curl https://dev.kaniva.io/api/v1/admin/blog/posts?status=…&category=…&search=…&per_page=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/posts?status=…&category=…&search=…&per_page=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/posts?status=…&category=…&search=…&per_page=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/blog/posts/{id} scope: blog:read

Get a post by id or slug, with its HTML content and SEO fields.

Request

curl https://dev.kaniva.io/api/v1/admin/blog/posts/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/posts/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/posts/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/blog/posts scope: blog:write

Create a post. Send content_markdown (converted to HTML) or content_html (sanitised). category and tags may be names; new ones are created. status draft (default) or published; published_at optional.

ParameterDescription
titleRequired
slugMade from the title when blank
excerptUp to 500 characters
content_markdownMarkdown body
content_htmlHTML body (used when no markdown)
categoryCategory id, slug or name
tagsArray of tag names or ids
featured_imageURL from POST /admin/blog/images
featured_image_altAlt text
meta_titleSEO title
meta_descriptionSEO description
meta_keywordsSEO keywords
statusdraft | published
published_atISO 8601, defaults to now when publishing
author_idA staff member id; defaults to the owner

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/blog/posts \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "…",
  "slug": "…",
  "excerpt": "…",
  "content_markdown": "…",
  "content_html": "…",
  "category": "…",
  "tags": "…",
  "featured_image": "…",
  "featured_image_alt": "…",
  "meta_title": "…",
  "meta_description": "…",
  "meta_keywords": "…",
  "status": "…",
  "published_at": "…",
  "author_id": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/posts", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "title": "…",
  "slug": "…",
  "excerpt": "…",
  "content_markdown": "…",
  "content_html": "…",
  "category": "…",
  "tags": "…",
  "featured_image": "…",
  "featured_image_alt": "…",
  "meta_title": "…",
  "meta_description": "…",
  "meta_keywords": "…",
  "status": "…",
  "published_at": "…",
  "author_id": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/posts");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "title" => "…",
        "slug" => "…",
        "excerpt" => "…",
        "content_markdown" => "…",
        "content_html" => "…",
        "category" => "…",
        "tags" => "…",
        "featured_image" => "…",
        "featured_image_alt" => "…",
        "meta_title" => "…",
        "meta_description" => "…",
        "meta_keywords" => "…",
        "status" => "…",
        "published_at" => "…",
        "author_id" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/blog/posts/{id} scope: blog:write

Update any of the create fields; omitted fields are left alone.

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/blog/posts/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/posts/{id}", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/posts/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
DELETE /admin/blog/posts/{id} scope: blog:write

Delete a post.

Request

curl -X DELETE https://dev.kaniva.io/api/v1/admin/blog/posts/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/posts/{id}", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/posts/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "DELETE",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "deleted": true }
}
POST /admin/blog/images scope: blog:write

Upload an image (multipart field file, jpeg/png/gif/webp, up to 10 MB). Returns url to use as featured_image or in the content.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/blog/images \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/images", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/images");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
GET /admin/blog/categories scope: blog:read

List blog categories.

Request

curl https://dev.kaniva.io/api/v1/admin/blog/categories \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/categories", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/categories");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
POST /admin/blog/categories scope: blog:write

Create a category (or return the existing one with that name).

ParameterDescription
nameRequired
descriptionOptional

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/blog/categories \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "…",
  "description": "…"
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/categories", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "name": "…",
  "description": "…"
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/categories");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        "name" => "…",
        "description" => "…"
    ]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
GET /admin/blog/tags scope: blog:read

List blog tags.

Request

curl https://dev.kaniva.io/api/v1/admin/blog/tags \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/blog/tags", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/blog/tags");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}

CRM (admin)

GET /admin/crm/contacts scope: crm:read

List CRM contacts.

Request

curl https://dev.kaniva.io/api/v1/admin/crm/contacts \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/crm/contacts", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/crm/contacts");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/crm/contacts/{id} scope: crm:read

Get a CRM contact.

Request

curl https://dev.kaniva.io/api/v1/admin/crm/contacts/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/crm/contacts/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/crm/contacts/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
GET /admin/crm/tickets scope: crm:read

List support tickets.

Request

curl https://dev.kaniva.io/api/v1/admin/crm/tickets \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/crm/tickets", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/crm/tickets");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/crm/tickets/{id} scope: crm:read

Get a support ticket.

Request

curl https://dev.kaniva.io/api/v1/admin/crm/tickets/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/crm/tickets/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/crm/tickets/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/crm/tickets scope: crm:write

Create a support ticket.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/crm/tickets \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/crm/tickets", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/crm/tickets");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Store & Webhooks (admin)

GET /admin/store/summary any valid key

Store summary statistics (any valid key).

Request

curl https://dev.kaniva.io/api/v1/admin/store/summary \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/store/summary", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/store/summary");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/webhooks/events any valid key

List subscribable webhook event types.

Request

curl https://dev.kaniva.io/api/v1/admin/webhooks/events \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks/events", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks/events");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/webhooks scope: webhooks:read

List webhooks.

Request

curl https://dev.kaniva.io/api/v1/admin/webhooks \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /admin/webhooks/{id} scope: webhooks:read

Get a webhook.

Request

curl https://dev.kaniva.io/api/v1/admin/webhooks/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks/{id}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
GET /admin/webhooks/{id}/deliveries scope: webhooks:read

List delivery attempts for a webhook.

Request

curl https://dev.kaniva.io/api/v1/admin/webhooks/{id}/deliveries \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks/{id}/deliveries", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks/{id}/deliveries");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/webhooks scope: webhooks:write

Create a webhook.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/webhooks \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
PUT /admin/webhooks/{id} scope: webhooks:write

Update a webhook.

Request

curl -X PUT https://dev.kaniva.io/api/v1/admin/webhooks/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks/{id}", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "PUT",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
DELETE /admin/webhooks/{id} scope: webhooks:write

Delete a webhook.

Request

curl -X DELETE https://dev.kaniva.io/api/v1/admin/webhooks/{id} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks/{id}", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks/{id}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "DELETE",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "deleted": true }
}
POST /admin/webhooks/{id}/regenerate-secret scope: webhooks:write

Regenerate the signing secret.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/webhooks/{id}/regenerate-secret \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks/{id}/regenerate-secret", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks/{id}/regenerate-secret");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}
POST /admin/webhooks/{id}/test scope: webhooks:write

Send a test delivery.

Request

curl -X POST https://dev.kaniva.io/api/v1/admin/webhooks/{id}/test \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
}'
const res = await fetch("https://dev.kaniva.io/api/v1/admin/webhooks/{id}/test", {
  method: "POST",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
})
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/admin/webhooks/{id}/test");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS     => json_encode([]),
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Products (storefront)

GET /storefront/products scope: products:read

Public product catalog.

Request

curl https://dev.kaniva.io/api/v1/storefront/products \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/storefront/products", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/storefront/products");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /storefront/products/search scope: products:read

Search products.

ParameterDescription
qsearch query

Request

curl https://dev.kaniva.io/api/v1/storefront/products/search?q=… \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/storefront/products/search?q=…", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/storefront/products/search?q=…");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /storefront/products/{slug} scope: products:read

Get a product by slug.

Request

curl https://dev.kaniva.io/api/v1/storefront/products/{slug} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/storefront/products/{slug}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/storefront/products/{slug}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}

Categories (storefront)

GET /storefront/categories scope: categories:read

Public category list.

Request

curl https://dev.kaniva.io/api/v1/storefront/categories \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/storefront/categories", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/storefront/categories");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": [ { "id": 1 } ],
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1 }
}
GET /storefront/categories/{slug} scope: categories:read

Get a category by slug.

Request

curl https://dev.kaniva.io/api/v1/storefront/categories/{slug} \
  -H "Authorization: Bearer kn_live_…" \
  -H "Accept: application/json"
const res = await fetch("https://dev.kaniva.io/api/v1/storefront/categories/{slug}", {
  method: "GET",
  headers: {
    "Authorization": "Bearer kn_live_…",
    "Accept": "application/json"
  }
});
const data = await res.json();
$ch = curl_init("https://dev.kaniva.io/api/v1/storefront/categories/{slug}");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer kn_live_…",
        "Accept: application/json"
    ],
]);
$data = json_decode(curl_exec($ch), true);

Response

{
  "data": { "id": 1 }
}