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.ts → apps/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
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
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.
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.
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.
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:
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
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
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
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
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:
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:
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):
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:
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.
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
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
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?
- API surface — the routes that use these types
- Environment variables — the env vars
- Architecture — the higher-level data flow