Skip to main content

API Reference

Base URL: http://<server>:45045/api/v1

Interactive docs (Swagger): http://<server>:45045/doc

All endpoints (except /authentication/) require a JWT Bearer token. See Scripting Overview for authentication examples.


Standard Response Envelope

{
"status": "200",
"message": "Success",
"data": { ... }
}

Error responses use standard HTTP status codes. Common ones:

CodeMeaning
400Bad request / missing or invalid parameters
401Unauthorized — missing or expired token
404Resource not found
429Rate limit exceeded
500Internal server error

Authentication — /api/v1/authentication/

MethodPathAuthDescription
POST/authentication/NoneLogin. Returns access + refresh tokens.
POST/authentication/refreshRefresh tokenExchange a refresh token for a new access token.
POST/authentication/registerBearerRegister a new operator account.

POST /authentication/

Request body:

{ "username": "longhaul", "password": "P@ssw0rd1!" }

Response data:

{
"access_token": "eyJ...",
"refresh_token": "eyJ..."
}

Tokens expire: access = 15 minutes, refresh = 1 day.


POST /authentication/refresh

Supply the refresh token as the Bearer token header.

Response data:

{ "access_token": "eyJ..." }

POST /authentication/register

Requires an existing valid access token.

Request body:

{ "username": "new_operator", "password": "SecurePass1!" }

Implants — /api/v1/implants/

MethodPathDescription
GET/implants/List all implants
POST/implants/Create a blank implant entry (returns a UUID)
GET/implants/<uuid>Get a single implant
PUT/implants/<uuid>Update implant metadata
DELETE/implants/<uuid>Delete an implant from the graph
POST/implants/<uuid>/taskQueue a task for an implant
GET/implants/<uuid>/tasksPeek at currently queued (pending) tasks
DELETE/implants/<uuid>/tasksClear all pending tasks for an implant
GET/implants/<uuid>/task/<task_uuid>Get the status/result of a specific task
GET/implants/<uuid>/tasks/historyGet full task history from MySQL
POST/implants/searchSearch implants by a term
POST/implants/history/searchSearch task history by a term

GET /implants/

Returns all implants known to the server.

Response data: Array of implant objects:

[
{
"implant_uuid": "01932ba4-...",
"system_hostname": "DESKTOP-ABC123",
"external_ip": "10.0.0.5",
"listener_uuid": "01932ba4-...",
...
}
]

POST /implants/<uuid>/task

Queue a command for an implant. The implant picks it up on its next beacon.

Accepts application/json or application/msgpack.

Request body:

{
"implant_uuid": "01932ba4-...",
"task": {
"task_name": "ls",
"args": { "directory": "C:\\Users\\" }
}
}

Response data:

{ "task_uuid": "01932ba4-yyyy-..." }

Use the returned task_uuid to poll for the result.

Task Names Reference

Task NameArgs
exit(none)
sleepsleep_time (int, seconds)
cddirectory (string)
lsdirectory (string)
file downloadfile_path (string)
file uploadfile_path (string), file_contents (bytes)
memstore list(none)
memstore uploadfile_name (string), file_contents (bytes)
memstore downloadfile_name (string)
memstore deletefile_name (string)
memstore clear(none)
strat active(none)
strat list(none)
strat set poststrategy_name (string)
strat set getstrategy_name (string)
strat set bothget_strategy_name (string), post_strategy_name (string)
bofbof_contents (bytes), bof_args (string)
link smbprotocol ("smb"), target (string), inbox_pipe (string), outbox_pipe (string)
unlink smbchild_uuid (string)
link list(none)

Binary args: For tasks that take binary data (file upload, memstore upload, bof), send raw bytes inside a msgpack payload. If using JSON, the client handles base64 decoding before serializing — the server and implant always work with raw bytes.


GET /implants/<uuid>/task/<task_uuid>

Retrieve the status and result of a specific task.

Response data:

{
"task_uuid": "...",
"implant_uuid": "...",
"task_request": { "task_name": "ls", "args": { "directory": "C:\\" } },
"task_response": {
"message": { "type": "text", "value": "Success" },
"data": { "type": "text", "value": "file1.txt\nfile2.txt\n" },
"windows_error_code": { "type": "text", "value": "0" }
}
}

task_response is null until the implant has checked in and returned a result.


GET /implants/<uuid>/tasks/history

Returns all completed tasks for an implant from MySQL.

Query parameters:

ParamTypeDescription
sinceUUIDv7 stringOnly return tasks with a task_uuid newer than this value. Use the last seen task_uuid to poll incrementally.

POST /implants/search

Search implants by hostname, IP, UUID, or any indexed field.

Request body:

{ "search_term": "DESKTOP" }

Listeners — /api/v1/listeners/

MethodPathDescription
GET/listeners/List all listeners
POST/listeners/Create and start a new listener
GET/listeners/<uuid>Get a single listener
PATCH/listeners/<uuid>Start or stop a listener ({"active": true/false})
DELETE/listeners/<uuid>Stop and permanently delete a listener

POST /listeners/

Request body:

{
"listener_name": "http_mimicry",
"listener_type": "raw",
"listener_host": "0.0.0.0",
"listener_port": 80,
"listener_profile_name": "raw_http_profile.toml",
"listener_profile_contents": "<contents of raw_http_profile.toml>",
"listener_notes": "Optional notes"
}

Response data: The created listener object, including its generated listener_uuid.


PATCH /listeners/<uuid>

Start or stop an existing listener without deleting it.

{ "active": true }

Returns 200 with a message — also returns 200 (not an error) if the listener is already in the requested state.


