Authentication
Authenticate your API requests with an API key.
All API requests are made to https://mlab.sh/api/v1/ and must include your API key in the Authorization header.
Authorization: token mlab_your_api_key_here
Generate an API Key
- Log in to mlab.sh
- Go to Account > Settings > API Keys
- Click Create API Key, give it a descriptive note
- Copy the key — it is only shown once
Keep your API key secret. Do not commit it to version control or share it publicly. If compromised, delete it immediately and create a new one.
Quick Start
Make your first API call in seconds.
Test your API key by calling the root endpoint:
curl -H "Authorization: token YOUR_API_KEY" \
https://mlab.sh/api/v1/
If your key is valid, you will get a greeting response:
{
"message": "Hello, anonymous user of YourOrganization!"
}
Base URL
| Environment | Base URL |
| Production | https://mlab.sh/api/v1 |
All endpoints described in this documentation are relative to this base URL.
Domain Scan
Launch, monitor, and retrieve results from an automated domain security scan.
Launch a scan
| Method | POST |
| Endpoint | /scan/domain |
| Auth | API Key required |
Request Body
| Field | Type | Required | Description |
domain | string | Yes | The domain to scan (e.g. example.com) |
curl -X POST \
-H "Authorization: token YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}' \
https://mlab.sh/api/v1/scan/domain
Response
{
"status": "success",
"message": "Domain scan has been started."
}
{
"status": "error",
"message": "Provided domain is invalid."
}
{
"status": "error",
"message": "Scan limit reached. Please try again later."
}
Check status
| Method | GET |
| Endpoint | /scan/domain/status?domain=example.com |
| Auth | API Key required |
Query Parameters
| Param | Type | Required | Description |
domain | string | Yes | The domain to check |
curl -H "Authorization: token YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/domain/status?domain=example.com"
Response
The status field indicates the scan progress:
| Status | Description |
pending | Scan is queued and has not started yet |
scanning | Scan is actively running |
success | Scan completed successfully |
{
"status": "pending",
"message": "Domain scan is still pending."
}
{
"status": "scanning",
"message": "Domain scan is still in progress."
}
{
"status": "success",
"message": "Domain scan is in done."
}
Tip: poll this endpoint every few seconds after launching a scan to track its progress. Once the status is success, retrieve the full results with /scan/domain/results.
Get results
| Method | GET |
| Endpoint | /scan/domain/results?domain=example.com |
| Auth | API Key required |
Query Parameters
| Param | Type | Required | Description |
domain | string | Yes | The domain to get results for |
curl -H "Authorization: token YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/domain/results?domain=example.com"
Response
{
"status": "completed",
"domain": "example.com",
"scan_date": "2026-03-23 10:30:00 UTC",
"results": {
"subdomains": ["www.example.com", "mail.example.com"],
"subdomains_suspicious": [
{ "keyword": "admin", "subdomain": "admin.example.com" }
],
"dns": {
"resolve": [
{
"domain": "example.com",
"a": ["93.184.216.34"],
"aaaa": ["2606:2800:220:1:..."],
"cname": null
}
],
"txt": {
"raw": ["v=spf1 include:..."],
"spf": "v=spf1 include:_spf.google.com ~all",
"dmarc": "v=DMARC1; p=reject; ...",
"dkim": []
}
},
"ssl": [
{
"domain": "example.com",
"issuer_name": "C=US, O=DigiCert Inc, ...",
"common_name": "www.example.org",
"not_before": "2024-01-30",
"not_after": "2025-03-01"
}
],
"files": {
"security_txt": "Contact: [email protected]\n...",
"robots_txt": "User-agent: *\nDisallow: /admin"
}
}
}
Response Fields
| Field | Type | Description |
status | string | completed or in_progress |
results.subdomains | array | All discovered subdomains |
results.subdomains_suspicious | array | Subdomains flagged as suspicious (keyword + subdomain) |
results.dns.resolve | array | DNS A, AAAA and CNAME records per subdomain |
results.dns.txt | object | TXT records: raw, SPF, DMARC, DKIM |
results.ssl | array | SSL certificates found (issuer, dates, names) |
results.files.security_txt | string | Contents of security.txt (empty if not found) |
results.files.robots_txt | string | Contents of robots.txt (empty if not found) |
If status is in_progress, some fields may be empty. Poll until completed for full results.
IP Lookup
Retrieve threat intelligence and geolocation data for an IP address.
| Method | GET |
| Endpoint | /scan/ip?ip=8.8.8.8 |
| Auth | API Key or Session |
Query Parameters
| Param | Type | Required | Description |
ip | string | Yes | IPv4 or IPv6 address to look up |
curl -H "Authorization: token YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/ip?ip=8.8.8.8"
Response
{
"ip": "8.8.8.8",
"reserved": false,
"isp": "Google LLC",
"org": "Google Public DNS",
"as": "AS15169 Google LLC",
"city": "Mountain View",
"region": "California",
"country": "United States",
"country_code": "US",
"continent": "North America",
"continent_code": "NA",
"timezone": "America/Los_Angeles",
"zip": "94035",
"lat": 37.386,
"lon": -122.0838,
"currency": "USD",
"status": "success"
}
Response Fields
| Field | Type | Description |
ip | string | The queried IP address |
reserved | boolean | true if the IP is a private/reserved range |
isp | string | Internet Service Provider |
org | string | Organization owning the IP |
as | string | Autonomous System number and name |
city | string | City geolocation |
region | string | Region / state |
country | string | Country name |
country_code | string | ISO 3166 country code |
continent | string | Continent name |
timezone | string | IANA timezone identifier |
lat / lon | number | Latitude and longitude |
currency | string | Local currency code |
Reserved IP Response
If the IP belongs to a private or reserved range, the response format differs:
{
"ip": "192.168.1.1",
"reserved": true,
"type": "IPv4",
"range": "Private network (Class C)",
"rfc": "RFC 1918"
}
Check IP Lookup Quota
curl -H "Authorization: token YOUR_API_KEY" \
https://mlab.sh/api/v1/limit/ip
{
"scan_type": "ip",
"remaining": 48,
"total": 50
}
Results are cached for 30 days. Subsequent lookups for the same IP within that period return cached data without consuming quota.
File Scan
Upload and analyze files for threats and metadata.
Upload a file
| Method | POST |
| Endpoint | /upload/file |
| Auth | Session cookie or API Key |
| Content-Type | multipart/form-data |
| Field | Type | Required | Description |
file | binary | Yes | The file to analyze (max 10 MB) |
Supported file types: PNG, JPG, PDF, DOCX, XLSX, PPTX, EXE, DLL, SYS
curl -X POST \
-H "Authorization: token YOUR_API_KEY" \
-F "[email protected]" \
https://mlab.sh/upload/file
Upload Response
{
"success": true,
"filename": "uuid.ext",
"sha256": "a1b2c3d4e5f6...",
"job_launched": true
}
Upload Errors
{
"success": false,
"error": { "code": 429, "message": "rate_limited" }
}
| Status | Message | Description |
400 | invalid_content_type | Not multipart/form-data |
400 | no_file | No file in form |
400 | Unsupported or forbidden... | MIME type not supported |
413 | file_too_large | File exceeds 10 MB |
429 | rate_limited | Quota exceeded |
500 | storage_error | Internal storage error |
Get scan results
After uploading, use the sha256 from the upload response to retrieve the analysis results.
| Method | GET |
| Endpoint | /scan/file/results?sha256=... |
| Auth | API Key or Session |
curl -H "Authorization: token YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/file/results?sha256=a1b2c3d4e5f6..."
Results Response
{
"status": "completed",
"file": {
"sha256": "a1b2c3d4e5f6...",
"md5": "d4e5f6a1b2c3...",
"ssdeep": "384:H8a9fJ2k...",
"filename": "malware.exe",
"size": 1234567,
"mime_type": "application/x-dosexec",
"created_at": "2026-03-30T12:00:00Z"
},
"jobs_total": 3,
"jobs_completed": 3,
"analysis": [
{
"job_name": "file",
"end_date": "2026-03-30T12:01:00Z",
"data": "decoded analysis content"
},
{
"job_name": "strings",
"end_date": "2026-03-30T12:01:05Z",
"data": "extracted strings content"
}
]
}
Response Fields
| Field | Type | Description |
status | string | pending, in_progress, or completed |
file | object | File metadata (hashes, filename, size, mime type) |
jobs_total | number | Total analysis jobs launched |
jobs_completed | number | Jobs that have finished |
analysis[] | array | Results per job (decoded from base64) |
analysis[].job_name | string | Name of the analysis tool (e.g. file, strings) |
analysis[].data | string/object | Decoded analysis output (JSON object or plain text) |
If status is in_progress, poll this endpoint every few seconds until completed. The analysis array will grow as jobs finish.
Check file scan quota
curl -H "Authorization: token YOUR_API_KEY" \
https://mlab.sh/api/v1/limit/file
{
"scan_type": "file",
"remaining": 19,
"total": 20
}
SSL Info
Retrieve SSL certificate information for a domain.
| Method | GET |
| Endpoint | /domain/ssl?domain=example.com |
| Auth | API Key required |
Query Parameters
| Param | Type | Required | Description |
domain | string | Yes | The domain to check SSL for |
curl -H "Authorization: token YOUR_API_KEY" \
"https://mlab.sh/api/v1/domain/ssl?domain=example.com"
Returns SSL certificate details including issuer, validity dates, and certificate chain information.
Rate Limits
Understand and monitor your API usage limits.
API rate limits depend on your organization's subscription plan. You can check your remaining quota at any time.
| Method | GET |
| Endpoint | /limit/domain | /limit/ip | /limit/file | /limit/crypto |
| Auth | API Key or Session |
curl -H "Authorization: token YOUR_API_KEY" \
https://mlab.sh/api/v1/limit/domain
Response
{
"scan_type": "domain",
"remaining": 98,
"total": 100
}
Response Fields
| Field | Type | Description |
scan_type | string | The scan type checked (domain, ip, file, or crypto) |
remaining | number | Scans remaining for the current day |
total | number | Total daily limit for your plan |
Scan Limits by Plan
| Plan | Domain scans/day | File scans/day | IP lookups/day | Crypto lookups/day |
anonymous | 2 | 1 | 5 | 3 |
free | 5 | 3 | 10 | 10 |
pro | 25 | 20 | 50 | 30 |
team | 100 | 80 | 200 | 100 |
enterprise | Unlimited | Unlimited | Unlimited | Unlimited |
Limits are per organization, shared across all members. Resets daily.
When a scan limit is reached, the API returns a
400 error. Upgrade your plan on the
pricing page for higher limits.
Errors
HTTP status codes and error handling.
The API uses standard HTTP status codes to indicate success or failure.
| Code | Meaning | Description |
200 | OK | Request succeeded |
400 | Bad Request | Missing or invalid parameters |
401 | Unauthorized | Invalid or missing API key |
404 | Not Found | Endpoint does not exist |
Error Response Format
Error responses are returned as JSON with a descriptive message:
{
"status": "error",
"message": "Description of what went wrong."
}
Common Errors
| Error | Cause | Fix |
Provided domain is invalid. |
Domain format is wrong |
Use a valid domain like example.com |
Scan limit reached. |
Rate limit exceeded |
Wait or upgrade your plan |
Please provide all required information. |
Missing required fields in request body |
Check the endpoint documentation for required fields |
Crypto Address Lookup
Retrieve threat intelligence for a blockchain address.
| Method | GET |
| Endpoint | /scan/crypto?address=0x...&chain=eth |
| Auth | API Key or Session |
Query Parameters
| Param | Type | Required | Description |
address | string | Yes | The blockchain address to look up |
chain | string | No | Chain ID (auto-detected for EVM/BTC/TRX addresses). See supported chains below. |
curl -H "Authorization: token YOUR_API_KEY" \
"https://mlab.sh/api/v1/scan/crypto?address=0x722122df12d4e14e13ac3b6895a86e84145b6967&chain=eth"
Response
{
"address": "0x722122df12d4e14e13ac3b6895a86e84145b6967",
"chain": "ETH",
"type": "contract",
"categories": ["contract", "mixer"],
"labels": [
{ "name": "Tornado Cash: Proxy", "source": "community" }
],
"sanctions": { "is_sanctioned": false },
"risk_score": 80,
"risk_level": "critical",
"checked_at": "2026-04-16T09:22:49.482Z"
}
Response Fields
| Field | Type | Description |
address | string | The queried address |
chain | string | Chain ID |
type | string | eoa, contract, or unknown |
categories | array | Address categories (e.g. exchange, defi, mixer, scam, sanctioned) |
labels | array | Labels with name and source |
sanctions | object | Sanctions status (is_sanctioned, optional authority and list_date) |
risk_score | number | 0–100 risk score |
risk_level | string | low, medium, high, or critical |
checked_at | string | ISO 8601 timestamp |
Supported Chains
| Chain | ID | Auto-detected |
| Ethereum | ETH | Yes (0x...) |
| BNB Chain | BSC | Use chain=BSC |
| Polygon | POLYGON | Use chain=POLYGON |
| Arbitrum | ARBITRUM | Use chain=ARBITRUM |
| Optimism | OPTIMISM | Use chain=OPTIMISM |
| Base | BASE | Use chain=BASE |
| Avalanche | AVAX | Use chain=AVAX |
| Bitcoin | BTC | Yes (1.../3.../bc1...) |
| Tron | TRX | Yes (T...) |
| Solana | SOL | Use chain=SOL |
| TON | TON | Use chain=TON |
| Dogecoin | DOGE | Use chain=DOGE |
EVM addresses (0x...) default to Ethereum. To query the same address on BSC, Polygon, etc., pass the chain parameter explicitly.
Check Crypto Lookup Quota
curl -H "Authorization: token YOUR_API_KEY" \
https://mlab.sh/api/v1/limit/crypto
{
"scan_type": "crypto",
"remaining": 28,
"total": 30
}