Version: 0.3.0
Base URL: http://localhost:7890
Content-Type: application/json
As of v0.3.0, Armada supports multi-tenant authentication. All endpoints (except those listed as exempt) require authentication. There are three authentication methods, evaluated in the following order:
Bearer tokens are the canonical authentication mechanism. Each token is a 64-character random alphanumeric string stored in a Credential record, linked to a specific tenant and user.
Authorization: Bearer <token>
The default installation seeds a credential with bearer token default, so Authorization: Bearer default works out of the box for single-user setups.
Session tokens are self-contained, AES-256-CBC encrypted tokens with a 24-hour lifetime. They are returned by POST /api/v1/authenticate and are intended for interactive/dashboard use. No server-side session storage is required -- the token contains the tenant ID, user ID, and expiration timestamp, validated by decryption.
X-Token: <encrypted-session-token>
The X-Api-Key header is retained for backward compatibility. When ApiKey is configured in settings, the server creates a synthetic admin tenant (ten_system) and user (usr_system) on startup. The API key resolves to this synthetic admin identity through the same AuthContext path as all other auth methods.
X-Api-Key: your-api-key-here
Deprecation notice:
X-Api-Keywill be removed in a future version. Migrate to bearer tokens for new integrations.
All endpoints fall into one of three authorization levels:
| Level | Description |
|---|---|
NoAuthRequired |
Health check, tenant lookup, onboarding, authenticate |
Authenticated |
All operational CRUD within the caller's tenant |
AdminOnly |
Tenant/user/credential management (with self-read exceptions) |
Armada distinguishes three effective caller roles:
IsAdmin = true: global system admin. Can access any tenant and any object in the system.IsAdmin = false,IsTenantAdmin = true: tenant-scoped admin. Can access and manage any object within the caller's tenant, including users and credentials in that tenant.IsAdmin = false,IsTenantAdmin = false: regular user. Can read tenant-scoped operational data within the caller's tenant, but self-service routes are limited to the caller's own user account and own credentials. Server-controlled fields and protected resources cannot be modified directly.
Operational entities persist both TenantId and UserId. Those ownership columns are indexed and enforced by foreign keys across SQLite, PostgreSQL, SQL Server, and MySQL.
| Endpoint | Method | Permission | Notes |
|---|---|---|---|
/api/v1/server/stop |
POST | NoAuthRequired*** | When RequireAuthForShutdown is true, requires global admin (IsAdmin = true) |
/api/v1/status/health |
GET | NoAuthRequired | |
/api/v1/authenticate |
POST | NoAuthRequired | |
/api/v1/tenants/lookup |
POST | NoAuthRequired | Input: email, returns matching tenants |
/api/v1/onboarding |
POST | NoAuthRequired | Gated by AllowSelfRegistration setting |
/api/v1/whoami |
GET | Authenticated | |
/api/v1/status |
GET | Authenticated | Tenant-scoped |
/api/v1/fleets |
ALL | Authenticated | Tenant-scoped |
/api/v1/vessels |
ALL | Authenticated | Tenant-scoped |
/api/v1/captains |
ALL | Authenticated | Tenant-scoped |
/api/v1/missions |
ALL | Authenticated | Tenant-scoped |
/api/v1/voyages |
ALL | Authenticated | Tenant-scoped |
/api/v1/docks |
ALL | Authenticated | Tenant-scoped |
/api/v1/signals |
ALL | Authenticated | Tenant-scoped |
/api/v1/events |
ALL | Authenticated | Tenant-scoped |
/api/v1/merge-queue |
ALL | Authenticated | Tenant-scoped |
/api/v1/tenants |
GET (list) | AdminOnly | Global admin only |
/api/v1/tenants |
POST | AdminOnly | Global admin only |
/api/v1/tenants/{id} |
GET | Authenticated | Global admin: any; tenant admin or regular user: own tenant only |
/api/v1/tenants/{id} |
PUT/DELETE | AdminOnly | Global admin only |
/api/v1/users |
GET (list) | AdminOnly | Global admin: all users. Tenant admin: users in own tenant |
/api/v1/users |
POST | AdminOnly | Global admin: any tenant. Tenant admin: own tenant only |
/api/v1/users/{id} |
GET | Authenticated | Global admin: any. Tenant admin: users in own tenant. Regular user: self only |
/api/v1/users/{id} |
PUT/DELETE | AdminOnly | Global admin: any. Tenant admin: users in own tenant. Regular user: self-update only |
/api/v1/credentials |
GET (list) | Authenticated | Global admin: all. Tenant admin: credentials in own tenant. Regular user: own only |
/api/v1/credentials |
POST | Authenticated | Global admin: any tenant/user. Tenant admin: own tenant. Regular user: self only |
/api/v1/credentials/{id} |
GET | Authenticated | Global admin: any. Tenant admin: own tenant. Regular user: own only |
/api/v1/credentials/{id} |
PUT | Authenticated | Global admin: any. Tenant admin: own tenant. Regular user: own only |
/api/v1/credentials/{id} |
DELETE | Authenticated | Global admin: any. Tenant admin: own tenant. Regular user: own only |
Exempt routes (no authentication required):
GET /api/v1/status/healthPOST /api/v1/authenticatePOST /api/v1/tenants/lookupPOST /api/v1/onboarding(whenAllowSelfRegistrationis enabled)POST /api/v1/server/stop(whenRequireAuthForShutdownisfalse, the default)GET /dashboardand all/dashboard/*pathsGET /(redirects to/dashboard)
All list endpoints return paginated results wrapped in EnumerationResult<T>. There are two ways to query:
GET /api/v1/missions?pageNumber=2&pageSize=25&status=InProgress&order=CreatedAscending
POST /api/v1/missions/enumerate
Content-Type: application/json
{
"PageNumber": 2,
"PageSize": 25,
"Status": "InProgress",
"Order": "CreatedAscending"
}
Query string parameters override body values on POST enumerate endpoints, allowing defaults in the body with per-request overrides via URL.
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
pageNumber |
int | 1 | >= 1 | Page number (1-based) |
pageSize |
int | 100 | 1 - 1000 | Results per page |
order |
string | CreatedDescending |
CreatedAscending, CreatedDescending |
Sort order by creation date |
createdAfter |
datetime | null | ISO 8601 | Filter: created after this timestamp |
createdBefore |
datetime | null | ISO 8601 | Filter: created before this timestamp |
| Parameter | Applies To | Description |
|---|---|---|
status |
missions, voyages, captains | Filter by status value |
fleetId |
vessels | Filter by fleet ID |
vesselId |
missions, docks, events | Filter by vessel ID |
captainId |
missions, docks, events | Filter by captain ID |
voyageId |
missions, events | Filter by voyage ID |
missionId |
events | Filter by mission ID |
type |
events | Filter by event type (alias for eventType) |
signalType |
signals | Filter by signal type |
toCaptainId |
signals | Filter by recipient captain ID |
unreadOnly |
signals | true to return only unread signals |
{
"Success": true,
"PageNumber": 1,
"PageSize": 25,
"TotalPages": 4,
"TotalRecords": 87,
"Objects": [ ... ],
"TotalMs": 3.14
}All error responses use a consistent JSON format with Error, Description, Message, and Data fields:
{
"Error": "NotFound",
"Description": "The requested resource was not found.",
"Message": "Mission not found",
"Data": {}
}| Field | Type | Description |
|---|---|---|
Error |
string | Error code (see table below) |
Description |
string | Standard description for the error code |
Message |
string | Human-readable message with specific details |
Data |
object | Additional context (usually empty) |
| Error Code | HTTP Status | When Used |
|---|---|---|
BadRequest |
400 | Invalid input, missing required fields, malformed request body, invalid state transition |
DeserializationError |
400 | Request body could not be parsed as valid JSON or does not match the expected type |
Unauthorized |
401 | Missing or invalid API key / bearer token |
Forbidden |
403 | Authenticated but not authorized for this operation |
NotFound |
404 | Entity not found by the given ID |
Conflict |
409 | Operation conflicts with current state (e.g., deleting an active voyage, retry landing failed) |
InternalError |
500 | Unexpected server error |
- The
Errorfield always contains one of the error codes listed above. - The
Messagefield provides a specific, actionable description of what went wrong. - HTTP status codes are set on the response and match the error code mapping above.
- Clients should check the HTTP status code first, then parse the response body for details.
Authenticate with email and password to receive an encrypted session token. This is the login endpoint used by the dashboard.
Permission: NoAuthRequired
Request Body: AuthenticateRequest
{
"TenantId": "default",
"Email": "admin@armada",
"Password": "password"
}Response: 200 OK - AuthenticateResult
{
"Success": true,
"Token": "eyJhbGciOi...",
"ExpiresUtc": "2026-03-16T12:00:00Z"
}Errors:
400 Bad Request- Missing required fields (TenantId, Email, Password)401 Unauthorized- Invalid credentials or inactive tenant/user
Returns the authenticated user's tenant and user information.
Permission: Authenticated
Request Headers: Authorization: Bearer <token> or X-Token: <session-token>
Response: 200 OK - WhoAmIResult
{
"Tenant": {
"Id": "default",
"Name": "Default Tenant",
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
},
"User": {
"Id": "default",
"TenantId": "default",
"Email": "admin@armada",
"PasswordSha256": "********",
"FirstName": null,
"LastName": null,
"IsAdmin": true,
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
}
}Errors:
401 Unauthorized- Not authenticated
Look up which tenants a given email address belongs to. Used by the dashboard login flow to determine the tenant before authentication.
Permission: NoAuthRequired
Request Body: TenantLookupRequest
{
"Email": "admin@armada"
}Response: 200 OK - TenantLookupResult
{
"Tenants": [
{
"Id": "default",
"Name": "Default Tenant"
}
]
}Errors:
400 Bad Request- Missing email
Self-register a new user within an existing tenant. Requires AllowSelfRegistration to be enabled in settings (default: true).
Creates a new user and an associated bearer token credential.
Permission: NoAuthRequired (gated by AllowSelfRegistration setting)
Request Body: OnboardingRequest
{
"TenantId": "default",
"Email": "newuser@example.com",
"Password": "securepassword",
"FirstName": "Jane",
"LastName": "Doe"
}Response: 200 OK - OnboardingResult
{
"Success": true,
"Tenant": {
"Id": "default",
"Name": "Default Tenant",
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
},
"User": {
"Id": "usr_abc123",
"TenantId": "default",
"Email": "newuser@example.com",
"PasswordSha256": "********",
"FirstName": "Jane",
"LastName": "Doe",
"IsAdmin": false,
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
},
"Credential": {
"Id": "crd_abc123",
"TenantId": "default",
"UserId": "usr_abc123",
"Name": null,
"BearerToken": "aBcDeFgH...",
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
},
"ErrorMessage": null
}Errors:
400 Bad Request- Missing required fields, email already exists in tenant403 Forbidden- Self-registration is disabled404 Not Found- Tenant not found
Permission: Global admin for list, create, update, delete. Authenticated users can read their own tenant.
List all tenants (paginated). Global admin only.
Response: 200 OK - EnumerationResult<TenantMetadata>
Enumerate tenants with filtering and sorting via JSON body. Global admin only.
Create a new tenant. Global admin only.
Request Body: TenantMetadata
{
"Name": "Acme Corp"
}Response: 201 Created - TenantMetadata
Get a tenant by ID. Non-admin users can only read their own tenant.
Response: 200 OK - TenantMetadata
Update a tenant. Global admin only.
Id, CreatedUtc, LastUpdateUtc, and IsProtected are preserved server-side.
Request Body: TenantMetadata
Response: 200 OK - TenantMetadata
Delete a tenant. Global admin only.
If the tenant is protected, the server returns 403 Forbidden.
Deleting an unprotected tenant cascades through all tenant-scoped subordinate resources, including protected users and credentials seeded for that tenant.
The delete flow is ownership-aware: direct delete of a protected tenant, user, or credential returns 403, but protected child auth records can still be removed as part of an allowed parent delete.
Response: 200 OK
Permission: Global admins can manage users across the system. Tenant admins can manage users within their own tenant. Regular users can read and update only their own user record.
List users (paginated). Global admins can list all users. Tenant admins can list users in their own tenant.
Response: 200 OK - EnumerationResult<UserMaster>
Password fields are redacted in responses.
Enumerate users with filtering and sorting via JSON body. Global admins can enumerate all users. Tenant admins are limited to their own tenant.
Create a new user. Global admins can create users in any tenant. Tenant admins can create users only in their own tenant and cannot grant global admin.
IsProtected is server-controlled and ignored if supplied by the client.
Password is plaintext in the request body and is hashed server-side before persistence. PasswordSha256 is accepted only for backward compatibility.
Request Body: user upsert payload
{
"TenantId": "default",
"Email": "newuser@example.com",
"Password": "securepassword",
"FirstName": "Jane",
"LastName": "Doe",
"IsAdmin": false,
"IsTenantAdmin": false
}Response: 201 Created - UserMaster (password redacted)
Get a user by ID. Global admins can read any user. Tenant admins can read users in their own tenant. Regular users can read only their own user record.
Response: 200 OK - UserMaster (password redacted)
Update a user. Global admins can update any user. Tenant admins can update users in their own tenant. Regular users can update only their own user record.
Id, TenantId, CreatedUtc, LastUpdateUtc, and IsProtected are server-controlled and cannot be modified by API clients.
If Password is supplied, the server hashes and stores the new password. If Password is omitted or empty, the current password is preserved.
Request Body: user upsert payload
{
"Email": "updated@example.com",
"Password": "newpassword",
"FirstName": "Jane",
"LastName": "Smith",
"IsAdmin": false,
"IsTenantAdmin": false,
"Active": true
}Response: 200 OK - UserMaster (password redacted)
Delete a user. Global admins can delete any unprotected user. Tenant admins can delete unprotected users in their own tenant. Regular users cannot delete users directly.
If the user is protected, the server returns 403 Forbidden.
Deleting an unprotected user cascades through that user's subordinate resources inside the tenant.
Response: 200 OK
Permission: Authenticated. Global admins can manage all credentials. Tenant admins can manage credentials in their own tenant. Regular users can list, read, create, update, and delete only their own credentials.
List credentials (paginated). Global admin: all credentials. Tenant admin: credentials in own tenant. Regular user: own credentials only.
Response: 200 OK - EnumerationResult<Credential>
Enumerate credentials with filtering and sorting via JSON body. Results are scoped by role.
Create a new credential (bearer token). A bearer token is auto-generated if not provided. Admin: can create for any tenant/user. Non-admin: can create for self only.
IsProtected is server-controlled and ignored if supplied by the client.
Request Body: Credential
{
"TenantId": "default",
"UserId": "default",
"Name": "My API Token"
}Response: 201 Created - Credential
Get a credential by ID. Non-admin users can only read their own credentials.
Response: 200 OK - Credential
Update a credential. Global admins can update any credential. Tenant admins can update credentials inside their tenant. Regular users can update only their own credentials.
Id, TenantId, UserId, CreatedUtc, LastUpdateUtc, and IsProtected are server-controlled and cannot be modified by API clients.
Request Body: Credential
Response: 200 OK - Credential
Delete a credential. Global admin: any. Tenant admin: credentials in own tenant. Regular user: own credentials only.
If the credential is protected, the server returns 403 Forbidden.
Response: 200 OK
Returns aggregate status including captain counts, mission breakdown, active voyages, and recent signals.
Response: 200 OK - ArmadaStatus
{
"TotalCaptains": 5,
"IdleCaptains": 2,
"WorkingCaptains": 3,
"StalledCaptains": 0,
"ActiveVoyages": 1,
"MissionsByStatus": {
"Pending": 3,
"InProgress": 2,
"Complete": 10
},
"Voyages": [],
"RecentSignals": [],
"TimestampUtc": "2026-03-07T12:00:00Z"
}Health check endpoint. Does not require authentication.
Response: 200 OK
{
"Status": "healthy",
"Timestamp": "2026-03-07T12:00:00Z",
"StartUtc": "2026-03-07T08:00:00Z",
"Uptime": "0.04:00:00",
"Version": "0.2.0",
"Ports": {
"Admiral": 7890,
"Mcp": 7891,
"WebSocket": 7892
}
}Initiates a graceful shutdown of the Admiral server.
Permission: NoAuthRequired by default. When RequireAuthForShutdown is true, requires global admin (IsAdmin = true).
Response: 200 OK
{
"Status": "shutting_down"
}A fleet is a named collection of repositories (vessels) under management.
List all fleets with pagination.
Query Parameters: Pagination parameters
Response: 200 OK - EnumerationResult<Fleet>
curl http://localhost:7890/api/v1/fleets?pageSize=10Paginated enumeration of fleets with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<Fleet>
curl -X POST http://localhost:7890/api/v1/fleets/enumerate \
-H "Content-Type: application/json" \
-d '{"PageSize": 10, "Order": "CreatedAscending"}'Create a new fleet.
Request Body: Fleet
| Field | Type | Required | Description |
|---|---|---|---|
Name |
string | yes | Fleet name |
Description |
string | no | Fleet description |
Response: 201 Created - Fleet
curl -X POST http://localhost:7890/api/v1/fleets \
-H "Content-Type: application/json" \
-d '{"Name": "Production Fleet", "Description": "Production repositories"}'Get a single fleet by ID, including all its vessels.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Fleet ID (flt_ prefix) |
Response: 200 OK - { Fleet: Fleet, Vessels: Vessel[] }
Error: 404 - Fleet not found
curl http://localhost:7890/api/v1/fleets/flt_abc123Update an existing fleet.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Fleet ID (flt_ prefix) |
Request Body: Fleet (fields to update)
Response: 200 OK - Fleet
Error: 404 - Fleet not found
curl -X PUT http://localhost:7890/api/v1/fleets/flt_abc123 \
-H "Content-Type: application/json" \
-d '{"Name": "Renamed Fleet"}'Delete a fleet. Vessels in the fleet are not deleted; their FleetId is set to null.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Fleet ID (flt_ prefix) |
Response: 204 No Content
curl -X DELETE http://localhost:7890/api/v1/fleets/flt_abc123Batch delete multiple fleets from the database by ID. Returns a summary of deleted and skipped entries. This cannot be undone.
Request Body:
{
"Ids": ["flt_abc123", "flt_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found" or "Empty ID").
A vessel is a git repository registered with Armada.
List all vessels with pagination.
Query Parameters: Pagination parameters, plus:
| Parameter | Type | Description |
|---|---|---|
fleetId |
string | Filter by fleet ID |
Response: 200 OK - EnumerationResult<Vessel>
curl http://localhost:7890/api/v1/vessels?fleetId=flt_abc123Paginated enumeration of vessels with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<Vessel>
curl -X POST http://localhost:7890/api/v1/vessels/enumerate \
-H "Content-Type: application/json" \
-d '{"FleetId": "flt_abc123", "PageSize": 50}'Register a new vessel (git repository).
Request Body: Vessel
| Field | Type | Required | Description |
|---|---|---|---|
Name |
string | yes | Vessel name |
RepoUrl |
string | yes | Remote repository URL |
FleetId |
string | no | Fleet to assign to |
DefaultBranch |
string | no | Default branch name (default: "main") |
Response: 201 Created - Vessel
curl -X POST http://localhost:7890/api/v1/vessels \
-H "Content-Type: application/json" \
-d '{"Name": "MyRepo", "RepoUrl": "https://github.com/org/repo.git", "FleetId": "flt_abc123"}'Get a single vessel by ID.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Vessel ID (vsl_ prefix) |
Response: 200 OK - Vessel
Error: 404 - Vessel not found
Update an existing vessel.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Vessel ID (vsl_ prefix) |
Request Body: Vessel (fields to update)
Response: 200 OK - Vessel
Error: 404 - Vessel not found
Delete a vessel.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Vessel ID (vsl_ prefix) |
Response: 204 No Content
Batch delete multiple vessels from the database by ID. Returns a summary of deleted and skipped entries. This cannot be undone.
Request Body:
{
"Ids": ["vsl_abc123", "vsl_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found" or "Empty ID").
Update only the ProjectContext, StyleGuide, and ModelContext fields of a vessel.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Vessel ID (vsl_ prefix) |
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
ProjectContext |
string | no | Project context describing architecture, key files, and dependencies |
StyleGuide |
string | no | Style guide describing naming conventions, patterns, and library preferences |
ModelContext |
string | no | Agent-accumulated context about this repository |
curl -X PATCH http://localhost:7890/api/v1/vessels/vsl_abc123/context \
-H "Content-Type: application/json" \
-d '{"ProjectContext": "C# .NET 8 project with SQLite", "StyleGuide": "Use PascalCase for public members"}'Response: 200 OK - Vessel
Error: 404 - Vessel not found
A voyage is a batch of related missions tracked together.
List all voyages with pagination.
Query Parameters: Pagination parameters, plus:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by voyage status (Open, InProgress, Complete, Cancelled) |
Response: 200 OK - EnumerationResult<Voyage>
curl http://localhost:7890/api/v1/voyages?status=InProgressPaginated enumeration of voyages with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<Voyage>
Create a new voyage with optional missions. Missions are automatically dispatched to the target vessel.
Request Body: VoyageRequest
| Field | Type | Required | Description |
|---|---|---|---|
Title |
string | yes | Voyage title |
Description |
string | no | Voyage description |
VesselId |
string | yes | Target vessel ID |
Missions |
array | no | List of MissionRequest objects |
Response: 201 Created - Voyage
curl -X POST http://localhost:7890/api/v1/voyages \
-H "Content-Type: application/json" \
-d '{
"Title": "API Hardening",
"Description": "Security improvements",
"VesselId": "vsl_abc123",
"Missions": [
{"Title": "Add rate limiting", "Description": "Add rate limiting middleware"},
{"Title": "Add input validation", "Description": "Validate all POST endpoints"}
]
}'Get a voyage and all its associated missions.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Voyage ID (vyg_ prefix) |
Response: 200 OK - VoyageDetail
{
"Voyage": { ... },
"Missions": [ ... ]
}Error: 404 - Voyage not found
Cancel a voyage. Sets the voyage status to Cancelled and cancels all Pending or Assigned missions. In-progress missions are not affected.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Voyage ID (vyg_ prefix) |
Response: 200 OK
{
"Voyage": { "Id": "vyg_abc123", "Status": "Cancelled", "..." : "..." },
"CancelledMissions": 3
}Error: 404 - Voyage not found
Permanently delete a voyage and all its associated missions from the database. This cannot be undone.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Voyage ID (vyg_ prefix) |
Response: 200 OK
{
"Status": "deleted",
"VoyageId": "vyg_abc123",
"MissionsDeleted": 5
}Error: 404 - Voyage not found
Batch delete multiple voyages and their associated missions from the database by ID. Voyages that are Open/InProgress or have active missions are skipped. Returns a summary of deleted and skipped entries. This cannot be undone.
Request Body:
{
"Ids": ["vyg_abc123", "vyg_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found", "Cannot delete voyage while status is Open", or "Cannot delete voyage with N active mission(s)").
A mission is an atomic unit of work assigned to a captain (AI agent).
List all missions with pagination.
Query Parameters: Pagination parameters, plus:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by mission status |
vesselId |
string | Filter by vessel ID |
captainId |
string | Filter by captain ID |
voyageId |
string | Filter by voyage ID |
Response: 200 OK - EnumerationResult<Mission>
Note: The
DiffSnapshotfield is excluded from mission list responses to keep payloads compact. UseGET /api/v1/missions/{id}/diffto retrieve the full diff.
curl http://localhost:7890/api/v1/missions?status=InProgress&vesselId=vsl_abc123Paginated enumeration of missions with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<Mission>
curl -X POST http://localhost:7890/api/v1/missions/enumerate \
-H "Content-Type: application/json" \
-d '{"Status": "InProgress", "VesselId": "vsl_abc123", "PageSize": 25}'Create and dispatch a new mission. If a VesselId is provided, the Admiral will assign a captain and set up a worktree.
Request Body: Mission
| Field | Type | Required | Description |
|---|---|---|---|
Title |
string | yes | Mission title |
Description |
string | no | Detailed instructions for the AI agent |
VesselId |
string | no | Target vessel (required for auto-dispatch) |
VoyageId |
string | no | Parent voyage ID |
Priority |
int | no | Priority (lower = higher priority, default: 100) |
Response: 201 Created - Mission
curl -X POST http://localhost:7890/api/v1/missions \
-H "Content-Type: application/json" \
-d '{"Title": "Fix login bug", "Description": "The login form does not validate email addresses", "VesselId": "vsl_abc123"}'Get a single mission by ID.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Mission ID (msn_ prefix) |
Response: 200 OK - Mission
Error: 404 - Mission not found
Note: The
DiffSnapshotfield is excluded from responses to keep payloads compact. UseGET /api/v1/missions/{id}/diffto retrieve the full diff.
Update mission fields (title, description, priority, etc.). Does not change status -- use the status transition endpoint for that.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Mission ID (msn_ prefix) |
Request Body: Mission (fields to update)
Response: 200 OK - Mission
Error: 404 - Mission not found
Transition a mission to a new status. Only valid transitions are allowed.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Mission ID (msn_ prefix) |
Request Body: StatusTransitionRequest
| Field | Type | Required | Description |
|---|---|---|---|
Status |
string | yes | Target status name |
Response: 200 OK - Mission
Error: 400 - Invalid transition or invalid status name
Error: 404 - Mission not found
Valid Status Transitions:
| From | Allowed Targets |
|---|---|
Pending |
Assigned, Cancelled |
Assigned |
InProgress, Cancelled |
InProgress |
WorkProduced, Testing, Review, Complete, Failed, Cancelled |
WorkProduced |
PullRequestOpen, Complete, LandingFailed, Cancelled |
PullRequestOpen |
Complete, LandingFailed, Cancelled |
Testing |
Review, InProgress, Complete, Failed |
Review |
Complete, InProgress, Failed |
LandingFailed |
WorkProduced, Failed, Cancelled |
Complete |
(terminal) |
Failed |
(terminal) |
Cancelled |
(terminal) |
curl -X PUT http://localhost:7890/api/v1/missions/msn_abc123/status \
-H "Content-Type: application/json" \
-d '{"Status": "Assigned"}'Cancel a mission by setting its status to Cancelled. Returns the full updated mission.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Mission ID (msn_ prefix) |
Response: 200 OK - Mission (with Status: "Cancelled")
Error: 404 - Mission not found
Batch delete multiple missions from the database by ID. Returns a summary of deleted and skipped entries. This cannot be undone.
Request Body:
{
"Ids": ["msn_abc123", "msn_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found" or "Empty ID").
Restart a failed or cancelled mission by resetting it to Pending for re-dispatch. Clears captain assignment, branch, PR URL, and timing fields. Optionally update the title and description (instructions) before restarting.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Mission ID (msn_ prefix) |
Request Body (optional):
{
"Title": "Updated mission title",
"Description": "Updated instructions for the captain"
}| Field | Type | Required | Description |
|---|---|---|---|
Title |
string | No | New mission title. Omit to keep the original. |
Description |
string | No | New mission description/instructions. Omit to keep the original. |
Response: 200 OK - Mission (with Status: "Pending")
Errors:
400- Mission is not inFailedorCancelledstatus404- Mission not found
Returns the git diff of changes made by a captain in the mission's worktree. Checks for a saved diff file first (captured at completion), then falls back to a live worktree diff.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Mission ID (msn_ prefix) |
Response: 200 OK
{
"MissionId": "msn_abc123",
"Branch": "armada/msn_abc123",
"Diff": "diff --git a/src/auth.ts b/src/auth.ts\n..."
}Error: 404 - Mission not found or no diff available
Returns the session log (captured stdout/stderr) for a mission. Log files are written to disk when a captain executes a mission. Supports pagination via query parameters.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Mission ID (msn_ prefix) |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
lines |
integer | 100 | Number of lines to return |
offset |
integer | 0 | Line offset (0-based, skip this many lines from start) |
Response: 200 OK
{
"MissionId": "msn_abc123",
"Log": "Starting mission...\nCloning repository...\n...",
"Lines": 100,
"TotalLines": 542
}If the mission exists but has no log file yet, returns an empty log:
{
"MissionId": "msn_abc123",
"Log": "",
"Lines": 0,
"TotalLines": 0
}Error: 404 - Mission not found
# Get first 50 lines
curl http://localhost:8080/api/v1/missions/msn_abc123/log?lines=50 \
-H "X-Api-Key: your-key"
# Get lines 100-200
curl http://localhost:8080/api/v1/missions/msn_abc123/log?offset=100&lines=100 \
-H "X-Api-Key: your-key"A captain is an AI agent instance (Claude Code, Codex, etc.) that executes missions.
List all captains with pagination.
Query Parameters: Pagination parameters, plus:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by captain state (Idle, Working, Stalled, Stopping) |
Response: 200 OK - EnumerationResult<Captain>
curl http://localhost:7890/api/v1/captains?status=WorkingPaginated enumeration of captains with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<Captain>
Register a new captain (AI agent).
Request Body: Captain
| Field | Type | Required | Description |
|---|---|---|---|
Name |
string | yes | Captain name |
Runtime |
string | no | Agent runtime type (default: ClaudeCode) |
Response: 201 Created - Captain
curl -X POST http://localhost:7890/api/v1/captains \
-H "Content-Type: application/json" \
-d '{"Name": "captain-1", "Runtime": "ClaudeCode", "SystemInstructions": "You are a testing specialist. Always run tests before committing."}'Get a single captain by ID.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Captain ID (cpt_ prefix) |
Response: 200 OK - Captain
Error: 404 - Captain not found
Update a captain's name or runtime. Operational fields (state, process, mission) are preserved.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Captain ID (cpt_ prefix) |
Request Body:
{
"name": "captain-bravo",
"runtime": "Codex",
"systemInstructions": "Focus on code quality and always run linting before commits."
}Response: 200 OK - Captain
Error: 404 - Captain not found
curl -X PUT http://localhost:7890/api/v1/captains/cpt_abc123 \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_KEY" \
-d '{"name": "captain-bravo", "runtime": "Codex"}'Stop a running captain agent. Kills its OS process and recalls it to idle state.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Captain ID (cpt_ prefix) |
Response: 200 OK
{
"Status": "stopped"
}Error: 404 - Captain not found
Emergency stop all running captains, recalling them to idle state.
Response: 200 OK
{
"Status": "all_stopped"
}Returns the current session log for a captain. The captain's .current pointer file is resolved to find the active mission's log file. Supports pagination via query parameters.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Captain ID (cpt_ prefix) |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
lines |
integer | 100 | Number of lines to return |
offset |
integer | 0 | Line offset (0-based, skip this many lines from start) |
Response: 200 OK
{
"CaptainId": "cpt_abc123",
"Log": "[2026-03-07] Processing task...\nRunning tests...\n...",
"Lines": 100,
"TotalLines": 203
}If the captain has no active log (no pointer file or target file missing), returns an empty log:
{
"CaptainId": "cpt_abc123",
"Log": "",
"Lines": 0,
"TotalLines": 0
}Error: 404 - Captain not found
curl http://localhost:8080/api/v1/captains/cpt_abc123/log?lines=200 \
-H "X-Api-Key: your-key"Delete a captain. Blocked if the captain is currently working or has active missions.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Captain ID (cpt_ prefix) |
Response: 204 No Content
Error: 404 - Captain not found
Error: 409 Conflict - Cannot delete captain while state is Working. Stop the captain first.
Error: 409 Conflict - Cannot delete captain with active missions in Assigned or InProgress status. Cancel or complete them first.
Batch delete multiple captains from the database by ID. Captains that are Working or have active missions are skipped. Returns a summary of deleted and skipped entries. This cannot be undone.
Request Body:
{
"Ids": ["cpt_abc123", "cpt_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found", "Cannot delete captain while state is Working", or "Cannot delete captain with N active mission(s)").
A signal is a message between the admiral and captains or between captains.
List recent signals with pagination.
Query Parameters: Pagination parameters, plus:
| Parameter | Type | Description |
|---|---|---|
signalType |
string | Filter by signal type |
toCaptainId |
string | Filter by recipient captain ID |
unreadOnly |
bool | true to return only unread signals |
Response: 200 OK - EnumerationResult<Signal>
curl http://localhost:7890/api/v1/signals?toCaptainId=cpt_abc123&unreadOnly=truePaginated enumeration of signals with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<Signal>
Send a new signal (message).
Request Body: Signal
| Field | Type | Required | Description |
|---|---|---|---|
Type |
string | no | Signal type (default: Nudge) |
Payload |
string | no | Signal payload (message content) |
ToCaptainId |
string | no | Recipient captain ID (null = to Admiral) |
FromCaptainId |
string | no | Sender captain ID (null = from Admiral) |
Response: 201 Created - Signal
curl -X POST http://localhost:7890/api/v1/signals \
-H "Content-Type: application/json" \
-d '{"Type": "Mail", "Payload": "Please check the test results", "ToCaptainId": "cpt_abc123"}'Batch soft-delete multiple signals by marking them as read. Returns a summary of deleted and skipped entries.
Request Body:
{
"Ids": ["sig_abc123", "sig_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found" or "Empty ID").
System events represent state changes and audit trail entries generated automatically by the server.
List system events with pagination.
Query Parameters: Pagination parameters, plus:
| Parameter | Type | Description |
|---|---|---|
type |
string | Filter by event type (e.g. mission.status_changed) |
captainId |
string | Filter by captain ID |
missionId |
string | Filter by mission ID |
vesselId |
string | Filter by vessel ID |
voyageId |
string | Filter by voyage ID |
limit |
int | Alias for pageSize |
Response: 200 OK - EnumerationResult<ArmadaEvent>
curl http://localhost:7890/api/v1/events?type=mission.status_changed&missionId=msn_abc123Paginated enumeration of events with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<ArmadaEvent>
Delete a single event by ID.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Event ID (evt_ prefix) |
Response: 204 No Content
Error: 404 - Event not found
Batch delete multiple events by ID. Returns a summary of deleted and skipped entries.
Request Body:
{
"Ids": ["evt_abc123", "evt_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found" or "Empty ID").
Docks are git worktrees provisioned for captains. These endpoints provide access to dock state and management.
List all docks with optional filtering.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
vesselId |
string | Filter by vessel ID |
pageNumber |
integer | Page number (1-based, default 1) |
pageSize |
integer | Results per page (default 100) |
order |
string | Sort order: CreatedAscending, CreatedDescending |
Response: 200 OK
{
"Objects": [],
"TotalRecords": 0,
"PageSize": 100,
"PageNumber": 1,
"TotalPages": 0,
"Success": true,
"TotalMs": 0.5
}Paginated enumeration of docks with optional filtering and sorting.
Request Body:
{
"PageNumber": 1,
"PageSize": 25,
"VesselId": "vsl_abc123"
}Response: 200 OK -- Same shape as GET /api/v1/docks.
Get a single dock by ID.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Dock ID (dck_ prefix) |
Response: 200 OK - Dock object
Error: 404 - Dock not found
Delete a dock and clean up its git worktree. Blocked if the dock is actively in use by a captain.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Dock ID (dck_ prefix) |
Response: 204 No Content
Error: 404 - Dock not found
Error: 409 - Dock is actively in use by a captain
Force purge a dock and its git worktree, even if a mission references it. This cannot be undone.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Dock ID (dck_ prefix) |
Response: 200 OK
{
"Status": "purged",
"DockId": "dck_abc123"
}Error: 404 - Dock not found
Batch delete multiple docks and their git worktrees from the database by ID. Returns a summary of deleted and skipped entries. This cannot be undone.
Request Body:
{
"Ids": ["dck_abc123", "dck_def456"]
}Response: 200 OK
{
"Status": "deleted",
"Deleted": 2,
"Skipped": []
}Skipped entries include the entity ID and the reason (e.g., "Not found" or "Empty ID").
A bors-style merge queue that batches branches, runs tests, and lands passing batches.
List merge queue entries with pagination.
Query Parameters: Pagination parameters
Response: 200 OK - EnumerationResult<MergeEntry>
curl http://localhost:7890/api/v1/merge-queuePaginated enumeration of merge queue entries with optional filtering and sorting.
Request Body: EnumerationQuery (optional)
Response: 200 OK - EnumerationResult<MergeEntry>
Enqueue a branch for testing and merging.
Request Body: MergeEntry
| Field | Type | Required | Description |
|---|---|---|---|
BranchName |
string | yes | Branch to merge |
TargetBranch |
string | no | Target branch (default: "main") |
MissionId |
string | no | Parent mission ID |
VesselId |
string | no | Vessel ID |
Priority |
int | no | Queue priority (lower = higher, default: 0) |
TestCommand |
string | no | Test command for verification |
Response: 201 Created - MergeEntry
curl -X POST http://localhost:7890/api/v1/merge-queue \
-H "Content-Type: application/json" \
-d '{"BranchName": "armada/msn_abc123", "TargetBranch": "main", "MissionId": "msn_abc123"}'Get a single merge queue entry by ID.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Merge entry ID (mrg_ prefix) |
Response: 200 OK - MergeEntry
Error: 404 - Merge entry not found
Cancel a queued merge entry.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Merge entry ID (mrg_ prefix) |
Response: 204 No Content
Trigger processing of the merge queue. Creates integration branches, runs tests, and lands passing batches.
Response: 200 OK
{
"Status": "processed"
}Permanently delete a single terminal merge queue entry from the database. Only entries in Landed, Failed, or Cancelled status can be purged. This cannot be undone.
Path Parameters:
| Parameter | Description |
|---|---|
id |
Merge entry ID (mrg_ prefix) |
Response: 200 OK
{
"Status": "purged",
"EntryId": "mrg_abc123"
}Error: 404 - Merge entry not found
Error: 409 - Entry is not in a terminal state
Batch purge multiple terminal merge queue entries from the database by ID. Returns a summary of purged and skipped entries. This cannot be undone.
Request Body:
{
"EntryIds": ["mrg_abc123", "mrg_def456"]
}Response: 200 OK
{
"Status": "purged",
"EntriesPurged": 2,
"Skipped": []
}Skipped entries include the entry ID and the reason (e.g., "Not found" or "Not in terminal state").
Create and download a ZIP backup of the Armada database and settings.
Response: 200 OK — Binary ZIP file stream with Content-Disposition: attachment; filename="armada-backup-{timestamp}.zip" header.
ZIP Contents:
| File | Description |
|---|---|
armada.db |
SQLite database snapshot created via the SQLite online backup API |
settings.json |
Current Armada server configuration |
manifest.json |
Backup metadata: timestamp, schema version, Armada version, record counts per table |
Example:
curl -H "X-Api-Key: your-key" http://localhost:7890/api/v1/backup -o backup.zipRestore Armada from a previously created backup ZIP file.
Request: Binary ZIP file in the request body (Content-Type: application/zip).
Headers:
| Header | Required | Description |
|---|---|---|
Content-Type |
Yes | application/zip |
X-Original-Filename |
No | Original filename of the uploaded backup (used in the response message). If omitted, the server's temp filename is used. |
Validation:
- ZIP must contain
armada.dbwith a validschema_migrationstable - A safety backup is automatically created before overwriting the current database
Response: 200 OK
{
"Status": "restored",
"SafetyBackupPath": "~/.armada/backups/armada-safety-backup-20260311T120000Z.zip",
"SchemaVersion": 9,
"Message": "Database restored from backup.zip. Restart the server to reload the restored data."
}Example:
curl -X POST -H "X-Api-Key: your-key" \
-H "Content-Type: application/zip" \
-H "X-Original-Filename: backup.zip" \
--data-binary @backup.zip \
http://localhost:7890/api/v1/restoreNote: Restart the server after restoring to ensure all in-memory state is refreshed.
A tenant in the multi-tenant system.
{
"Id": "ten_abc123",
"Name": "Acme Corp",
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with ten_ prefix |
Name |
string | "My Tenant" |
Tenant name |
Active |
bool | true | Whether tenant is active |
IsProtected |
bool | false | Protected tenants cannot be deleted directly |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
A user in the multi-tenant system. Passwords are stored as SHA256 hashes and redacted in API responses.
{
"Id": "usr_abc123",
"TenantId": "default",
"Email": "admin@armada",
"PasswordSha256": "********",
"FirstName": "Jane",
"LastName": "Doe",
"IsAdmin": false,
"IsTenantAdmin": false,
"IsProtected": false,
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with usr_ prefix |
TenantId |
string | "default" |
Parent tenant |
Email |
string | "admin@armada" |
Email address (unique within tenant) |
PasswordSha256 |
string | SHA256("password") | SHA256 hash of password (redacted in responses) |
FirstName |
string? | null | First name |
LastName |
string? | null | Last name |
IsAdmin |
bool | false | Global system admin privileges |
IsTenantAdmin |
bool | false | Tenant-scoped admin privileges |
IsProtected |
bool | false | Protected users cannot be deleted directly |
Active |
bool | true | Whether user is active |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
A bearer token credential for API authentication.
{
"Id": "crd_abc123",
"TenantId": "default",
"UserId": "default",
"Name": "My API Token",
"BearerToken": "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789...",
"IsProtected": false,
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with crd_ prefix |
TenantId |
string | "default" |
Parent tenant |
UserId |
string | "default" |
Owning user |
Name |
string? | null | Friendly name |
BearerToken |
string | auto-generated | 64-character random alphanumeric token |
IsProtected |
bool | false | Protected credentials cannot be deleted directly |
Active |
bool | true | Whether credential is active |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
Represents the authenticated identity context resolved from any authentication method.
{
"IsAuthenticated": true,
"TenantId": "default",
"UserId": "default",
"IsAdmin": true,
"IsTenantAdmin": true,
"AuthMethod": "Bearer"
}| Field | Type | Description |
|---|---|---|
IsAuthenticated |
bool | Whether the request is authenticated |
TenantId |
string? | Tenant identifier |
UserId |
string? | User identifier |
IsAdmin |
bool | Global system admin privileges |
IsTenantAdmin |
bool | Tenant-scoped admin privileges |
AuthMethod |
string? | "Bearer", "Session", "ApiKey", or null |
Role semantics:
IsAdmin = true: global system-wide admin with access to every tenant and object.IsAdmin = false,IsTenantAdmin = true: tenant-scoped admin with full access inside that tenant.IsAdmin = false,IsTenantAdmin = false: regular user limited to read-only tenant visibility plus self-service on their own user account and credentials.
Immutable update fields:
Id, creation timestamps, ownership identifiers (TenantId,UserIdwhere applicable), andIsProtectedare preserved server-side on update routes.
Result of GET /api/v1/whoami.
{
"Tenant": { ... },
"User": { ... }
}| Field | Type | Description |
|---|---|---|
Tenant |
TenantMetadata | Tenant information |
User |
UserMaster | User information (password redacted) |
Request body for POST /api/v1/authenticate.
| Field | Type | Required | Description |
|---|---|---|---|
TenantId |
string | Yes | Tenant identifier |
Email |
string | Yes | User email address |
Password |
string | Yes | Plaintext password |
Request body for POST /api/v1/tenants/lookup.
| Field | Type | Required | Description |
|---|---|---|---|
Email |
string | Yes | Email address to look up |
Result of POST /api/v1/tenants/lookup.
| Field | Type | Description |
|---|---|---|
Tenants |
array | List of { TenantId, TenantName } entries matching the email |
Request body for POST /api/v1/onboarding.
| Field | Type | Required | Description |
|---|---|---|---|
TenantId |
string | Yes | Tenant to join |
Email |
string | Yes | Email address |
Password |
string | Yes | Plaintext password |
FirstName |
string? | No | First name |
LastName |
string? | No | Last name |
Result of POST /api/v1/onboarding.
| Field | Type | Description |
|---|---|---|
Success |
bool | Whether onboarding succeeded |
Tenant |
TenantMetadata? | Created/joined tenant |
User |
UserMaster? | Created user (password redacted) |
Credential |
Credential? | Created credential with bearer token |
ErrorMessage |
string? | Error message if failed |
A named collection of repositories under management.
{
"Id": "flt_abc123",
"Name": "Production Fleet",
"Description": "Production repositories",
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with flt_ prefix |
Name |
string | "My Fleet" |
Fleet name |
Description |
string? | null | Fleet description |
Active |
bool | true | Whether fleet is active |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
A git repository registered with Armada.
{
"Id": "vsl_abc123",
"FleetId": "flt_abc123",
"Name": "MyRepo",
"RepoUrl": "https://github.com/org/repo.git",
"LocalPath": "/home/user/.armada/repos/MyRepo",
"WorkingDirectory": null,
"DefaultBranch": "main",
"ProjectContext": null,
"StyleGuide": null,
"EnableModelContext": false,
"ModelContext": null,
"LandingMode": null,
"BranchCleanupPolicy": null,
"Active": true,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with vsl_ prefix |
FleetId |
string? | null | Parent fleet ID |
Name |
string | "My Vessel" |
Vessel name |
RepoUrl |
string? | null | Remote repository URL |
LocalPath |
string? | null | Local path to bare repository clone |
WorkingDirectory |
string? | null | Local working directory for merge on completion |
DefaultBranch |
string | "main" |
Default branch name |
ProjectContext |
string? | null | Project context describing architecture, key files, and dependencies |
StyleGuide |
string? | null | Style guide describing naming conventions, patterns, and library preferences |
EnableModelContext |
bool | false | Whether model context accumulation is enabled |
ModelContext |
string? | null | Agent-accumulated context about this repository |
LandingMode |
LandingModeEnum? | null | Per-vessel landing policy override (null = use global setting) |
BranchCleanupPolicy |
BranchCleanupPolicyEnum? | null | Per-vessel branch cleanup policy override (null = use global setting) |
Active |
bool | true | Whether vessel is active |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
A batch of related missions tracked together.
{
"Id": "vyg_abc123",
"Title": "API Hardening",
"Description": "Security improvements across the API",
"Status": "InProgress",
"CreatedUtc": "2026-03-07T12:00:00Z",
"CompletedUtc": null,
"LastUpdateUtc": "2026-03-07T12:00:00Z",
"AutoPush": null,
"AutoCreatePullRequests": null,
"AutoMergePullRequests": null,
"LandingMode": null
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with vyg_ prefix |
Title |
string | "New Voyage" |
Voyage title |
Description |
string? | null | Voyage description |
Status |
VoyageStatusEnum | Open |
Current status |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
CompletedUtc |
datetime? | null | Completion timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
AutoPush |
bool? | null | Per-voyage auto-push override (null = use global setting) |
AutoCreatePullRequests |
bool? | null | Per-voyage auto-create PRs override |
AutoMergePullRequests |
bool? | null | Per-voyage auto-merge PRs override |
LandingMode |
LandingModeEnum? | null | Per-voyage landing policy override (null = use vessel/global setting) |
An atomic unit of work assigned to a captain.
{
"Id": "msn_abc123",
"VoyageId": "vyg_abc123",
"VesselId": "vsl_abc123",
"CaptainId": "cpt_abc123",
"Title": "Fix login bug",
"Description": "The login form does not validate email addresses",
"Status": "InProgress",
"Priority": 100,
"ParentMissionId": null,
"BranchName": "armada/msn_abc123",
"DockId": null,
"ProcessId": null,
"PrUrl": null,
"CommitHash": null,
"DiffSnapshot": null,
"CreatedUtc": "2026-03-07T12:00:00Z",
"StartedUtc": "2026-03-07T12:05:00Z",
"CompletedUtc": null,
"LastUpdateUtc": "2026-03-07T12:10:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with msn_ prefix |
VoyageId |
string? | null | Parent voyage ID |
VesselId |
string? | null | Target vessel (repository) ID |
CaptainId |
string? | null | Assigned captain (agent) ID |
Title |
string | "New Mission" |
Mission title |
Description |
string? | null | Detailed instructions for the AI agent |
Status |
MissionStatusEnum | Pending |
Current status |
Priority |
int | 100 | Priority (lower number = higher priority) |
ParentMissionId |
string? | null | Parent mission ID for sub-tasks |
BranchName |
string? | null | Git branch name |
DockId |
string? | null | Dock identifier for the mission's worktree |
ProcessId |
int? | null | OS process ID of the agent working on the mission |
PrUrl |
string? | null | Pull request URL if created |
CommitHash |
string? | null | Git commit hash captured on completion |
DiffSnapshot |
string? | null | Always null in list/status responses to keep payloads compact. Use GET /api/v1/missions/{id}/diff to retrieve the full diff. |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
StartedUtc |
datetime? | null | Work start timestamp (UTC) |
CompletedUtc |
datetime? | null | Completion timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
A worker AI agent instance executing missions.
{
"Id": "cpt_abc123",
"Name": "captain-1",
"Runtime": "ClaudeCode",
"SystemInstructions": null,
"State": "Idle",
"CurrentMissionId": null,
"CurrentDockId": null,
"ProcessId": null,
"RecoveryAttempts": 0,
"LastHeartbeatUtc": null,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with cpt_ prefix |
Name |
string | "Captain" |
Captain name |
Runtime |
AgentRuntimeEnum | ClaudeCode |
Agent runtime type |
SystemInstructions |
string? | null | Per-captain system instructions injected into every mission prompt |
State |
CaptainStateEnum | Idle |
Current state |
CurrentMissionId |
string? | null | Currently assigned mission ID |
CurrentDockId |
string? | null | Currently assigned dock (worktree) ID |
ProcessId |
int? | null | OS process ID |
RecoveryAttempts |
int | 0 | Auto-recovery attempts for current mission |
LastHeartbeatUtc |
datetime? | null | Last heartbeat timestamp (UTC) |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
A message between the admiral and captains.
{
"Id": "sig_abc123",
"FromCaptainId": "cpt_abc123",
"ToCaptainId": null,
"Type": "Progress",
"Payload": "Mission msn_abc123 transitioned to Testing",
"Read": false,
"CreatedUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with sig_ prefix |
FromCaptainId |
string? | null | Sender captain ID (null = from Admiral) |
ToCaptainId |
string? | null | Recipient captain ID (null = to Admiral) |
Type |
SignalTypeEnum | Nudge |
Signal type |
Payload |
string? | null | Message payload |
Read |
bool | false | Whether signal has been read |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
A recorded event representing a state change in the system.
{
"Id": "evt_abc123",
"EventType": "mission.status_changed",
"EntityType": "mission",
"EntityId": "msn_abc123",
"CaptainId": "cpt_abc123",
"MissionId": "msn_abc123",
"VesselId": "vsl_abc123",
"VoyageId": "vyg_abc123",
"Message": "Mission msn_abc123 transitioned to Complete",
"Payload": null,
"CreatedUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with evt_ prefix |
EventType |
string | "" |
Event type identifier |
EntityType |
string? | null | Related entity type |
EntityId |
string? | null | Related entity ID |
CaptainId |
string? | null | Related captain ID |
MissionId |
string? | null | Related mission ID |
VesselId |
string? | null | Related vessel ID |
VoyageId |
string? | null | Related voyage ID |
Message |
string | "" |
Human-readable event message |
Payload |
string? | null | JSON payload with additional details |
CreatedUtc |
datetime | now | Event timestamp (UTC) |
Known Event Types:
mission.created- Mission was createdmission.status_changed- Mission status transitionedmission.completed- Mission completed successfullymission.failed- Mission failedcaptain.launched- Captain agent process startedcaptain.stopped- Captain agent process stoppedcaptain.stalled- Captain detected as stalledvoyage.created- Voyage was createdvoyage.completed- All missions in voyage completedvoyage.deleted- Voyage permanently deleted
An entry in the merge queue representing a branch to be tested and merged.
{
"Id": "mrg_abc123",
"MissionId": "msn_abc123",
"VesselId": "vsl_abc123",
"BranchName": "armada/msn_abc123",
"TargetBranch": "main",
"Status": "Queued",
"Priority": 0,
"BatchId": null,
"TestCommand": "dotnet test",
"TestOutput": null,
"TestExitCode": null,
"CreatedUtc": "2026-03-07T12:00:00Z",
"LastUpdateUtc": "2026-03-07T12:00:00Z",
"TestStartedUtc": null,
"CompletedUtc": null
}| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with mrg_ prefix |
MissionId |
string? | null | Parent mission ID |
VesselId |
string? | null | Vessel ID |
BranchName |
string | "unknown" |
Branch to merge |
TargetBranch |
string | "main" |
Target branch |
Status |
MergeStatusEnum | Queued |
Current status |
Priority |
int | 0 | Queue priority (lower = higher) |
BatchId |
string? | null | Batch ID during batch testing |
TestCommand |
string? | null | Test command for verification |
TestOutput |
string? | null | Test output or error message |
TestExitCode |
int? | null | Test process exit code |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
TestStartedUtc |
datetime? | null | Test start timestamp (UTC) |
CompletedUtc |
datetime? | null | Completion timestamp (UTC) |
Aggregate status summary returned by the status endpoint.
{
"TotalCaptains": 5,
"IdleCaptains": 2,
"WorkingCaptains": 3,
"StalledCaptains": 0,
"ActiveVoyages": 1,
"MissionsByStatus": {
"Pending": 3,
"InProgress": 2,
"Complete": 10
},
"Voyages": [
{
"Voyage": { ... },
"TotalMissions": 5,
"CompletedMissions": 3,
"FailedMissions": 0,
"InProgressMissions": 2
}
],
"RecentSignals": [],
"TimestampUtc": "2026-03-07T12:00:00Z"
}| Field | Type | Description |
|---|---|---|
TotalCaptains |
int | Total registered captains |
IdleCaptains |
int | Number of idle captains |
WorkingCaptains |
int | Number of working captains |
StalledCaptains |
int | Number of stalled captains |
ActiveVoyages |
int | Total active voyages |
MissionsByStatus |
dict<string, int> | Mission counts grouped by status |
Voyages |
array | Active VoyageProgress objects |
RecentSignals |
array | Recent Signal objects |
TimestampUtc |
datetime | Snapshot timestamp (UTC) |
Progress information for an active voyage, nested in ArmadaStatus.
| Field | Type | Description |
|---|---|---|
Voyage |
Voyage | Voyage details |
TotalMissions |
int | Total missions in voyage |
CompletedMissions |
int | Number of completed missions |
FailedMissions |
int | Number of failed missions |
InProgressMissions |
int | Number of in-progress missions |
A git worktree provisioned for a captain. Docks are managed internally by the Admiral and are not directly created/deleted via API.
| Field | Type | Default | Description |
|---|---|---|---|
Id |
string | auto-generated | Unique ID with dck_ prefix |
VesselId |
string | "" |
Vessel ID |
CaptainId |
string? | null | Captain currently using dock |
WorktreePath |
string? | null | Local filesystem path to worktree |
BranchName |
string? | null | Branch name checked out |
Active |
bool | true | Whether dock is active/usable |
CreatedUtc |
datetime | now | Creation timestamp (UTC) |
LastUpdateUtc |
datetime | now | Last update timestamp (UTC) |
All enumerations serialize as strings in JSON (e.g., "InProgress", not 2).
| Value | Description |
|---|---|
Pending |
Created but not yet assigned to a captain |
Assigned |
Assigned to a captain, awaiting work start |
InProgress |
Captain is actively working |
WorkProduced |
Agent exited successfully; work ready for landing |
PullRequestOpen |
Pull request created, awaiting merge confirmation |
Testing |
Work complete, under automated testing |
Review |
Awaiting human review |
Complete |
Successfully completed — code landed (terminal) |
Failed |
Mission failed (terminal) |
LandingFailed |
Landing (merge/PR) failed; may be retried |
Cancelled |
Mission cancelled (terminal) |
| Value | Description |
|---|---|
LocalMerge |
Merge branch into default branch locally and push |
PullRequest |
Create a pull request and poll for merge confirmation |
MergeQueue |
Enqueue the branch into Armada's merge queue |
None |
No automated landing; leave work on the branch |
| Value | Description |
|---|---|
LocalOnly |
Delete the local branch after landing |
LocalAndRemote |
Delete both local and remote branches after landing |
None |
Do not delete branches after landing |
| Value | Description |
|---|---|
Open |
Created, missions being set up |
InProgress |
Has active missions in progress |
Complete |
All missions completed |
Cancelled |
Voyage was cancelled |
| Value | Description |
|---|---|
Idle |
Available for assignment |
Working |
Actively working on a mission |
Stalled |
Process appears stalled (no heartbeat) |
Stopping |
In the process of stopping |
| Value | Description |
|---|---|
ClaudeCode |
Anthropic Claude Code CLI |
Codex |
OpenAI Codex CLI |
Gemini |
Google Gemini CLI |
Cursor |
Cursor agent CLI |
Custom |
Custom agent runtime |
| Value | Description |
|---|---|
Assignment |
Mission assignment notification |
Progress |
Progress update from captain |
Completion |
Mission completion notification |
Error |
Error notification |
Heartbeat |
Heartbeat signal |
Nudge |
Ephemeral nudge message |
Mail |
Persistent mail message |
| Value | Description |
|---|---|
Queued |
Waiting to be picked up |
Testing |
Currently being tested |
Passed |
Tests passed, ready to land |
Failed |
Tests failed |
Landed |
Successfully merged into target branch |
Cancelled |
Removed from queue |
| Value | Description |
|---|---|
CreatedAscending |
Sort by creation date, oldest first |
CreatedDescending |
Sort by creation date, newest first (default) |
Query parameters for paginated enumeration. Used as the POST body for all /enumerate endpoints.
{
"PageNumber": 1,
"PageSize": 25,
"Order": "CreatedDescending",
"CreatedAfter": "2026-03-01T00:00:00Z",
"CreatedBefore": null,
"Status": "InProgress",
"FleetId": null,
"VesselId": "vsl_abc123",
"CaptainId": null,
"VoyageId": null,
"MissionId": null,
"EventType": null,
"SignalType": null,
"ToCaptainId": null,
"UnreadOnly": null
}All fields are optional. Omitted fields use defaults. See Pagination for full details.
Request body for creating a voyage with missions.
{
"Title": "API Hardening",
"Description": "Security improvements",
"VesselId": "vsl_abc123",
"Missions": [
{"Title": "Add rate limiting", "Description": "Add rate limiting middleware"},
{"Title": "Add input validation", "Description": "Validate all POST endpoints"}
]
}| Field | Type | Required | Description |
|---|---|---|---|
Title |
string | yes | Voyage title |
Description |
string | no | Voyage description |
VesselId |
string | yes | Target vessel ID |
Missions |
array | no | List of MissionRequest objects |
A mission within a VoyageRequest.
| Field | Type | Required | Description |
|---|---|---|---|
Title |
string | yes | Mission title |
Description |
string | no | Mission description/instructions |
Request body for transitioning a mission status.
{
"Status": "InProgress"
}| Field | Type | Required | Description |
|---|---|---|---|
Status |
string | yes | Target status name (case-insensitive) |
Paginated result wrapper returned by all list and enumerate endpoints.
{
"Success": true,
"PageNumber": 1,
"PageSize": 25,
"TotalPages": 4,
"TotalRecords": 87,
"Objects": [ ... ],
"TotalMs": 3.14
}| Field | Type | Description |
|---|---|---|
Success |
bool | Whether the operation succeeded |
PageNumber |
int | Current page number (1-based) |
PageSize |
int | Number of items per page |
TotalPages |
int | Total number of pages |
TotalRecords |
long | Total records matching the query |
Objects |
array<T> | Result objects for this page |
TotalMs |
double | Query execution time in milliseconds |
Response from GET /api/v1/voyages/{id}.
{
"Voyage": { ... },
"Missions": [ ... ]
}| Field | Type | Description |
|---|---|---|
Voyage |
Voyage | Voyage details |
Missions |
array<Mission> | All missions in this voyage |
Response from GET /api/v1/missions/{id}/diff.
{
"MissionId": "msn_abc123",
"Branch": "armada/msn_abc123",
"Diff": "diff --git ..."
}| Field | Type | Description |
|---|---|---|
MissionId |
string | Mission ID |
Branch |
string | Branch name |
Diff |
string | Git diff output |
Response from GET /api/v1/missions/{id}/log.
{
"MissionId": "msn_abc123",
"Log": "line1\nline2\n...",
"Lines": 100,
"TotalLines": 542
}| Field | Type | Description |
|---|---|---|
MissionId |
string | Mission ID |
Log |
string | Log content (newline-delimited) |
Lines |
integer | Number of lines returned |
TotalLines |
integer | Total lines in log file |
Response from GET /api/v1/captains/{id}/log.
{
"CaptainId": "cpt_abc123",
"Log": "line1\nline2\n...",
"Lines": 100,
"TotalLines": 203
}| Field | Type | Description |
|---|---|---|
CaptainId |
string | Captain ID |
Log |
string | Log content (newline-delimited) |
Lines |
integer | Number of lines returned |
TotalLines |
integer | Total lines in log file |
| # | Method | URL | Description | Auth |
|---|---|---|---|---|
| 1 | POST | /api/v1/authenticate |
Authenticate (get session token) | No |
| 2 | GET | /api/v1/whoami |
Get current identity | Yes |
| 3 | POST | /api/v1/tenants/lookup |
Lookup tenants by email | No |
| 4 | POST | /api/v1/onboarding |
Self-register new user | No* |
| 5 | GET | /api/v1/tenants |
List tenants (paginated) | Admin |
| 6 | POST | /api/v1/tenants/enumerate |
Enumerate tenants | Admin |
| 7 | POST | /api/v1/tenants |
Create tenant | Admin |
| 8 | GET | /api/v1/tenants/{id} |
Get tenant | Yes** |
| 9 | PUT | /api/v1/tenants/{id} |
Update tenant | Admin |
| 10 | DELETE | /api/v1/tenants/{id} |
Delete tenant | Admin |
| 11 | GET | /api/v1/users |
List users (paginated) | Admin |
| 12 | POST | /api/v1/users/enumerate |
Enumerate users | Admin |
| 13 | POST | /api/v1/users |
Create user | Admin |
| 14 | GET | /api/v1/users/{id} |
Get user | Yes** |
| 15 | PUT | /api/v1/users/{id} |
Update user | Admin |
| 16 | DELETE | /api/v1/users/{id} |
Delete user | Admin |
| 17 | GET | /api/v1/credentials |
List credentials (paginated) | Yes** |
| 18 | POST | /api/v1/credentials/enumerate |
Enumerate credentials | Yes** |
| 19 | POST | /api/v1/credentials |
Create credential | Yes** |
| 20 | GET | /api/v1/credentials/{id} |
Get credential | Yes** |
| 21 | PUT | /api/v1/credentials/{id} |
Update credential | Yes** |
| 22 | DELETE | /api/v1/credentials/{id} |
Delete credential | Yes** |
| 23 | GET | /api/v1/status |
System status dashboard | Yes |
| 24 | GET | /api/v1/status/health |
Health check | No |
| 25 | POST | /api/v1/server/stop |
Graceful shutdown | *** |
| 26 | GET | /api/v1/fleets |
List fleets (paginated) | Yes |
| 27 | POST | /api/v1/fleets/enumerate |
Enumerate fleets | Yes |
| 28 | POST | /api/v1/fleets |
Create fleet | Yes |
| 29 | GET | /api/v1/fleets/{id} |
Get fleet | Yes |
| 30 | PUT | /api/v1/fleets/{id} |
Update fleet | Yes |
| 31 | DELETE | /api/v1/fleets/{id} |
Delete fleet | Yes |
| 32 | GET | /api/v1/vessels |
List vessels (paginated) | Yes |
| 33 | POST | /api/v1/vessels/enumerate |
Enumerate vessels | Yes |
| 34 | POST | /api/v1/vessels |
Create vessel | Yes |
| 35 | GET | /api/v1/vessels/{id} |
Get vessel | Yes |
| 36 | PUT | /api/v1/vessels/{id} |
Update vessel | Yes |
| 37 | DELETE | /api/v1/vessels/{id} |
Delete vessel | Yes |
| 38 | GET | /api/v1/voyages |
List voyages (paginated) | Yes |
| 39 | POST | /api/v1/voyages/enumerate |
Enumerate voyages | Yes |
| 40 | POST | /api/v1/voyages |
Create voyage with missions | Yes |
| 41 | GET | /api/v1/voyages/{id} |
Get voyage with missions | Yes |
| 42 | DELETE | /api/v1/voyages/{id} |
Cancel voyage | Yes |
| 43 | DELETE | /api/v1/voyages/{id}/purge |
Permanently delete voyage | Yes |
| 44 | GET | /api/v1/missions |
List missions (paginated) | Yes |
| 45 | POST | /api/v1/missions/enumerate |
Enumerate missions | Yes |
| 46 | POST | /api/v1/missions |
Create mission | Yes |
| 47 | GET | /api/v1/missions/{id} |
Get mission | Yes |
| 48 | PUT | /api/v1/missions/{id} |
Update mission | Yes |
| 49 | PUT | /api/v1/missions/{id}/status |
Transition mission status | Yes |
| 50 | DELETE | /api/v1/missions/{id} |
Cancel mission | Yes |
| 51 | POST | /api/v1/missions/{id}/restart |
Restart failed/cancelled mission | Yes |
| 52 | GET | /api/v1/missions/{id}/diff |
Get mission diff | Yes |
| 53 | GET | /api/v1/missions/{id}/log |
Get mission log | Yes |
| 54 | GET | /api/v1/captains |
List captains (paginated) | Yes |
| 55 | POST | /api/v1/captains/enumerate |
Enumerate captains | Yes |
| 56 | POST | /api/v1/captains |
Create captain | Yes |
| 57 | GET | /api/v1/captains/{id} |
Get captain | Yes |
| 58 | PUT | /api/v1/captains/{id} |
Update captain | Yes |
| 59 | POST | /api/v1/captains/{id}/stop |
Stop captain | Yes |
| 60 | POST | /api/v1/captains/stop-all |
Stop all captains | Yes |
| 61 | GET | /api/v1/captains/{id}/log |
Get captain current log | Yes |
| 62 | DELETE | /api/v1/captains/{id} |
Delete captain | Yes |
| 63 | GET | /api/v1/signals |
List signals (paginated) | Yes |
| 64 | POST | /api/v1/signals/enumerate |
Enumerate signals | Yes |
| 65 | POST | /api/v1/signals |
Send signal | Yes |
| 66 | GET | /api/v1/events |
List events (paginated) | Yes |
| 67 | POST | /api/v1/events/enumerate |
Enumerate events | Yes |
| 68 | GET | /api/v1/merge-queue |
List merge queue (paginated) | Yes |
| 69 | POST | /api/v1/merge-queue/enumerate |
Enumerate merge queue | Yes |
| 70 | POST | /api/v1/merge-queue |
Enqueue branch | Yes |
| 71 | GET | /api/v1/merge-queue/{id} |
Get merge entry | Yes |
| 72 | DELETE | /api/v1/merge-queue/{id} |
Cancel merge entry | Yes |
| 73 | POST | /api/v1/merge-queue/process |
Process merge queue | Yes |
* Gated by AllowSelfRegistration setting.
** Non-admin users are scoped to their own records only.
*** NoAuthRequired by default; requires global admin (IsAdmin = true) when RequireAuthForShutdown is true.
| Service | Default Port | Description |
|---|---|---|
| Admiral REST API | 7890 | This API |
| MCP Server | 7891 | Model Context Protocol (Voltaic) for AI tool use |
| WebSocket Hub | 7892 | Real-time event streaming and command interface |
All responses include permissive CORS headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Token, X-Api-Key