DecompilerAI
REST API - v1

DecompilerAI API

Headless REST access to the same engines the web UI uses: upload a binary, decompile it, fetch the C. Same credits, same cache, no browser required.

Base URL https://decompiler.ai/api/v1
Get an API key openapi.yaml

1Get an API key

Keys are created on your profile page (section "API keys"). A key looks like dcai_... and is shown in full exactly once, when it is created or rotated; store it in a secret manager. You can label keys, give each one an optional monthly credit cap and its own rate limit, rotate them and revoke them at any time. API keys are separate from your browser session: a session token never works on the API, and an API key never works as a login.

2Authentication

Send the key on every request, either as a header of its own or as a bearer token:

curl -s https://decompiler.ai/api/v1/me -H "X-API-Key: dcai_YOUR_KEY"
curl -s https://decompiler.ai/api/v1/me -H "Authorization: Bearer dcai_YOUR_KEY"

Missing or revoked keys answer 401 {"error": ...}. All errors are JSON with an error field.

3The full flow: upload, decompile, fetch C

3.1 Upload a binary

curl -s https://decompiler.ai/api/v1/binaries \
  -H "X-API-Key: dcai_YOUR_KEY" \
  -F "file=@./program"
# 201 {"id": 42, "name": "1755600000000_program", "sha256": "...", "size_bytes": 16384, "format": "elf"}

