API Guide
Integrate mlab into your security workflows with the REST API to automate lookups, submit files and retrieve results programmatically.
Integrate mlab into your security workflows with the REST API. Automate lookups, submit files and retrieve results programmatically.
Changed on 1 October 2026: API keys now have permissions
Every API key now carries a set of permissions that decides which endpoints it can call. Existing keys were migrated to full access, so nothing that worked before stops working. What changed:
- API keys moved from Account settings to Organization settings → API keys. They belong to the organization, not to the person who created them.
- A new key needs at least one permission. A call outside its permissions returns
403naming the missing permission (it used to be401for endpoints a key could not use). - Keys can now reach cases, finding tags, scheduled scans, RedKit audits, batch triage and the AI script analysis, which used to require a signed-in member.
- What a key does is attributed to the key itself: usage per key, its name in the team activity feed, and comments signed
API key · <name>.
Authentication
All API requests require an API key passed in the Authorization header, as Bearer <key> or token <key>.
# Include your API key in every request
GET https://mlab.sh/api/v1/scan/ip?ip=8.8.8.8
Authorization: Bearer YOUR_API_KEYAPI keys belong to your organization: they are created, changed and deleted by its owner and admins in Organization settings → API keys, and every member can see them there (without the key itself). A key keeps working if the person who created it leaves. Its scans count against the organization's daily quotas.
| Plan | API keys per organization |
|---|---|
| Free | 1 |
| Pro | 5 |
| Team | 100 |
| Enterprise | 100 |
A key is shown once, when it is created. Keep it secret and never put it in client-side code. If it leaks, delete it in the organization settings: it stops working at once.
Permissions
Each key has the permissions chosen when it was created, and an owner or admin can change them at any time in the organization settings (the change applies from the key's next call). Give a key only what its integration needs.
| Permission | Lets the key | Endpoints |
|---|---|---|
scan.lookup | Look up indicators and extract IOCs from text | /api/v1/scan/ip, crypto, hash, url, email, phone, mac, ioc |
scan.domain | Launch domain scans and read their results | /api/v1/scan/domain, domain/status, domain/results, domain/loadnetworkrequest, domain/resolve |
scan.file | Submit files and shell scripts, run the AI script analysis | /upload/file, /api/v1/scan/file/results, scan/file/bash, scan/file/bash/ai |
scan.batch | Triage a pasted list of indicators | /api/v1/scan/batch |
redkit | Launch RedKit audits, follow them, read the quota | /api/v1/scan/redkit, redkit/status, redkit/quota |
watchdog.read | List scheduled scans | /api/v1/scan/watchdog/list |
watchdog.write | Create, pause and delete scheduled scans | /api/v1/scan/watchdog/create, update, delete |
cases.read | List and read cases | /api/v1/cases, /api/v1/cases/detail |
cases.write | Create and update cases, add indicators and comments | /api/v1/cases/create, update, delete, indicator/add, indicator/delete, comment/add, comment/delete |
tags.read | Read the tags on RedKit findings | /api/v1/scan/finding-tags |
tags.write | Tag and untag RedKit findings | /api/v1/scan/finding-tags/add, remove |
Full access grants every permission above, and any added later. Writing implies reading: cases.write also grants cases.read, and the same goes for tags and scheduled scans. Checking your quota (/api/v1/limit/*) needs no permission.
Whatever its permissions, a key never reaches the organization or account settings: members, roles, invitations, webhooks, other API keys, MCP tokens, passwords. It cannot create or change keys either. Bookmarks and the RedKit recap email are personal and stay with members.
A call outside the key's permissions returns 403:
{
"error": "This API key does not have the 'cases.write' permission (Write cases). An owner or admin can add it in the organization settings."
}Who a key's work is credited to
- Scans are counted per key: the organization's usage history has a By API key breakdown, and the team activity feed names the key instead of a person.
- Cases, comments and finding tags written with a key are credited to the key (
API key · <name>). A key deletes only what it created itself; it never moderates a member's work. - Scheduled scans and RedKit audits launched with a key belong to the organization's first member, who receives their notification emails, since a key has no mailbox.
Rate limits
API requests count against your plan's daily scan quotas, shared across your organization and reset daily. When you exceed a daily limit, the API returns 400 Bad Request with an error message such as "IP lookup limit reached. Please try again later.". Check what is left with GET /api/v1/limit/{domain|ip|file|crypto}.
| Plan | Domain scans | IP lookups | File scans | Crypto lookups |
|---|---|---|---|---|
| Pro | 25 / day | 50 / day | 20 / day | 30 / day |
| Team | 100 / day | 200 / day | 80 / day | 100 / day |
| Enterprise | Custom | Custom | Custom | Custom |
Core endpoints
Indicator lookups
Each indicator type has its own lookup endpoint. There is no single combined search endpoint on the API: the search bar on the website is a router that redirects to these modules, so integrations call the specific endpoint they need.
| Indicator | Endpoint | Counts against a quota |
|---|---|---|
| IP address | GET /api/v1/scan/ip?ip={value} | Yes (IP scans) |
| Crypto address | GET /api/v1/scan/crypto?address={value}&chain={chain} | Yes (crypto lookups) |
| File hash (MD5, SHA-1, SHA-256) | GET /api/v1/scan/hash?hash={value} | No |
| URL | GET /api/v1/scan/url?url={value}&resolve=true | No |
| MAC address | GET /api/v1/scan/mac?mac={value} | No |
| Email address | GET /api/v1/scan/email?email={value} | No |
| Phone number | GET /api/v1/scan/phone?number={value} | No |
# Example: look up an IP address
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/ip?ip=185.220.101.47"
# Example: look up a crypto address.
# Pass `chain` for an EVM address: all 13 EVM chains share one address format,
# so it cannot be derived, and omitting it defaults to Ethereum.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/crypto?address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&chain=ETH"
# Example: look up a file hash
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/hash?hash=44d88612fea8a8f36de82e1278abb02f"
# Example: analyse a URL (add resolve=true to follow redirects)
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/url?url=https%3A%2F%2Fbit.ly%2F3xYz"
# Example: look up a MAC address
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/mac?mac=00:0C:29:1A:2B:3C"
# Example: look up an email address
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/[email protected]"
# Example: look up a phone number (the '+' is URL-encoded as %2B)
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/phone?number=%2B33612345678"Hash, URL, MAC, email and phone lookups do not count against a scan quota. IP and crypto lookups draw on live intelligence and count against your plan's daily quotas. Hash and crypto also accept a batch as a POST to the same path ({"hashes": [...]} or {"addresses": [...], "chain": "..."}). Domain and file analysis use the scan endpoints below. CVE lookups are available on the website and through the MCP server.
Each lookup accepts a single indicator and returns the same data as the matching module on the website. See the per-module pages under Scans & Lookups for the exact response fields.
Scan a domain
Launch a full domain scan, then poll for its result.
POST /api/v1/scan/domain
Content-Type: application/json
# Example: start a domain scan
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":"example.com"}' \
"https://mlab.sh/api/v1/scan/domain"
# Retrieve the results once the scan has completed
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/domain/results?domain=example.com"Extract IOCs from text
Pull every indicator (IPs, domains, URLs, emails, hashes, crypto addresses, CVEs) out of up to 1 MB of raw text. Defanged indicators (hxxp://, [.], [at]) come back as the real ones. Add risk=true to score it as an SMS threat.
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Your parcel is waiting: http://bit.ly/3xYz"}' \
"https://mlab.sh/api/v1/scan/ioc?risk=true"Triage a list of indicators
Paste up to 1 MB of text (one indicator per line, or any free text) and get what mlab already knows about each of up to 200 distinct indicators, from cache. Needs scan.batch; spends no scan quota.
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"indicators":"8.8.8.8\nevil.example\n44d88612fea8a8f36de82e1278abb02f"}' \
"https://mlab.sh/api/v1/scan/batch"Submit a file for analysis
Upload a file (max 10 MB) for scanning and analysis.
POST /upload/file
Content-Type: multipart/form-data
# Example: upload a suspicious binary
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "[email protected]" \
"https://mlab.sh/upload/file"The upload endpoint lives at the site root, not under /api/v1. It returns the file's sha256, which you use to fetch results.
Explain a shell script with AI
After submitting a script, ask for a prose explanation of what it does. Needs scan.file. Cached per script; a new analysis counts against the daily AI analysis quota.
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/file/bash/ai?sha256=SCRIPT_SHA256"Get scan results
Results are keyed by what you scanned, not by a scan ID.
# Domain scan: progress, then full results
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/domain/status?domain=example.com"
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/domain/results?domain=example.com"
# File scan: results by SHA-256
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/file/results?sha256=YOUR_FILE_SHA256"RedKit audits
Needs redkit. See RedKit for the plugin list.
# Launch an audit
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"domain":"example.com","plugins":["headers","ssl","dns"]}' \
"https://mlab.sh/api/v1/scan/redkit"
# Follow it with the returned scan_uuid, and check the remaining quota
curl -H "Authorization: Bearer YOUR_API_KEY" "https://mlab.sh/api/v1/scan/redkit/status?uuid=SCAN_UUID"
curl -H "Authorization: Bearer YOUR_API_KEY" "https://mlab.sh/api/v1/scan/redkit/quota"Scheduled scans
watchdog.read lists them, watchdog.write creates, pauses and deletes them. Times are UTC; weekly schedules take day_of_week (0 = Monday), monthly ones day_of_month (1 to 28). A RedKit schedule needs a domain verified in your infrastructure.
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"scan_type":"domain","domain":"example.com","frequency":"weekly","day_of_week":0,"hour":6}' \
"https://mlab.sh/api/v1/scan/watchdog/create"
curl -H "Authorization: Bearer YOUR_API_KEY" "https://mlab.sh/api/v1/scan/watchdog/list"Cases
Cases are part of the Team and Enterprise plans. cases.read lists and reads them, cases.write creates and updates them.
# Open a case, add what the SOAR found, comment on it
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"title":"Phishing wave","summary":"Reported by 12 users"}' \
"https://mlab.sh/api/v1/cases/create"
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"uuid":"CASE_UUID","indicators":"evil.example\n185.220.101.47"}' \
"https://mlab.sh/api/v1/cases/indicator/add"
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"uuid":"CASE_UUID","body":"Blocked at the gateway"}' \
"https://mlab.sh/api/v1/cases/comment/add"
# Read it back
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
-d '{"uuid":"CASE_UUID"}' "https://mlab.sh/api/v1/cases/detail"Finding tags
Mark RedKit findings as false-positive, accepted-risk or fixed. tags.read reads them, tags.write sets and removes them.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/finding-tags/add?scan_uuid=SCAN_UUID&finding_id=FINDING_ID&tag=false-positive"See the API Reference for every endpoint, parameter and response schema, with the permission each one needs.
Response format
All API responses are JSON. A successful request returns 200 with the endpoint's result object directly (no wrapper); its fields are documented per endpoint in the API Reference. Errors return an HTTP status code and an error field.
// Error response
{
"error": "IP lookup limit reached. Please try again later."
}HTTP status codes
| Code | Meaning |
|---|---|
200 | Success - result returned |
400 | Bad request - invalid parameter, missing required field, or daily quota reached |
401 | Unauthorized - missing or invalid API key |
403 | Forbidden - the API key lacks the permission this endpoint needs (the message names it), the endpoint is not open to API keys, or the organization is locked |
404 | Not found - unknown endpoint or no result for this input |
502 | Bad gateway - an upstream intelligence source could not be reached, retry later |
500 | Server error - please retry or contact support |
Verify Your Infrastructure
Declare the domains, IP networks, code repositories and S3 buckets your organization operates, and prove you own them to unlock RedKit audits and scheduled scans.
Unified Search
Paste any indicator into the mlab search bar and get routed to the right intelligence module: IP, domain, hash, URL, email, phone, MAC, crypto address or CVE.