CloudrawAPI v0
Menu

Guide

Errors

Errors use HTTP status codes and an RFC 9457 problem body (Content-Type: application/problem+json).

404 · application/problem+json
{
  "type": "https://cloudraw.com/problems/person-not-found",
  "code": "person-not-found",
  "title": "person not found",
  "status": 404,
  "detail": null
}
FieldUse
codeStable, machine-readable. Switch on this. A code is never renamed within v0.
typeThe same code as a URI.
title, detailFor people (logs, error messages). Wording may change; do not parse it.
errorsOn validation errors: [{ "path": "email", "message": "…" }] per field, when available.
retry_after_sOn 429 and 503: seconds to wait (also in the Retry-After header).

Status codes

StatusMeaningRetry?
200, 201Done; the body is the result.—
202Accepted. The body is a task: state: "done" when the change already happened.—
204Done, no body.—
400The request is invalid (see code and errors).No — fix the request.
401Missing, unknown, revoked or expired token.No.
403The token may not do this (scope, role ceiling, console-only).No.
404Not found. An id from another workspace also answers 404.No.
409Conflict with the current state (e.g. version-conflict, idempotency-key-reuse, a feature not set up yet).After re-reading the state.
429Rate limited.Yes, after Retry-After.
500, 502Our fault, or a system we depend on failed.Yes, with backoff (and an Idempotency-Key).
503busy: Cloudraw is switching servers or cannot save right now.Yes, after Retry-After (usually 2–10 s).

A retry helper

Python
import time, uuid, requests

def call(s, method, url, **kw):
    """Retry 429 / 503 / network errors; one Idempotency-Key for every attempt of a POST."""
    if method == "POST":
        kw.setdefault("headers", {})["Idempotency-Key"] = str(uuid.uuid4())
    for attempt in range(5):
        try:
            r = s.request(method, url, timeout=30, **kw)
        except requests.ConnectionError:
            time.sleep(2 ** attempt); continue
        if r.status_code in (429, 503) or r.status_code >= 500:
            time.sleep(int(r.headers.get("Retry-After", 2 ** attempt))); continue
        if r.status_code >= 400:
            p = r.json()
            raise RuntimeError(f"{p['status']} {p['code']}: {p.get('detail')}")
        return r.json() if r.content else None
    raise RuntimeError("gave up after 5 attempts")
Node.js
export async function call(method, url, body) {
  const headers = { Authorization: `Bearer ${process.env.CLOUDRAW_TOKEN}` };
  if (method === "POST") headers["Idempotency-Key"] = crypto.randomUUID();   // same key for every attempt
  if (body !== undefined) headers["Content-Type"] = "application/json";
  for (let attempt = 0; attempt < 5; attempt++) {
    let res;
    try { res = await fetch(url, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) }); }
    catch { await new Promise((r) => setTimeout(r, 2 ** attempt * 1000)); continue; }
    if (res.status === 429 || res.status >= 500) {
      await new Promise((r) => setTimeout(r, Number(res.headers.get("retry-after") || 2 ** attempt) * 1000));
      continue;
    }
    if (!res.ok) { const p = await res.json(); throw new Error(`${p.status} ${p.code}: ${p.detail ?? ""}`); }
    return res.status === 204 ? null : res.json();
  }
  throw new Error("gave up after 5 attempts");
}
PowerShell
function Invoke-Cloudraw($Method, $Uri, $Body) {
  $h = @{ Authorization = "Bearer $env:CLOUDRAW_TOKEN" }
  if ($Method -eq 'Post') { $h['Idempotency-Key'] = [guid]::NewGuid().ToString() }
  for ($i = 0; $i -lt 5; $i++) {
    try {
      if ($Body) { return Invoke-RestMethod -Method $Method -Uri $Uri -Headers $h -ContentType 'application/json' -Body ($Body | ConvertTo-Json -Depth 10) }
      return Invoke-RestMethod -Method $Method -Uri $Uri -Headers $h
    } catch {
      $r = $_.Exception.Response
      if ($r -and ([int]$r.StatusCode -eq 429 -or [int]$r.StatusCode -ge 500)) {
        $wait = 2 * ($i + 1); if ($r.Headers['Retry-After']) { $wait = [int]$r.Headers['Retry-After'] }
        Start-Sleep -Seconds $wait; continue
      }
      throw
    }
  }
}