API reference

Base URL https://app.herald.run; versioned endpoints live under /api/v1. Send the connection token as Authorization: Bearer hdr_…; your identity and account come from the token, never the request body. JSON bodies are limited to 128 KiB.

The machine-readable description is openapi.json (OpenAPI 3.1), generated from the same schemas the server validates with. Point a client generator or API tool at it.

Scopes

Scope Grants
messages:send Send, cancel, run tasks, deliver secrets
messages:read Read messages, threads, logs, files; collect secrets
destinations:manage Register and manage destinations
events:read The live socket
files:write Upload files

Endpoints marked human need a signed-in app session and reject connection tokens.

Account

EndpointAccessBodyResponse
GET /api/ping
Liveness and server version
public200 Ping
GET /api/v1/token
The calling token, its scopes and account
any token200 TokenInfo
DELETE /api/v1/token
Revoke the calling token
any token204
GET /api/v1/account
Plan, usage and reset date
any token200 Account
PATCH /api/v1/account
Rename the account
human{ name }200 Account
DELETE /api/v1/account
Delete the account and all its data
human{ confirm }204
GET /api/v1/account/export
Download every account record as JSON
human200 { }

Messages

EndpointAccessBodyResponse
POST /api/v1/messages
Send a message, request or form
messages:sendSealedMessageInput201 Message
GET /api/v1/messages
List messages (newest first) or the revision feed
messages:read200 Message | Tombstone[]
GET /api/v1/messages/{id}
A full message or task
messages:read200 Message
PATCH /api/v1/messages/{id}
Human: mark read
human{ read }200 { ok }
DELETE /api/v1/messages/{id}
Human: delete content and unshared files
human200 { ok }
POST /api/v1/messages/{id}/cancel
Cancel a pending request
messages:send200 Message
GET /api/v1/messages/{id}/thread
Thread messages, oldest first, 100 per page
messages:read200 { messages, next }
GET /api/v1/messages/{id}/logs
Task logs
messages:read200 { logs }
POST /api/v1/messages/{id}/response
Answer a request once
humanSealedResponseInput200 Message
POST /api/v1/messages/{id}/secrets
Collect sealed secret answers once (15 min)
messages:read200 object
GET /api/v1/messages/{id}/secret-receiver
Sender: the human device waiting for a secret
messages:read200 { claimId, publicKey, sig, received }
POST /api/v1/messages/{id}/secret-receiver
Human: claim a secret offer with a device key
human{ claimId, publicKey, sig }200 { ok }
POST /api/v1/messages/{id}/secret-delivery
Sender: deliver the encrypted secret
messages:send{ claimId, envelope }200 { ok }
POST /api/v1/messages/{id}/secret-receive
Human: consume the delivered secret
human{ claimId }200 { envelope, pending }
POST /api/v1/messages/sync
Human: current records for up to 100 IDs
human{ ids }200 Message[]

Tasks

EndpointAccessBodyResponse
POST /api/v1/outbox
Human: dispatch a task to a destination
humanSealedOutboxInput201 Message
POST /api/v1/tasks/{id}/claim
Pull runner: claim a queued task
messages:send{ runnerId, heartbeat }200 { lease, leaseExpiresAt, task }
POST /api/v1/tasks/{id}/heartbeat
Pull runner: renew the lease (every 60 s)
messages:send{ lease }200 { lease, leaseExpiresAt }
POST /api/v1/tasks/{id}/update
Runner: append logs, complete or fail
messages:send{ lease, status, errorSealed, logs }200 Message

Destinations

EndpointAccessBodyResponse
GET /api/v1/destinations
List destinations
destinations:manage200 Destination[]
POST /api/v1/destinations
Register a destination; a repeated key updates it
destinations:manageDestinationInput201 Destination
PUT /api/v1/destinations/{id}
Replace a destination
destinations:manageDestinationInput200 Destination
DELETE /api/v1/destinations/{id}
Remove a destination and cancel its queued tasks
destinations:manage200 { ok }
POST /api/v1/destinations/{id}/secret
Rotate a webhook signing secret (returned once)
destinations:manage200 Destination

Files

EndpointAccessBodyResponse
POST /api/v1/files
Reserve an upload (≤100 MB, 15 min)
files:write{ name, type, size }201 Attachment
PUT /api/v1/files/{id}
Upload the exact reserved bytes once
files:writebytes200 Attachment
GET /api/v1/files/{id}
Download a file
messages:read200