Build — /api/v1/build/

MethodPathDescription
POST/build/Submit a new implant build job
GET/build/List all builds (payloads) in the database
GET/build/jobs/<build_uuid>Get the status of a specific build job
GET/build/<hash>Download a compiled payload binary
DELETE/build/<hash>Delete a payload from the database
GET/build/<hash>/sourceDownload the source code archive (ZIP) for a build

POST /build/

Submit a build. The build runs synchronously inside a Docker container.

Request body:

{
"implant_name": "my_implant",
"listener_uuids": ["01932ba4-...", "01932ba4-..."],
"initial_get_profile_listener_uuid": "01932ba4-...",
"initial_post_profile_listener_uuid": "01932ba4-...",
"options": {
"debug": false,
"clear_cache": false
}
}
FieldDescription
implant_nameName for the build / output artifacts
listener_uuidsList of listener UUIDs to bake strategies for into the implant
initial_get_profile_listener_uuidWhich listener's GET profile to use at first boot
initial_post_profile_listener_uuidWhich listener's POST profile to use at first boot
options.debugEnable debug logging in the implant binary (-DENABLE_IMPLANT_LOGS=ON)
options.clear_cacheClear the Docker build cache before compiling

Response data:

{
"build_uuid": "01932ba4-...",
"build_stats": { "build_time": 12.4 }
}

Artifacts (.exe, .dll) are stored in MySQL after a successful build. Use GET /build/<hash> to download them.


GET /build/jobs/<build_uuid>

Check the status of a build.

Response data:

{
"build_uuid": "...",
"payload_name": "my_implant",
"build_status": "complete",
"payload_hash": "a1b2c3d4..."
}

build_status values: building, complete, failed.


Filestore — /api/v1/filestore/

Server-side file storage for staging files before pushing them to implants.

MethodPathDescription
POST/filestore/Upload a file (base64-encoded in JSON body)
GET/filestore/List all stored files
GET/filestore/<file_uuid>Download a file
DELETE/filestore/<file_uuid>Delete a file

POST /filestore/

{
"file_name": "mimikatz.exe",
"file_contents": "<base64_encoded_bytes>"
}

Response data:

{ "file_uuid": "01932ba4-..." }

Graph — /api/v1/graph/

Returns the implant topology and network graph data used to populate the Graph view in the UI.

MethodPathDescription
GET/graph/Get all nodes and relationships in the graph

Profiles — /api/v1/profiles/

Profiles are stored server-side and managed through this API. The UI uses these endpoints for all profile operations — there is no filesystem dependency.

MethodPathDescription
GET/profiles/List all stored profiles (metadata only, no contents)
POST/profiles/Upload or update a profile
GET/profiles/<name>Download a profile by name (full contents)
DELETE/profiles/<name>Delete a profile by name
POST/profiles/seedBulk-upload default profiles
POST/profiles/previewParse and render a profile TOML for visualization

GET /profiles/

Returns all profiles stored on the server. Contents are not included — use GET /profiles/<name> to fetch a specific profile's TOML.

Response data:

{
"profiles": [
{
"artifact_uuid": "01932ba4-...",
"artifact_name": "raw_http_profile.toml",
"content_hash": "a1b2c3...",
"created_at": 1719700000000,
"updated_at": 1719700000000
}
]
}

POST /profiles/

Upload a new profile or update an existing one. If a profile with the same name already exists and the content is identical (same SHA256 hash), the request is a no-op. If the content differs, the profile is updated.

Request body:

{
"profile_name": "raw_http_profile.toml",
"profile_contents": "<full TOML string>"
}

Response data:

{
"artifact_uuid": "01932ba4-...",
"artifact_name": "raw_http_profile.toml",
"content_hash": "a1b2c3...",
"created": true
}

created is true for new profiles, false for updates or no-ops.


GET /profiles/<name>

Download a specific profile by filename.

Response data:

{
"artifact_uuid": "01932ba4-...",
"artifact_name": "raw_http_profile.toml",
"artifact_contents": "[profile]\nname = \"HTTP Mimicry\"\n...",
"content_hash": "a1b2c3...",
"created_at": 1719700000000,
"updated_at": 1719700000000
}

DELETE /profiles/<name>

Delete a profile from the server. Returns 404 if the profile does not exist.


POST /profiles/seed

Bulk-upload multiple profiles in one request. Each profile follows upsert semantics (same as POST /profiles/).

Request body:

{
"profiles": [
{ "profile_name": "raw_http_profile.toml", "profile_contents": "..." },
{ "profile_name": "raw_ntp_profile.toml", "profile_contents": "..." }
]
}

Response data:

{
"seeded": 6,
"profiles": ["raw_http_profile.toml", "raw_ntp_profile.toml", "..."]
}

POST /profiles/preview

Parse and render a profile TOML, returning structured output with per-step transform chains. Always returns HTTP 200. Parse failures are returned as data (check data.validation.parse_ok), not as HTTP errors.

Request body:

{ "profile_contents": "<raw TOML string>" }

Response data:

{
"profile_name": "HTTP Mimicry",
"profile_author": "LongHaul Team",
"smb": null,
"raw_profiles": [
{
"name": "default",
"get": { "proto": "tcp", "client": { ... }, "server": { ... } },
"post": { "proto": "tcp", "client": { ... }, "server": { ... } }
}
],
"validation": {
"parse_ok": true,
"parse_error": null,
"missing_fields": [],
"warnings": []
}
}

See Mimicry for the full response shape and field descriptions.


Health — /api/v1/health/

MethodPathAuthDescription
GET/health/NoneReturns server health status