devirt.re
Create account
Menu

Your first analysis.
A clear path.

Use the same analysis service as the workspace, from your own tools. Submit a file, keep its job ID, and retrieve the evidence when it is ready.

Base URLhttps://devirt.re/api/v1

Interactive Try the three-step API example

POST/api/v1/submitBearer ••••
202 / Example responsequeued
job_id
demo_001
status
queued
progress
0%
Your evidence packageAvailable after successful completion

Keep this job ID.

The accepted scope and funding determine when processing starts. Every later request refers to the same job.

Local simulation, not a live API request. No file is uploaded and no credit is used.

Create your key.

API access comes with an active Team, Professional or Enterprise plan. Open API & settings, create a key, and store it as DEVIRT_API_KEY in your server environment. Never put it in browser code or a public repository.

jobs:writeSubmit files and fund jobs
jobs:readRead your job status
results:readRetrieve your analysis

Only reading existing jobs? Leave out jobs:write. Keys are shown once and can be revoked.

Send your file.

POST/packages/triage

Request a Triage Plus summary for one authorized file. This bounded static check identifies file structure and protection indicators; it does not recover code.

Fileauthorized-sample.bin
OutputBounded JSON summary
DeliveryStatic inventory · 30-day retention
Payment$29 or one Triage Plus allowance

A working request.

Choose a request language
submit.pyPython / httpx
import os
import uuid
 
import httpx
 
headers = {
    "Authorization": f"Bearer {os.environ['DEVIRT_API_KEY']}",
    "Idempotency-Key": str(uuid.uuid4()),
}
 
# Keep this key when retrying the same request.
with open("authorized-sample.bin", "rb") as binary:
    response = httpx.post(
        "https://devirt.re/api/v1/packages/triage",
        headers=headers,
        files={"binary": binary},
        data={
            "product_id": "triage_plus",
            "use_allowance": "false",
            "authorization": "true",
        },
        timeout=300,
    )
 
response.raise_for_status()
job = response.json()
print(job["job_id"])
Submit a binaryShell / cURL
curl https://devirt.re/api/v1/packages/triage \
  -H "Authorization: Bearer $DEVIRT_API_KEY" \
  -H "Idempotency-Key: research-upload-0001" \
  -F "[email protected]" \
  -F "product_id=triage_plus" \
  -F "use_allowance=false" \
  -F "authorization=true"

The Python example uses httpx: install it with pip install httpx.

Request fields
FieldDefaultWhat to send
binaryRequiredYour authorized file. Maximum 500 MiB.
product_idcommunity_triagecommunity_triage or triage_plus. Neither product performs VM recovery.
use_allowancefalseApply one available Triage Plus allowance. General Analysis and recovery use separate product allowances.
authorizationRequiredtrue confirms your authorization to analyze the file.

Use community_triage for a free workspace inventory with no artifact download. General Analysis and protected recovery begin with an assessment. Choose an approved package offer for that exact binary; its outputs and price are fixed before payment.

One request. One idempotency key.

Reuse the same key after a connection failure. A different file or selection requires a new key.

Funding starts the job.

Keep the returned job_id. If checkout_required is true, POST to /job/{job_id}/checkout and open the returned URL. A confirmed payment event activates the job.

Follow its progress.

GET/job/{job_id}

Poll every 5–15 seconds with the same Bearer key, or use a completion webhook. Payment state distinguishes an unfunded submission from a funded queue entry.

QueuedProcessingComplete

A job can also fail. Read its error and refund state instead of waiting indefinitely.

Illustrative recovery progressJSON
{
  "job_id": "demo_001",
  "status": "processing",
  "progress": 60,
  "stage": "Comparing recovered behavior"
}

Save your evidence.

GET/job/{job_id}/result

Once complete, paid work returns a signed output_url. Recovery results also include coverage_ledger and proof_summary. Static triage returns static_summary; Community Triage has no artifact download. Save paid outputs in your own evidence store.

24h maxSigned link lifetime
72h / 30 daysDefault / Team retention; Triage Plus also has 30 days
410Response after deletion
Completed recovery response
Illustrative completed recoveryJSON
{
  "job_id": "demo_001",
  "status": "complete",
  "product_id": "protected_full",
  "output_url": "https://storage.example/result.zip?signature=…",
  "coverage_ledger": {
    "proven": 86,
    "runtime_dependent": 7,
    "unresolved": 2,
    "permanently_bounded": 5,
    "total": 100,
    "scope": "Synthetic example: 100 assessed protected functions",
    "notes": []
  },
  "proof_summary": {
    "proven_count": 86,
    "sat_count": 2,
    "timeout_count": 3,
    "permanent_bounds_count": 5
  }
}

While output is retained, request another signed link if needed. Renewing a link never extends retention. SAT and timeout counts are proof-summary outcomes, not extra coverage buckets.

Receive completion events.

Configure a public HTTPS endpoint in settings and securely save its signing secret.

  1. Keep the raw body. Sign the timestamp, a period, and the unmodified request bytes.
  2. Verify authenticity. Compare HMAC-SHA256 with v1 in X-Devirt-Signature using a constant-time comparison.
  3. Check freshness. Reject timestamps outside five minutes. Deduplicate X-Devirt-Event or event_id.
  4. Record, then acknowledge. Return 2xx after durable storage; process the event separately.

Delivery can repeat. Redirects are not followed; private-network destinations are rejected.

Assess before committing.

For General Analysis, protected recovery or custom work, POST binary, description, contact_email, and authorization=true to /novel/assess with an idempotency key. The email must match the verified account. Keep the returned assessment_id.

Free assessmentWritten offerYour decision

Completed assessments can include package_offers. Each offer identifies the exact binary, accepted outputs, price and expiry. POST to /packages/offers/{offer_id}/accept with {"accept_terms": true, "use_allowance": false, "priority": "standard"}. Use only an allowance for that product. Express is available only when the offer permits it. The returned job_id identifies the accepted order; use its checkout path if checkout_required is true. General Analysis allowances never purchase recovery.

For a separately quoted engagement, GET /novel/assess/{assessment_id}to read its written offer. POST to its /accept path with {"accept_terms": true}, then fund the deposit. Or POST to /decline with nothing charged. Offers and assessment reports expire after 72 hours. Acceptance and decline require the assessments:write scope.

The endpoint map.

Paths begin with /api/v1. The OpenAPI schema is available for tools and code generation; this page is the human reference.

POST/packages/triage
Submit Community Triage or Triage Plus

Required scope: jobs:write.

POST/packages/offers/{offer_id}/accept
Accept an assessed package and its fixed price

Required scope: jobs:write.

GET/job/{job_id}
Read status, progress, and ETA

Required scope: jobs:read.

GET/job/{job_id}/result
Get the result URL and coverage

Required scope: results:read.

POST/job/{job_id}/checkout
Fund a remaining job balance

Required scope: jobs:write.

POST/novel/assess
Request a free assessment

Required scope: assessments:write.

GET/novel/assess/{assessment_id}
Read an assessment and its offer

Required scope: assessments:read.

GET/database/list
Search your purchased library

Required scope: database:read.

GET/database/{entry_id}/download
Download an available entry format

Required scope: database:read.

Database routes also require permanent library access. Search with q, category, and page; download with format=ida or another available format.

Errors with a next step.

401Replace an invalid or revoked key.
403Check key scopes and your active plan.
402Add eligible credit or fund the balance.
409Inspect the job state or idempotency conflict.
413Use a file within the 500 MiB limit.
422Read the field errors and correct the request.
429Wait for the Retry-After interval.
5xxBack off and retry with the same idempotency key.
Create an account for API access