Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.neuraldraft.io/llms.txt

Use this file to discover all available pages before exploring further.

Every error response from the v1 API follows RFC 7807 application/problem+json. Branch on the code field — it’s stable. The title and detail are for humans and may be reworded over time.

Shape

{
  "type": "https://api.neuraldraft.io/errors/validation_failed",
  "title": "Validation failed",
  "status": 422,
  "code": "validation_failed",
  "detail": "One or more fields failed validation.",
  "instance": "req_2Nh4PqRsTuVw",
  "errors": {
    "customer_email": ["The customer email field must be a valid email."],
    "starts_at": ["The starts at field must be a valid ISO 8601 date."]
  }
}
FieldNotes
typeURI describing the error class. Stable, dereferenceable.
titleHuman-readable summary. Don’t pattern-match on this.
statusHTTP status code (mirrors the response status).
codeStable machine identifier. Branch on this.
detailHuman-readable explanation of this particular error.
instanceRequest id. Also returned as the X-Request-Id response header.
errorsField-level errors (only on 422).
Always log the instance (request id) — when you open a support ticket, that’s the first thing we’ll ask for.

Code catalog

HTTPcodeMeaningRetry?
400bad_requestMalformed request — invalid JSON, missing required body field, wrong method.No. Fix the request.
401unauthorizedMissing, malformed, expired, or revoked API key.No. Re-issue the key.
402out_of_creditsProject balance is zero. Top up or upgrade.No, until credits are added.
403forbiddenKey is valid but lacks the required scope.No. Re-issue with the missing scope.
404not_foundResource does not exist (or your key can’t see it).No.
409conflictGeneric conflict — e.g. slug already taken, key limit reached.Sometimes. Read detail.
409slot_unavailableBooking slot was taken between availability check and create.Yes — refresh availability.
409idempotency_conflictIdempotency key reused with different parameters.No. Use a fresh key or match params.
409connect_not_readyStripe Connect not onboarded; checkout cannot be created.No, until Connect is set up.
422validation_failedOne or more fields failed validation. See errors map.No. Fix and resend.
429rate_limitedPer-project rate limit exceeded. Honour Retry-After.Yes — exponential backoff.
500internal_errorServer bug. We’re paged.Yes — exponential backoff, alert.
502upstream_unavailableUpstream AI provider error (model, image gen, etc.). Often transient.Yes — exponential backoff.
503service_unavailableMaintenance or transient outage. Honour Retry-After.Yes — exponential backoff.

out_of_credits

The most common failure for active projects. The response includes the credit delta required:
{
  "type": "https://api.neuraldraft.io/errors/out_of_credits",
  "title": "Out of credits",
  "status": 402,
  "code": "out_of_credits",
  "detail": "This operation requires 400 credits but the project balance is 12. Top up or upgrade your plan.",
  "instance": "req_2Nh4PqRsTuVw"
}
Subscribe to the project.credits_low webhook (fired at 20% remaining) and the project.credits_exhausted event (fired the moment the first 402 fires) — both let you alert your team or auto-top-up.

validation_failed

Field-level errors are returned as an errors map; arrays of strings keyed by the offending field. Mirror the keys back to the user.
{
  "code": "validation_failed",
  "status": 422,
  "errors": {
    "customer_email": ["The customer email field must be a valid email."],
    "starts_at": ["The starts at field must be a valid ISO 8601 date."]
  }
}

rate_limited

The response carries Retry-After (seconds) and the standard rate-limit headers. See rate-limits for the full backoff strategy.

slot_unavailable

A booking-specific 409: the slot was taken between the time you ran an availability check and the time you posted the booking. Refresh availability and let the user pick again. Don’t auto-retry.

Retry strategy

For retryable error classes, use exponential backoff with full jitter. Cap retries at 5 attempts; cap any single delay at 30 seconds.
async function withRetry<T>(
  fn: () => Promise<T>,
  options: { maxAttempts?: number; baseMs?: number; capMs?: number } = {}
): Promise<T> {
  const { maxAttempts = 5, baseMs = 250, capMs = 30_000 } = options;
  let attempt = 0;
  let lastError: unknown;
  while (attempt < maxAttempts) {
    try {
      return await fn();
    } catch (err: any) {
      lastError = err;
      const status = err?.status;
      const code = err?.body?.code;
      const retryable =
        status === 429 ||
        status === 502 ||
        status === 503 ||
        code === "upstream_unavailable";
      if (!retryable) throw err;

      const retryAfter = Number(err?.headers?.["retry-after"]);
      const expBackoff = Math.min(capMs, baseMs * 2 ** attempt);
      const jittered = Math.random() * expBackoff;
      const delay = Number.isFinite(retryAfter)
        ? retryAfter * 1000
        : jittered;
      await new Promise((r) => setTimeout(r, delay));
      attempt++;
    }
  }
  throw lastError;
}
A few rules of thumb:
  • Never retry 400, 401, 403, 404, 409 (except slot_unavailable, which means “refresh and let the user choose”), or 422. They are deterministic.
  • Always honour Retry-After if present; the platform sets it precisely.
  • Long-running jobs are submitted via 202 Accepted and tracked via /jobs/{id}. The submit call is idempotent if you pass an Idempotency-Key; the job itself is the right place to handle failures, not the submit endpoint.

Idempotency

POST and other mutating endpoints accept an Idempotency-Key header (any unique string up to 255 chars). Retries with the same key within 24 hours return the original response without re-executing the side effect.
curl -X POST https://api.neuraldraft.io/v1/blog-posts \
  -H "Authorization: Bearer $NEURAL_DRAFT_API_KEY" \
  -H "Idempotency-Key: post-$(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"title":"Hello","content":"<p>Hi</p>","language_code":"en"}'
If you reuse a key with different parameters (different body, different path), the request fails with 409 idempotency_conflict. Use one key per logical operation; UUIDs are fine.

When to ask for help

Open a ticket with support@neuraldraft.io or the dashboard support widget and include:
  1. The instance (request id) — also X-Request-Id on the response.
  2. The exact request URL and method.
  3. The response status and code.
  4. The approximate timestamp (UTC).
We’ll trace the request end-to-end and respond within one business day on the free tier, four hours on Build, and one hour on Scale.