Errors
SDK methods never throw. They return a `Result` whose error branch is a typed `CimplifyError` with a stable `code`, a human-readable `message`, an optional `retryable` hint, and structured `context`.
The shape
class CimplifyError {
code: string; // e.g. "VALIDATION_ERROR"
message: string; // human-readable
retryable?: boolean; // safe to retry with backoff?
context?: Record<string, unknown>; // structured detail (field path, limits, …)
}Reading an error
const r = await client.cart.addItem({ item_id: "missing", quantity: 1 });
if (!r.ok) {
console.error(r.error.code); // "NOT_FOUND"
console.error(r.error.message); // "Product missing was not found"
console.error(r.error.context); // { item_id: "missing", business_id: "bus_…" }
return;
}Common codes
| Code | HTTP | Retryable | Meaning |
|---|---|---|---|
VALIDATION_ERROR | 400 | No | Body failed schema or constraint checks. context.field points at the offender. |
UNAUTHORIZED | 401 | No | Missing, malformed, or revoked API key. |
FORBIDDEN | 403 | No | Key is valid but lacks scope for this resource. |
NOT_FOUND | 404 | No | Resource doesn't exist or isn't visible to this business. |
BUSINESS_RULE_VIOLATION | 422 | No | Domain invariant rejected the request; show the message to the user. |
RATE_LIMITED | 429 | Yes | context.retry_after_ms tells you how long to back off. |
NETWORK_ERROR | Yes | Request didn't reach the server. | |
SERVER_ERROR | 5xx | Yes | Backend faulted. Use exponential backoff. |
Retry semantics
The SDK retries network errors and 5xx responses automatically with capped exponential backoff. You handle retryable === false codes; those are the ones the user needs to see or fix.
const r = await client.cart.addItem(payload);
if (!r.ok) {
if (r.error.retryable) {
// SDK already retried; surface a soft message.
toast.warn("Connection issue, please try again.");
} else {
switch (r.error.code) {
case "NOT_FOUND":
toast.error("That item is no longer available.");
break;
case "BUSINESS_RULE_VIOLATION":
toast.error(r.error.message);
break;
case "VALIDATION_ERROR":
// r.error.context.field tells you which input is wrong.
focusField(r.error.context?.field as string);
break;
default:
toast.error(r.error.message);
}
}
}Schema violations from the test harness
Inside tests, assertCart, assertBrand, and friends throw SchemaViolationError instead of returning a Result. The structured issues[] and RFC 7807 toJSON() let agents and CI surface the exact field path that drifted.
import { assertCart, SchemaViolationError } from "@cimplify/sdk/testing";
try {
assertCart(response);
} catch (err) {
if (err instanceof SchemaViolationError) {
console.error(err.toJSON()); // { type, title, status, detail, errors[] }
}
}Next
-
Error codes reference Full table with retry rules
-
Result How errors flow through the SDK
Idempotency
Every write method on the SDK accepts an optional `{ idempotencyKey }` as its second argument. Replays of the same key against the same body return the original response and never a duplicate side effect.
Webhooks
Cimplify pushes order, payment, and booking lifecycle events to your endpoint as JSON over HTTPS. Every delivery is HMAC-signed and replayed with exponential backoff if your server doesn't return a 2xx within 30 seconds.