Skip to content

Request schema

The data shapes used by the API. Field types follow Elysia's type system and are the same types the web app consumes through Eden Treaty.

The authoritative Elysia request/response models live in apps/api/src/api/models.ts (shared across modules) and in each apps/api/src/modules/<resource>/model.ts (module-local). The plain TypeScript types (the ones used by the core services and the web app's apps/web/src/lib/api/types.ts) live next to their service in apps/api/src/core/<domain>/<domain>.types.ts and are re-exported through apps/api/src/types.tsapps/api/src/types/domain.ts. This page is a guided tour of those types, with a focus on what each field means in practice.

HttpMethod

ts
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS'

The seven methods Rewind knows about. Anything else is rejected at validation time. The order matches the request area's method picker.

KeyValuePair

ts
interface KeyValuePair {
  key: string
  value: string
  enabled: boolean
  secret?: boolean
  description?: string
}

The shape of a row in the Params, Headers, URL-encoded, and form-data tables, and of an environment variable row. enabled: false rows are stored and shown but ignored at send time. secret: true rows have their value masked in the UI, history, and normal exports. description is free-form and only displayed as a tooltip in the editor.

AuthConfig

The discriminated union that powers the Auth tab.

ts
type AuthConfig =
  | { type: 'none' }
  | { type: 'bearer'; token: string }
  | { type: 'basic'; username: string; password: string }
  | { type: 'apiKey'; placement: 'header' | 'query'; key: string; value: string }
  | {
      type: 'oauth2'
      grantType: 'authorization_code' | 'client_credentials' | 'manual'
      tokenUrl: string
      clientId: string
      clientSecret: string
      scope: string
      accessToken: string
    }

oauth2.client_credentials makes the server call the token URL on your behalf; the others expect a pre-existing accessToken. See Authentication for the full semantics.

RequestBodyConfig

The discriminated union that powers the Body tab.

ts
type RequestBodyConfig =
  | { mode: 'none' }
  | { mode: 'raw'; contentType: string; value: string }
  | { mode: 'urlencoded'; fields: KeyValuePair[] }
  | { mode: 'multipart'; fields: MultipartField[] }
  | { mode: 'binary'; attachmentId: string }

type MultipartField =
  | (KeyValuePair & { kind: 'text' })
  | { kind: 'file'; key: string; attachmentId: string; enabled: boolean; description?: string }

For multipart, the text fields are inline values and the file fields reference an attachment by ID. For binary, the body is the attachment's file contents.

ApiRequestDraft

The wire shape of a request — the body of POST /api/v1/requests/send and the value of Request.CreateInput.body.

ts
interface ApiRequestDraft {
  method: HttpMethod
  url: string
  headers: KeyValuePair[]
  queryParams: KeyValuePair[]
  body?: RequestBodyConfig
  auth?: AuthConfig
  environmentId?: string
  timeoutMs?: number       // 100 to 300_000
  followRedirects?: boolean
  maxRedirects?: number    // 0 to 20
  cookieJarId?: string
}

environmentId selects the environment used for {{placeholder}} resolution. If omitted, the request area's active environment is used. timeoutMs defaults to 30 000 ms.

SavedRequest

A SavedRequest is an ApiRequestDraft plus identity, ordering, and revision fields:

ts
interface SavedRequest extends ApiRequestDraft {
  id: string
  collectionId: string
  folderId?: string | null
  name: string
  description: string
  sortOrder: number
  revision: number         // >= 1
  createdAt: string        // ISO timestamp
  updatedAt: string        // ISO timestamp
}

revision increments on every successful save. Update requests must echo the revision the client opened in expectedRevision; the server returns 409 otherwise.

Collection

ts
interface Collection {
  id: string
  name: string
  description: string
  createdAt: string
  updatedAt: string
  folders: Folder[]
  requests: SavedRequest[]
}

A collection always includes its full set of folders and requests in a single response. There is no pagination here — the counts are expected to be small.

Folder

ts
interface Folder {
  id: string
  collectionId: string
  name: string
  parentId?: string | null  // null = collection root
  sortOrder: number
  createdAt: string
  updatedAt: string
}

parentId: null means the folder is at the collection root. parentId: 'null' (string) is not allowed.

Environment

ts
interface Environment {
  id: string
  name: string
  isActive: boolean        // exactly one environment per workspace is active
  createdAt: string
  updatedAt: string
  variables: EnvironmentVariable[]
}

interface EnvironmentVariable {
  id: string
  environmentId: string
  key: string
  value: string
  enabled: boolean
  secret: boolean
}

Attachment

ts
interface Attachment {
  id: string
  name: string
  contentType: string
  sizeBytes: number
  createdAt: string
}

The path is server-side only and is never returned over the API. The actual file is fetched by ID with GET /api/v1/attachments/:id.

SendResult (v1) and SendResultV2 (v2)

The v1 send response is a flat object:

ts
interface SendResult {
  id: string
  requestId?: string | null
  method: HttpMethod
  url: string
  status: number
  statusText: string
  headers: Record<string, string>
  body: string             // text body; large/binary responses get a placeholder
  durationMs: number
  sizeBytes: number
  createdAt: string
}

The v2 response wraps the body in an envelope with metadata:

ts
interface SendResultV2 extends Omit<SendResult, 'body' | 'headers'> {
  headers: Array<{ key: string; value: string }>   // ordered, with set-cookie at the end
  redirects: Array<{ status: number; url: string; location: string }>
  body: {
    kind: 'text' | 'json' | 'xml' | 'html' | 'image' | 'binary'
    contentType: string
    charset?: string
    inline?: string
    bodyUrl?: string         // points to GET /api/v2/history/:id/body
    truncated: boolean
    sizeBytes: number
    storageState: 'stored' | 'omitted_limit' | 'missing'
  }
}

v2 is what the request area uses. v1 is still around for backward compatibility and the runner's simpler output.

HistorySummary and HistoryDetail

The history list returns HistorySummary (one row per entry):

ts
interface HistorySummary {
  id: string
  requestId?: string | null
  collectionId?: string | null
  name: string
  method: HttpMethod
  url: string
  status?: number | null
  durationMs?: number | null
  sizeBytes?: number | null
  createdAt: string
  outcome?: 'success' | 'http_error' | 'network_error'
}

A detail entry is a summary plus the full request, response, ordered headers, redirects, and an optional error:

ts
interface HistoryDetail extends HistorySummary {
  request: ApiRequestDraft
  response?: SendResult
  orderedHeaders?: Array<{ key: string; value: string }>
  redirects?: Array<{ status: number; url: string; location: string }>
  error?: { category: string; message?: string }
  body?: SendResultV2['body']
}

response is the v1 shape; body is the v2 envelope.

NetworkSettings

The settings on the Settings → Global network section.

ts
interface NetworkSettings {
  proxyUrl: string
  proxyAuthorization: string
  rejectUnauthorized: boolean
  caAttachmentId: string
  certAttachmentId: string
  keyAttachmentId: string
}

The three attachment IDs reference PEM files in the attachments table.

StorageSettings

ts
interface StorageSettings {
  previewBytes: number             // >= 1
  maxStoredResponseBytes: number   // >= 1
  maxHistoryBytes: number          // >= 1
  maxHistoryEntries: number        // >= 1
}

See Data and storage for the defaults and what they do.

Workspace

ts
interface WorkspaceExport {
  version: 2
  exportedAt: string
  collections: Collection[]
  environments: Environment[]
  history: HistoryDetail[]
  settings: Record<string, unknown>
}

The version field is always 2 for current exports. The WorkspaceImport union also accepts version: 1 for legacy JSON workspace exports.

What's next?

Released under the MIT License.