Connections

EndpointAccessBodyResponse
GET /api/v1/integrations
List connections
any token200 Integration[]
POST /api/v1/integrations
Create a connection; the token is returned once
human{ name, scopes, certificate }201 { token, integration }
PATCH /api/v1/integrations/{id}
Rename or recolor a connection
human{ name, color }200 Integration
DELETE /api/v1/integrations/{id}
Revoke a connection and its destinations
human200 { ok }
POST /api/v1/ws-ticket
One-time socket ticket (30 s)
human200 { ticket }

Encryption

EndpointAccessBodyResponse
GET /api/v1/keys
The account statement and connection certificates
messages:read200 KeyDirectory
PUT /api/v1/keys/account
Publish the account statement (201 new, 200 same identity)
humanAccountKeys201 AccountKeys
DELETE /api/v1/keys/account
Turn end-to-end encryption off and delete every key record
human{ confirm }204
GET /api/v1/keys/backups
Wrapped keyring backups
human200 { backups }
PUT /api/v1/keys/backups/{id}
Store a wrapped keyring (at most 10)
human{ wrapped }200 KeyBackup
DELETE /api/v1/keys/backups/{id}
Delete a backup
human204
PUT /api/v1/keys/device-code/{code}
Certify CLI keys for a device user code (15 min)
humanCertificate200 Certificate
GET /api/v1/keys/device-code/{code}
CLI: fetch its certificate once
human200 Certificate
POST /api/v1/keys/devices
Locked device: ask another device for the keyring (15 min)
human{ label, commit }201 PendingDevice
GET /api/v1/keys/devices
Devices waiting for approval
human200 { devices }
GET /api/v1/keys/devices/{id}
A pending device; the envelope once approved
human200 PendingDevice
DELETE /api/v1/keys/devices/{id}
Reject a pending device; again to remove it
human204
POST /api/v1/keys/devices/{id}/challenge
Approver: send a nonce (waiting → challenged)
human{ nonce }200 PendingDevice
POST /api/v1/keys/devices/{id}/reveal
Locked device: open the commitment (challenged → revealed)
human{ transfer, nonce }200 PendingDevice
POST /api/v1/keys/devices/{id}/approve
Approver: send the keyring envelope (revealed → approved)
human{ envelope }200 PendingDevice

Schemas

MessageInput

FieldType
title requiredstring
bodystring
runIdstring
checkpointIdstring
taskIdstring
replyTostring
requiresReviewboolean
groupstring
expiresAtstring
expiresInnumber
kind"message" | "form" | "report" | "files"
fieldsField[]
schemaobject
questions{ question, header, options, multiSelect }[]
blocksReviewBlock[]
actionsAction[]
attachmentsAttachment[]
publicKeyPublicKey

or

FieldType
title requiredstring
bodystring
runIdstring
checkpointIdstring
taskIdstring
replyTostring
requiresReviewboolean
groupstring
expiresAtstring
expiresInnumber
kind required"secret"
fieldsany
attachmentsany
schemaany
questionsany
blocksany
actionsany
publicKeyany

Field

FieldType
id requiredstring
label requiredstring
headerstring
type required"text" | "textarea" | "number" | "select" | "multiselect" | "boolean" | "date" | "secret" | "file"
defaultstring | number | boolean | string[] | null
nullableboolean
uniqueItemsboolean
integerboolean
minimumnumber
maximumnumber
exclusiveMinimumnumber
exclusiveMaximumnumber
minLengthinteger
maxLengthinteger
minItemsinteger
maxItemsinteger
requiredboolean
secretboolean
helpstring
placeholderstring
options{ value, label, description, preview }[]
otherboolean

Action

FieldType
id requiredstring
label requiredstring
values requiredobject

ReviewBlock

FieldType
type required"code" | "diff" | "json"
titlestring
requiresReviewboolean
language"text" | "sql" | "javascript" | "typescript" | "python" | "json"
text requiredstring

or

FieldType
type required"table"
titlestring
requiresReviewboolean
columns requiredstring[]
rows requiredstring[][]

or

FieldType
type required"image"
titlestring
requiresReviewboolean
attachmentId requiredstring
alt requiredstring

Attachment

FieldType
id requiredstring
name requiredstring
size requiredinteger
type requiredstring

PublicKey

FieldType
kty required"RSA"
n requiredstring
e required"AQAB"
alg"RSA-OAEP-256"
extboolean
key_ops"encrypt"[]

