Build on Vendu.
Integrate orders, products, and conversations into your stack. REST API with cursor pagination, sparse fieldsets, ETag caching, and RFC 7807 error details.
Quickstart
Three steps to your first API call.
- 1
Generate an API key
Go to Dashboard → Settings → Developers and click Generate new key. Copy the
vk_live_…token — it is shown only once. - 2
Make your first request
Use any HTTP client. The example below lists your most recent orders.
- 3
Handle the response
All list responses follow the
ListEnvelopeshape withdata[],has_more, andnext_cursorfor pagination.
curl https://api.vendu.app/api/v1/orders \
-H "Authorization: Bearer vk_live_YOUR_KEY" \
-H "Accept: application/json"Authentication
Every request must include a Bearer token in the Authorization header.
Keys are tenant-scoped — one key can never read another tenant's data.
Keys support scope restrictions: create read-only keys for third-party integrations.
Missing or invalid token → 401 authentication-required. Revoked token → 403 invalid-api-key.
Webhooks
Vendu posts JSON events to your registered URL when things happen in your tenant. All payloads share the same envelope shape.
Verifying the signature
Every request carries an X-Vendu-Signature header — HMAC-SHA256 of the raw body with your endpoint secret.
import { createHmac, timingSafeEqual } from 'crypto';
function verifyVenduWebhook(
rawBody: string,
signature: string,
secret: string,
): boolean {
const expected = createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const a = Buffer.from(signature);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}Register endpoints at Dashboard → Settings → Webhooks.
Rate Limits
Sliding-log per API key over a 60-second window. Two independent buckets: Read (GET / HEAD) and Write (POST / PUT / PATCH / DELETE).
| Plan | Read / min | Write / min |
|---|---|---|
| free | 30 | 5 |
| starter | 60 | 15 |
| professional | 120 | 30 |
| business | 300 | 60 |
| enterprise | 600 | 120 |
On block: 429 Too Many Requests + Retry-After + X-RateLimit-* headers.
Bulk endpoints consume one write slot regardless of batch size.
Error Catalog
All errors follow RFC 7807 Problem Details with Content-Type: application/problem+json. Switch on the stable type URI slug.
| Type slug | HTTP | When |
|---|---|---|
| authentication-required | 401 | No / malformed Authorization header. |
| invalid-api-key | 403 | Token revoked or does not match a tenant. |
| insufficient-scope | 403 | API key missing required scope (e.g. write). |
| rate-limit-exceeded | 429 | Per-API-key window exhausted. retry_after_sec set. |
| validation-failed | 422 | Request body / params failed schema validation. errors[] enumerates field problems. |
| resource-not-found | 404 | Resource missing or not accessible to this tenant. |
| conflict | 409 | Domain-level conflict (e.g. duplicate idempotency key). |
| precondition-failed | 412 | If-Match / If-Unmodified-Since failed. |
| payload-too-large | 413 | Body exceeds the route limit (e.g. bulk > 100 items). |
| internal-error | 500 | Unexpected server error. Use trace_id for triage. |
| service-unavailable | 503 | Downstream dependency (DB / Redis / QStash) degraded. |
Pagination
All list endpoints use cursor-based pagination. Pass ?cursor= + ?limit= (default 50, max 100). The response includes next_cursor when has_more is true.
?offset= pagination is accepted until 2026-07-31 (Deprecation + Sunset headers emitted). Migrate to cursor before that date.Ready to integrate?
Browse the full interactive API reference, try the console with your key, or check the changelog for recent changes.