All docs

Error Codes

Every API failure returns a structured body with an appropriate HTTP status. The code and message are nested under a top-level error key:

{ "error": { "code": "CONFLICT", "message": "schedule already fired" } }

The SDK unwraps this and surfaces the same information as a SendItError:

import { SendItError } from "@sendithq/sdk";

try {
  await sendit.reschedule("sch_123", { in: "1h" });
} catch (err) {
  if (err instanceof SendItError) {
    err.code;   // e.g. "CONFLICT"
    err.status; // e.g. 409 — undefined for network failures
  }
}

Codes

Code HTTP Meaning What to do
VALIDATION 400 Input failed validation — bad fireAt, oversized payload, malformed URL, reserved header. Fix the request. The message names the problem.
UNAUTHORIZED 401 Missing, malformed, revoked key, or deactivated account. Check the key; re-issue if needed.
FORBIDDEN 403 Allowed to authenticate but not to do this — e.g. monthly schedule quota exhausted (past the 10% grace), blocked target, or a session-only action attempted with an API key. Upgrade plan, fix the target, or use session login.
NOT_FOUND 404 No such schedule/resource, or it isn't yours. Verify the id.
CONFLICT 409 State conflict — e.g. rescheduling a schedule that already fired. Re-read current state before acting.
RATE_LIMITED 429 Too many requests from this key or IP. Back off and retry; the SDK retries idempotent calls automatically.
INTERNAL 500 Server-side error. Retry later; details are intentionally not exposed.
NETWORK The request never reached us (DNS, connection, timeout). status is undefined. Retry; idempotent calls and keyed schedules are retried by the SDK.

How the SDK retries

The SDK retries automatically, but only where it's safe:

  • Idempotent callslist, get, getAttempts, cancel, and any schedule/scheduleMany carrying idempotency keys — are retried on NETWORK failures and 5x (INTERNAL) responses, up to maxRetries with exponential backoff.
  • Non-idempotent callsreschedule, replay, clone, and a schedule without an idempotencyKey — are not retried, to avoid firing twice. A failure throws immediately.

Add an idempotencyKey to make schedule/scheduleMany safely retriable. See Scheduling.

Common cases

  • VALIDATION on fireAt — the time is in the past or missing a timezone offset. Use an explicit offset (Z or +09:00).
  • VALIDATION on payload — it exceeds your plan's size cap. See Plans & Limits.
  • FORBIDDEN on create — you've used your full monthly schedule quota plus the 10% grace, or the target resolves to a blocked address (see Security). Check GET /v1/usage to see where you stand.
  • CONFLICT on reschedule — the schedule already fired or was cancelled; it's no longer scheduled.