Envelope

FieldType
key requiredstring
iv requiredstring
data requiredstring

DestinationInput

FieldType
keystring
transport{ kind } | { kind, url }
descriptionstring
types requiredRequestType[]

RequestType

FieldType
id requiredstring
label requiredstring
descriptionstring
fieldsField[]
kind"session"
session{ prompt, attachments, modes, model, effort, commands }

SessionInput

FieldType
prompt requiredstring
modesobject
modelstring
effortstring
command{ id, arguments }
attachmentsstring[]

ResponseInput

FieldType
values requiredobject
actionIdstring
secretsobject

ConnectionColor

FieldType
mode required"auto"

or

FieldType
mode required"neutral"

or

FieldType
mode required"custom"
hue requirednumber
saturation requirednumber

SealedEnvelope

FieldType
v required1
ctx required{ t, account }
from requiredstring
to required{ kid, enc, key }[]
iv requiredstring
ct requiredstring
sig requiredstring

SealedMessageInput

FieldType
id requiredstring
kind"message" | "secret"
sealed requiredSealedEnvelope
digest requiredstring
asks requiredboolean
attachments{ id }[]
taskIdstring
replyTostring
expiresAtstring
expiresInnumber

SealedResponseInput

FieldType
sealed requiredSealedEnvelope
secretsobject
filesstring[]
secretFilesstring[]

SealedOutboxInput

FieldType
id requiredstring
destinationId requiredstring
typeId requiredstring
sealed requiredSealedEnvelope
filesstring[]
grants{ message, kid, enc, key }[]
replyTostring
expiresInnumber

AccountKeys

FieldType
statement required{ v, account, identity, inbox, created }
sig requiredstring

Certificate

FieldType
certificate required{ v, account, kid, sign, box, created }
sig requiredstring

WrappedKeyring

FieldType
v required1
kind required"prf" | "recovery"
credentialIdstring
iv requiredstring
ct requiredstring

Error

FieldType
error requiredstring
codestring

Ping

FieldType
ok requiredtrue
channel requiredstring
version requiredstring

Message

FieldType
id requiredstring
title requiredstring
bodystring
kind required"message" | "form" | "report" | "files" | "secret"
status required"pending" | "answered" | "delivered" | "expired" | "cancelled" | "queued" | "running" | "completed" | "failed"
direction required"inbound" | "outbound"
sender requiredstring
senderIdstring
createdAt requiredstring
revisioninteger
readboolean
fieldsField[]
attachmentsAttachment[]
blocksReviewBlock[]
actionsAction[]
response{ values, actionId, secretFields, createdAt, sealed }
expiresAtstring
replyTostring
threadIdstring
threadSequenceinteger
runIdstring
secretDelivery"offered" | "claimed" | "ready" | "received"
destinationIdstring
typeIdstring
input{ destinationId, typeId, values, sealed }
result{ status, completedAt, reason, sealed }
sealedSealedEnvelope

Tombstone

FieldType
id requiredstring
revision requiredinteger
deleted requiredtrue

Destination

FieldType
id requiredstring
integrationId requiredstring
name requiredstring
keystring
signingSecretstring

Account

FieldType
id requiredstring
email requiredstring
plan requiredstring
used requirednumber
reservednumber
creditsnumber
storage requirednumber
usageResetsAtstring

Integration

FieldType
id requiredstring
name requiredstring
scopes required"messages:send" | "messages:read" | "destinations:manage" | "events:read" | "files:write"[]
createdAt requiredstring
colorConnectionColor
e2eeboolean

TokenInfo

FieldType
id requiredstring
name requiredstring
scopes required"messages:send" | "messages:read" | "destinations:manage" | "events:read" | "files:write"[]
createdAt requiredstring
lastUsedAt requiredstring | null
account required{ email, name }

TaskLog

FieldType
sequence requiredinteger
stream required"stdout" | "stderr"
text requiredstring
sealedSealedEnvelope

KeyDirectory

FieldType
account requiredAccountKeys | null
certificates required{ certificate, sig, integrationId }[]

KeyBackup

FieldType
id requiredstring
wrapped requiredWrappedKeyring
createdAt requiredstring

PendingDevice

FieldType
id requiredstring
label requiredstring
state required"waiting" | "challenged" | "revealed" | "approved" | "rejected"
createdAt requiredstring
expiresAt requiredstring
commit requiredstring
challengestring
transferstring
noncestring
envelopeSealedEnvelope