ELF, PE/EXE, Mach-O, Android APK, APK sets (XAPK / APKS / APKM) and DEX are accepted (64 MB global cap; your plan sets the per-file size, an APK's own size cap, and how many files you can keep). An APK is a container: its summary lists the members (classes*.dex, lib/<abi>/*.so), and POST /api/analysis/:file/apk-open {member} extracts one into a file of its own (linked to the package, no file slot) that every other call then analyses. An APK set lists its base and split APKs the same way; opening one yields an APK. Use the returned id (or name) in every later call.

3.2 List its functions

curl -s "https://decompiler.ai/api/v1/binaries/42/functions?limit=50" \
  -H "X-API-Key: dcai_YOUR_KEY"
# {"total": 128, "functions": [{"name": "main", "addr": 4416, "size": 214}, ...]}

3.3a Decompile one function (synchronous)

curl -s https://decompiler.ai/api/v1/binaries/42/decompile \
  -H "X-API-Key: dcai_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"engine": "ghidra", "level": "l0", "addr": "0x1140"}'
# {"ok": true, "scope": "function", "code": "int main(void) { ... }", "cached": false, ...}

Engines: ghidra (free, instant), gpt, decai (the in-house model, per function and whole program). decai decompiles ELF (x86-64, AArch64) and PE (x86-64) with a COFF symbol table (a stripped PE is refused); ghidra and gpt decompile every ELF and PE; Mach-O can be browsed but not decompiled yet. An engine the binary's format does not support is refused before anything is billed: 400 for one function, 415 for a whole-program run; a full whole-program queue answers 503 with Retry-After. Results are cached per function, engine and level: repeating a call is free and returns "cached": true. Per-function levels are l0, l0-l1, l0-l4, l0-l1-l4 (L2/L3 need the whole program).

3.3b Decompile the whole program (async job)

curl -s https://decompiler.ai/api/v1/binaries/42/decompile \
  -H "X-API-Key: dcai_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"engine": "ghidra", "level": "l0-l4"}'
# 202 {"ok": true, "scope": "program", "job_id": 1337, "poll": "/api/v1/jobs/1337", "estimated_credits": 128, ...}

curl -s https://decompiler.ai/api/v1/jobs/1337 -H "X-API-Key: dcai_YOUR_KEY"
# {"id": 1337, "status": "RUNNING", "stages": {"analysis": {"status": "done"}, ...}}

Poll until status is DONE (or FAILED, with an error).

FORGE. Library functions the signature database recognizes (GET /api/v1/binaries/{id}/forge: name, library, version, tier, confidence) are left out of a whole-program run: they appear in the output under their real name with the library's source text, are not decompiled and not charged (forge_skipped in the 202, estimated_credits excludes them). Send "include_forge": true to decompile them too.

3.4 Fetch the C (or a .zip project)

# JSON (program C + per-function code)
curl -s "https://decompiler.ai/api/v1/binaries/42/decompiled?engine=ghidra&level=l0-l4" \
  -H "X-API-Key: dcai_YOUR_KEY"

# one .c file
curl -s "https://decompiler.ai/api/v1/binaries/42/decompiled?engine=ghidra&level=l0-l4&format=c" \
  -H "X-API-Key: dcai_YOUR_KEY" -o program.c

# a .zip project (program.c, functions/*.c, include/decompiled.h, Makefile)
curl -s "https://decompiler.ai/api/v1/binaries/42/decompiled.zip?engine=ghidra&level=l0-l4" \
  -H "X-API-Key: dcai_YOUR_KEY" -o program.zip

4Levels (stage tokens)

A level names exactly the pipeline stages that run:

l0
The engine's raw output.
l1
Syntax repair.
l2
Compile and link.
l3
Behaviour verification.
l4
Independent readability pass.

L1, L2 and L3 are the cumulative verify chain: requesting l3 implies l1 and l2. L4 is independent of them. Examples: l0, l0-l4, l0-l1-l2-l3-l4. Verify stages (L1 and up) need a Pro or Team plan.

5Endpoint reference

POST/api/v1/binariesUpload (multipart field file) -> id, sha256, format
GET/api/v1/binariesList your binaries with latest job + finished runs
GET/api/v1/binaries/{id}Summary + status of one binary
GET/api/v1/binaries/{id}/functionsFunction list (q, offset, limit)
GET/api/v1/binaries/{id}/forgeLibrary functions recognized by FORGE (name, lib, version, tier, confidence)
POST/api/v1/binaries/{id}/decompileWith addr: one function, sync. Without: whole program -> 202 + job id
GET/api/v1/jobs/{id}Whole-program job status with per-stage progress
GET/api/v1/binaries/{id}/decompiledA finished run's C (?engine&level, format=json|c)
GET/api/v1/binaries/{id}/decompiled.zipThe run as a .zip project
GET/api/v1/meAccount, key, credit balance and the current price list

6Credits and limits

  • credits Same credits as the web UI. An API decompile charges exactly what the same click costs in the browser; prices come from GET /api/v1/me. Ghidra L0 is free. Cached results are free.
  • 402 Insufficient credits (top up or upgrade on the pricing page), or this key's monthly credit cap is reached (the error says which).
  • 429 The key's per-minute rate limit was exceeded; honour the Retry-After header. The default is 60 requests/min, settable per key via the rate_per_min field of POST /api/keys (up to the server ceiling, 600/min).
  • jobs Whole-program runs are billed per function by the run itself; the 202 response carries an estimated_credits figure from a pre-count. The per-key monthly cap is reserved atomically before a billable request runs and given back when nothing ran (refused, cached, failed).

7OpenAPI spec

The machine-readable contract lives at https://decompiler.ai/openapi.yaml (OpenAPI 3.1). Point your client generator, Postman or any agent framework at it. Its analysis tag lists the analysis routes the inspector and the agent tools use (project documents and snapshots, code/data marks and flow repairs, decompiler corrections, debug files, header import, Android resources and JNI, the live debugger's session routes and its saved run configurations): they take the same key as a bearer token.

8Agents: MCP server and the in-app agent

Every analysis capability is also a tool an AI agent can call. Read tools: list functions, disassemble, decompile (Ghidra free, gpt priced; decai runs whole programs), cross-references, call graph, strings, imports, regex/byte search, semantic search, raw bytes, function diff, the functions of an older version matched to this one with a confidence and reason per pair and the ambiguous ones listed, never picked (match_versions), the patch list, packer detection, the script library, the type header and what it declares (get_types), where a function's decompilation can be corrected (correction_sites), every line that uses a struct member (member_xrefs: read / write / address-taken), the call-graph paths between two functions (call_paths: a connection, not a data-flow proof), the C++ classes from the RTTI (classes: bases, vtables, every slot new / override / inherited / pure), what a virtual call can reach (virtual_targets: exact / heuristic / unresolved, per call site or per target), static value queries over Ghidra's data flow (call_arguments: every call site of a function with the value of one argument, exact or unknown with its origin; value_origin: where one value comes from, where it goes, and whether it is compared on every path to a call - read-only, nothing runs the binary), the project snapshots (snapshot_list, and snapshot_diff: what a restore would change), and for Android packages the resources (android_resources, where one is used: android_resource_xrefs) and the JNI map (jni_map: native methods to their functions in each ABI's libraries). Write tools change the binary or run code: annotate (rename, comment, prototype, bookmark, and code vs data: define data, mark a string, mark code, undefine), the flow repairs (set_function_bounds, set_noreturn, set_sp_delta, set_switch_table), the decompiler corrections (correct_decompilation: a call's prototype, a union member, a split variable), the type header and import_header (a real .h file appended to it), vectorize, patch / remove_patch (bytes, assembled instructions, strings, added code blocks, detours, hooks, wrappers), emulate (the jailed Unicorn emulator: arguments, registers, memory, breakpoints, trace, stdin/stdout), run_script (a Python script in the scripting SDK), unpack / unpack_analyze and snapshot_save / snapshot_restore (the whole project state of a binary: every annotation, the type header, loader settings and the patch set, saved under a name and restored exactly), transfer_annotations (carry the names, prototypes, comments, bookmarks, local names and types of an older version into this one: a preview first, then one batch with a transfer id that one call undoes). Every read after a patch sees the patched bytes, and an open Inspect tab refreshes live when an agent changes the file. The same tool set is exposed two ways.

8.1 In the inspector: Agent mode

Open a binary in Inspect and press 🤖 Agent next to the chat. The assistant then calls the tools itself, shows each step, and answers from what it read. Each model turn costs one chat message; a tool costs what it costs in the API (a Ghidra decompile is free).

8.2 From your own agent: MCP

DecompilerAI is an MCP server. Any MCP client (Claude Desktop, Claude Code, Cursor, your own) can connect with an API key from /profile:

// hosted (no install): MCP over HTTP
POST https://decompiler.ai/mcp
Authorization: Bearer dcai_...
{"jsonrpc":"2.0","id":1,"method":"tools/list"}

// Claude Desktop / Claude Code: a local stdio server (needs node)
{ "mcpServers": { "decompilerai": {
    "command": "node", "args": ["/path/to/DecompilerAI/mcp/server.js"],
    "env": { "DECOMPILERAI_API_KEY": "dcai_...", "DECOMPILERAI_URL": "https://decompiler.ai" } } } }

Tools act with the key's identity and are billed like the API: the key's monthly credit cap and rate limit apply. Upload binaries through the API or the site first; list_binaries tells the agent the file names to use.

Key scope. A key is created read-only or read-write on /profile. A read-only key is only shown the read tools and every write it attempts (through MCP, the analysis API or /api/v1) answers 403 with read_only: true - the safe choice for an agent you do not fully trust. A read-write key can do everything your account can, patching included. Neither kind can create, rotate or revoke keys.

8.3 The live debugger

An agent drives the same debug session you see in the inspector's Emulate tab: one per file, the emulator paused between commands, every step the agent takes shown live in your tab and labelled agent (status line, Console, API log). debug_state says what is open, what a whole-program start costs and which run configurations are saved; debug_start runs a function, from an address, or the whole program with argv, environment, stdin and files (or a saved configuration by name); debug_breakpoint sets / deletes / lists breakpoints (conditions, hit counts, log-only, memory and API breakpoints, one-click hooks); debug_continue, debug_step (into, over, out, back in time) and debug_run_to wait for the next stop and answer compactly (pc, reason, the registers that changed, top of stack, the console's last output); debug_set changes a register, flag, memory or the pc; debug_read_memory, debug_eval, debug_origin (who wrote this value), debug_stdin, debug_files, debug_api_log and debug_stop complete it. A read-only key may look (state, memory, expressions, files, API log) but not start, run or change a session.

A whole-program session costs credits per start (the same price as the button). An agent never starts one blind: without accept_price (the price you agreed to) the start answers 428 with the price and nothing runs or is charged. Function and from-cursor sessions are free. Over plain HTTP the routes are POST /api/analysis/{file}/debug/start, GET /api/analysis/{file}/debug/session and POST /api/analysis/{file}/debug/current/{command}?wait=10 (see the OpenAPI spec); run configurations are GET|PUT|DELETE /api/analysis/{file}/run-configs[/{name}].