API Endpoint Map

This is the full reference for Firecracker's REST API — the entire user-facing control surface, served over a Unix domain socket by the API thread in the firecracker binary. Every row is method + path → purpose → example JSON body → where it's taught. Use it the way you'd use a phone book: you know the endpoint, you want the body shape, you want where to read next.

The authoritative source is the OpenAPI spec shipped in the repo. Read it, don't trust this page blindly:

# The whole surface, from the spec on YOUR branch:
rg -n "^\s+/|operationId|swagger:" src/firecracker/swagger/firecracker.yaml | less
# A specific endpoint's exact request body:
rg -n "/machine-config" -A30 src/firecracker/swagger/firecracker.yaml

Warning: Endpoints, fields, and which are pre-boot vs runtime evolve by version. Newer endpoints (/pmem, /serial, /hotplug/memory, /balloon/hinting/*, /vm/config) may not exist on your branch — verify. Field renames happen (enable_diff_snapshots → track_dirty_pages); deprecated aliases linger. The swagger.yaml and CHANGELOG.md are ground truth; this page is the map.


How to drive the API

One process is one microVM. You start firecracker listening on a socket, then configure pre-boot resources with PUTs, then PUT /actions {InstanceStart}. After boot, only the runtime-allowed endpoints work.

API=/tmp/firecracker.socket
sudo ./firecracker --api-sock $API &        # or --config-file config.json --no-api
curl -X PUT --unix-socket $API \
  --data '{"kernel_image_path":"./vmlinux-6.1.x","boot_args":"console=ttyS0 reboot=k panic=1"}' \
  http://localhost/boot-source
ColumnMeaning
Method + pathWhat you send. {id} is a path parameter (the resource id).
Phasepre-boot (only before InstanceStart), runtime (only after), or any.
PurposeWhat it configures or does.
Covered inThe level / deep-dive / lab that teaches the path behind it.

Note: A microVM can also be configured entirely from a --config-file with --no-api (no API thread at all). The JSON sections are kebab-case (boot-source, drives, machine-config, network-interfaces, vsock, balloon, logger, metrics, mmds-config, entropy, …) and the file boot also starts the VM. Same data, different door — see Level 3.


Instance & lifecycle

Method + pathPhasePurposeCovered in
GET /anyInstance info: id, state (Not started/Running/Paused), version, app name../deep-dives/api-server-and-action-channel.md
PUT /actionsanyOne-shot actions: InstanceStart, FlushMetrics, SendCtrlAltDelLab 3.1, ../deep-dives/signals-shutdown-and-reset.md
PATCH /vmruntimePause / resume the microVM: {"state":"Paused"} / {"state":"Resumed"}../deep-dives/snapshotting.md, Lab 9.2
GET /versionanyFirecracker version../release-governance/release-process.md
// PUT /actions — boot the configured microVM:
{ "action_type": "InstanceStart" }

// PUT /actions — graceful guest reboot (caught by the partial i8042):
{ "action_type": "SendCtrlAltDel" }

// PATCH /vm — pause before snapshotting:
{ "state": "Paused" }

Note: InstanceStart is the moment the vCPU threads are created and each enters KVM_RUN. Everything before it is configuration; everything after is runtime. The pre-boot/runtime split is enforced by PrebootApiController vs RuntimeApiController — see ../deep-dives/api-server-and-action-channel.md.


Boot & machine configuration (pre-boot)

Method + pathPhasePurposeCovered in
PUT /boot-sourcepre-bootKernel image path, boot args (cmdline), optional initrd../deep-dives/the-boot-sequence.md, Lab 6.3
GET/PUT/PATCH /machine-configpre-boot (PATCH limited)vCPU count, mem size, SMT, huge pages, CPU template, dirty-page tracking../deep-dives/cpu-templates-and-cpuid.md, Level 6
PUT /cpu-configpre-bootA custom CPU template (CPUID/MSR normalization)../deep-dives/cpu-templates-and-cpuid.md, Lab 4.3
// PUT /boot-source
{ "kernel_image_path": "./vmlinux-6.1.x",
  "boot_args": "console=ttyS0 reboot=k panic=1 pci=off nomodule",
  "initrd_path": null }

// PUT /machine-config  (defaults: vcpu_count=1, mem_size_mib=128, smt=false)
{ "vcpu_count": 2, "mem_size_mib": 1024, "smt": false,
  "track_dirty_pages": false, "huge_pages": "None", "cpu_template": "None" }

Warning: track_dirty_pages is the current field name (was enable_diff_snapshots). It must be true at boot for diff snapshots to work later — you cannot retrofit it. Verify the field set on your branch.


Storage & devices (pre-boot config, some runtime PATCH)

Method + pathPhasePurposeCovered in
PUT/PATCH /drives/{id}PUT pre-boot, PATCH runtimeA virtio-block device; PATCH updates path / rate limiter live../deep-dives/virtio-block.md, Lab 7.1
PUT/PATCH /network-interfaces/{id}PUT pre-boot, PATCH runtimeA virtio-net device over a host TAP; PATCH updates rate limiters../deep-dives/virtio-net-and-tap.md, ../masterclass/networking/lab-01-tap-and-bridges.md
PUT /vsockpre-bootThe single virtio-vsock device (guest CID + host Unix socket)../deep-dives/virtio-vsock.md, ../masterclass/virtio-devices/lab-03-vsock.md
PUT /entropypre-bootThe virtio-rng device (host randomness)../deep-dives/virtio-rng-entropy.md
GET/PUT/PATCH /balloon (+ GET/PATCH /balloon/statistics)PUT pre-boot, PATCH runtimeThe memory balloon (inflate/deflate); statistics polling interval../deep-dives/virtio-balloon.md, ../engineering/oversubscription-and-density.md
// PUT /drives/rootfs
{ "drive_id": "rootfs", "path_on_host": "./ubuntu-24.04.ext4",
  "is_root_device": true, "is_read_only": false }

// PATCH /drives/rootfs  (runtime: swap the backing file or rate limiter)
{ "drive_id": "rootfs", "path_on_host": "./new-rootfs.ext4" }

// PUT /network-interfaces/net1
{ "iface_id": "net1", "guest_mac": "06:00:AC:10:00:02",
  "host_dev_name": "tap0",
  "rx_rate_limiter": { "bandwidth": { "size": 1048576, "refill_time": 1000 } } }

// PUT /vsock
{ "vsock_id": "vsock0", "guest_cid": 3, "uds_path": "/tmp/v.sock" }

// PUT /balloon
{ "amount_mib": 256, "deflate_on_oom": true, "stats_polling_interval_s": 1 }

Note: /vsock is singular — exactly one vsock device per microVM. Block and net are keyed by {id} and you may have several. The rate-limiter shape (bandwidth / ops token buckets with size / one_time_burst / refill_time) is the same across drives and interfaces — see ../deep-dives/rate-limiting-token-bucket.md.


MMDS — the metadata service

Method + pathPhasePurposeCovered in
PUT /mmds/configpre-bootMMDS version (V1/V2), the network iface(s) it answers on, IPv4 addr../deep-dives/mmds-metadata-service.md, ../masterclass/networking/lab-03-mmds.md
GET/PUT/PATCH /mmdsanyRead/replace/merge the metadata document the guest will read../deep-dives/mmds-metadata-service.md
// PUT /mmds/config  (V2 is token/session-based, IMDSv2-like)
{ "version": "V2", "network_interfaces": ["net1"], "ipv4_address": "169.254.169.254" }

// PUT /mmds  (the document the guest fetches over HTTP via the dumbo stack)
{ "latest": { "meta-data": { "instance-id": "i-abc123" } } }

Note: The guest reaches MMDS over a normal HTTP socket served by the in-VMM dumbo TCP/IP stack — there is no host-side metadata server. V2 requires the guest to obtain a session token first (like EC2 IMDSv2). V1 is deprecated.


Observability

Method + pathPhasePurposeCovered in
PUT /loggerpre-bootLog destination, level, format, optional module filtering../deep-dives/logging-and-metrics.md
PUT /metricspre-bootThe metrics sink (a FIFO/file the VMM flushes structured metrics to)../deep-dives/logging-and-metrics.md, ../masterclass/debugging-profiling/lab-02-tracing-and-metrics.md
// PUT /logger
{ "log_path": "/tmp/fc.log", "level": "Info", "show_level": true, "show_log_origin": true }

// PUT /metrics  (then PUT /actions {FlushMetrics} to force a flush)
{ "metrics_path": "/tmp/fc-metrics.fifo" }

Tip: PUT /actions {"action_type":"FlushMetrics"} forces an immediate metrics flush — useful in tests and labs. Metrics are emitted as one JSON object per flush.


Snapshot / restore

Method + pathPhasePurposeCovered in
PUT /snapshot/createruntime (paused)Write the microVM state file + memory file; snapshot_type Full or Diff../deep-dives/snapshotting.md, ../masterclass/snapshotting/lab-01-create-and-restore.md
PUT /snapshot/loadpre-boot (fresh process)Restore from a state file + a mem_backend (File or Uffd); optional resume_vm../deep-dives/snapshotting.md, Lab 9.2
// Create: PATCH /vm {Paused}  →  PUT /snapshot/create  →  PATCH /vm {Resumed}
{ "snapshot_type": "Full",
  "snapshot_path": "/snap/state.file",
  "mem_file_path": "/snap/mem.file" }

// Load (in a fresh firecracker process):  PUT /snapshot/load
{ "snapshot_path": "/snap/state.file",
  "mem_backend": { "backend_type": "Uffd", "backend_path": "/tmp/uffd.sock" },
  "enable_diff_snapshots": false,
  "resume_vm": true }

Warning: A snapshot is two files — the state file (KVM + device state) and the memory file (guest RAM). On load, backend_type: "Uffd" hands page faults to a userspace handler over a Unix socket for lazy loading; "File" maps the memory file MAP_PRIVATE/COW. The standalone mem_file_path on load is deprecated in favor of mem_backend. Verify the exact field set on your branch — this surface has churned. See ../masterclass/snapshotting/lab-02-uffd-page-fault-handler.md.


Newer / experimental endpoints — verify before relying on them

These appear on recent branches but may be absent, renamed, or feature-gated on yours. Always confirm against swagger.yaml and CHANGELOG.md.

Method + pathPurposeVerify with
PUT/PATCH /pmem/{id}virtio-pmem persistent-memory devicerg -n "/pmem" src/firecracker/swagger/firecracker.yaml
PUT /serialConfigure the serial console (buffering / output) explicitlyrg -n "/serial" src/firecracker/swagger/firecracker.yaml
PUT/PATCH /hotplug/memoryHot-add memory to a running guest (virtio-mem)rg -n "hotplug" src/firecracker/swagger/firecracker.yaml
PUT /balloon/hinting/*Free-page hinting variants for the balloonrg -n "hinting" src/firecracker/swagger/firecracker.yaml
GET /vm/configRead back the full effective VM configurationrg -n "/vm/config" src/firecracker/swagger/firecracker.yaml
# Definitive "does my branch have it?" check:
rg -n "/pmem|/serial|/hotplug|/vm/config|hinting" src/firecracker/swagger/firecracker.yaml
gh pr list --repo firecracker-microvm/firecracker --search "pmem OR hotplug" --state merged

Error shape & the request path

Every API error returns a JSON body with a fault_message; HTTP status reflects the class (400 bad request, 405 method/phase not allowed, etc.). The path behind every endpoint is the same: the API thread parses the HTTP into a ParsedRequest, converts it to a VmmAction, sends it over an mpsc channel, wakes the VMM thread with an eventfd, and reads back a VmmData or VmmActionError.

sequenceDiagram
    participant C as curl (UDS)
    participant A as API thread
    participant V as VMM thread
    C->>A: PUT /machine-config {json}
    A->>A: parse → ParsedRequest → VmmAction
    A->>V: mpsc send(Box<VmmAction>) + eventfd wake
    V->>V: PrebootApiController dispatches
    V-->>A: Box<Result<VmmData, VmmActionError>>
    A-->>C: 204 No Content  /  4xx {fault_message}

Trace it end to end in Lab 3.1 and ../deep-dives/api-server-and-action-channel.md.

# Find the handler for any endpoint by grepping the parser, not a line number:
rg -n "machine-config|boot-source|/snapshot/|/actions" src/firecracker/src/api_server/
# Find which VmmAction an endpoint maps to:
rg -n "enum VmmAction\b" -A80 src/vmm/src/rpc_interface.rs

  • KVM ioctl Cheat-Sheet — what InstanceStart ultimately drives the vCPU threads into.
  • Key Types by Crate — ApiServer, ParsedRequest, VmmAction, VmResources, and the per-resource config structs.
  • Glossary — every endpoint's underlying device/concept defined.

Next: KVM ioctl Cheat-Sheet — the layer beneath InstanceStart.