SafeSkill API Documentation
SafeSkill provides AI Agent Skill security detection capabilities through a RESTful API. Submit Skills via file upload, URL, or name for multi-dimensional scanning including static analysis, external URL threat intelligence, LLM semantic analysis, and dynamic sandbox detection.
Base URL:
https://api.safeskill.ioAuthentication
All API requests require an apikey parameter for authentication. Obtain your API key from the User Center after signing in.
| Parameter | Type | Required | Description |
|---|---|---|---|
apikey | string | Yes | Your API key for authentication |
Typical Workflow
1Submit Skill (file / URL / name)
2Receive SHA256
3Poll report endpoint
4Get detection results
POST
/api/v1/scan
Submit a Skill for security scanning via file upload, URL, or Skill name.
POSThttps://api.safeskill.io/api/v1/scan
Provide exactly one of file, url, or name. When using file, Content-Type must be multipart/form-data; for url or name, use application/json or form-urlencoded. Non-Skill files will be rejected with response_code: -2.
* Mutually exclusive — provide exactly one of file, url, or name per request.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
apikey | string | Yes | API key for authentication |
file | file | No | Skill package file (zip, tar.gz) or SKILL.md |
url | string | No | URL of a Skill in supported stores |
name | string | No | Skill name to search and scan (case-insensitive) |
Response
JSON
{
'response_code': 0,
'verbose_msg': 'OK',
'data': {
'sha256': 'a1b2c3d4e5f67890abcdef...1234567890',
'permalink': 'https://safeskill.io/report/{sha256}'
}
}| Parameter | Type | Required | Description |
|---|---|---|---|
data.sha256 | string | No | SHA256 hash used for querying report |
data.permalink | string | No | Direct link to online scan report |
Example
cURL — file
curl "https://api.safeskill.io/api/v1/scan" \
--form apikey='YOUR_API_KEY' \
--form file=@linkedin-skill.zipcURL — url
curl "https://api.safeskill.io/api/v1/scan" \
--form apikey='YOUR_API_KEY' \
--form url='https://clawhub.ai/ide-rea/linkedin'cURL — name
curl "https://api.safeskill.io/api/v1/scan" \
--form apikey='YOUR_API_KEY' \
--form name='linkedin'Python — file
import requests
resp = requests.post(
"https://api.safeskill.io/api/v1/scan",
data={"apikey": "YOUR_API_KEY"},
files={"file": open("linkedin-skill.zip", "rb")},
)
sha256 = resp.json()["data"]["sha256"]
print(f"Submitted. SHA256: {sha256}")Python — url / name
import requests
# Scan by URL(与 curl --form 字段一致,application/x-www-form-urlencoded)
resp = requests.post(
"https://api.safeskill.io/api/v1/scan",
data={"apikey": "YOUR_API_KEY", "url": "https://clawhub.ai/ide-rea/linkedin"},
)
# Scan by name
resp = requests.post(
"https://api.safeskill.io/api/v1/scan",
data={"apikey": "YOUR_API_KEY", "name": "linkedin"},
)
sha256 = resp.json()["data"]["sha256"]
print(f"Submitted. SHA256: {sha256}")GET
/v1/search
Search for Skills in the SafeSkill database by name or URL. Returns matching records with basic information.
GEThttps://api.safeskill.io/v1/search?apikey=...&query=...
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
apikey | string | Yes | API key for authentication |
query | string | Yes | Skill name or URL to search for |
page | integer | No | Page number, default 1 |
per_page | integer | No | Results per page, default 20 (max 100) |
Response
JSON
{
"response_code": 0,
"verbose_msg": "OK",
"data": {
"total": 3,
"page": 1,
"per_page": 20,
"results": [
{
"sha256": "a1b2c3d4...",
"skill_name": "linkedin",
"skill_type": "OpenClaw Skill",
"developer": "",
"version": "",
"description": "Use when you need to interact with LinkedIn...",
"threat_level": "malicious",
"source": "clawhub.ai",
"source_url": "https://clawhub.ai/ide-rea/linkedin",
"file_name": "linkedin-skill.zip",
"first_seen": "2026-02-20 10:30:00",
"last_detection_time": "2026-03-11 14:23:00",
"permalink": "https://safeskill.io/report/a1b2c3d4..."
}
]
}
}Response Fields — results[]
| Parameter | Type | Required | Description |
|---|---|---|---|
sha256 | string | No | File SHA256 hash |
skill_name | string | No | Skill name |
skill_type | string | No | Skill type (e.g. OpenClaw Skill) |
developer | string | No | Developer (empty if unknown) |
version | string | No | Version (empty if unknown) |
description | string | No | Skill description |
threat_level | string | No | Overall threat level |
source | string | No | Source platform (e.g. clawhub.ai, github.com) |
source_url | string | No | Original source URL |
file_name | string | No | Original file name |
first_seen | string | No | First seen timestamp |
last_detection_time | string | No | Most recent detection time |
permalink | string | No | Link to full scan report |
Example
cURL
curl "https://api.safeskill.io/v1/search?apikey=YOUR_API_KEY&query=linkedin"Python
import requests
resp = requests.get(
"https://api.safeskill.io/v1/search",
params={"apikey": "YOUR_API_KEY", "query": "linkedin"}
)
for item in resp.json()["data"]["results"]:
print(f"{item['skill_name']} — {item['threat_level']}")GET
/api/v1/report
Query a detailed scan report by the file SHA256 hash.
GEThttps://api.safeskill.io/api/v1/report?apikey=...&sha256=...
When a file is still being analyzed (response_code: 3), the response may contain incomplete data. Poll every 10 seconds, up to 5 minutes.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
apikey | string | Yes | API key for authentication |
sha256 | string | Yes | SHA256 returned from scan endpoint |
Response
JSON
{
"response_code": 0,
"verbose_msg": "OK",
"data": {
"summary": {
"sha256": "a1b2c3d4e5f67890...",
"sha1": "b2c3d4e5f67890ab...",
"md5": "c3d4e5f67890abcd...",
"file_type": "application/zip",
"file_name": "linkedin-skill.zip",
"threat_level": "malicious",
"trust_score": 12,
"is_whitelist": false,
"multi_engines": "7/25",
"first_seen": "2026-03-11 14:20:00",
"last_seen": "2026-03-11 14:23:00",
"tags": ["zip", "openclaw_skill"],
"threat_classify": "Trojan",
"threat_name": "ClawHavoc"
},
"skill_details": {
"type": "OpenClaw Skill",
"basic_info": {
"skill_name": "linkedin",
"developer": "",
"version": "",
"skill_type": "OpenClaw Skill",
"description": "Use when you need to interact..."
}
},
"multi_verdict": {
"llm": "malicious",
"static": "malicious",
"dynamic": "unknown",
"subfiles": "unknown",
"external_urls": "malicious"
},
"external_urls_details": [
{
"url": "https://github.com/...",
"source": "SKILL.md",
"trigger_type": "manual",
"platform": "windows",
"threat_level": "malicious",
"last_detection_time": "2026-02-27 17:03:25",
"ext_info": { ... }
}
],
"subfile_details": [
{
"name": "data_fetcher.py",
"sha256": "af6a70...",
"sha1": "9b1442...",
"md5": "eac269...",
"size": 9626,
"threat_level": "unknown",
"file_type": "PYTHON"
}
],
"llm_details": {
"summary": "High-risk behaviors detected...",
"risk_level": "malicious",
"risk_indicators": [
{
"indicator": "Downloads from unofficial repo",
"severity": "high",
"evidence": "https://github.com/..."
}
]
},
"permalink": "https://safeskill.io/report/..."
}
}Response Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
data.summary | object | No | File summary (hashes, threat level, trust score, detection details) |
data.summary.sha1 | string | No | File SHA1 hash |
data.summary.md5 | string | No | File MD5 hash |
data.summary.threat_level | string | No | Overall threat level for the Skill |
data.summary.trust_score | integer | No | Trust score (0–100); see Trust Score for score ranges |
data.summary.first_seen | string | No | File submission time |
data.summary.last_seen | string | No | Last detection time |
data.summary.tags | array | No | Tags list |
data.skill_details.type | string | No | Detected Skill type |
data.skill_details.basic_info | object | No | Skill metadata (name, developer, version, description) |
data.multi_verdict | object | No | Per-dimension verdict (llm, static, dynamic, subfiles, external_urls) |
data.external_urls_details | array | No | Detailed analysis of each external URL |
data.subfile_details | array | No | Subfile detection details |
data.llm_details | object | No | LLM semantic analysis results |
data.permalink | string | No | Online report link |
Example
cURL
curl "https://api.safeskill.io/api/v1/report?apikey=YOUR_API_KEY&sha256=a1b2c3d4..."Python — Scan + Poll
import requests, time
API_KEY = "YOUR_API_KEY"
# Step 1: Submit scan (file example)
resp = requests.post(
"https://api.safeskill.io/api/v1/scan",
data={"apikey": API_KEY},
files={"file": open("linkedin-skill.zip", "rb")}
)
sha256 = resp.json()["data"]["sha256"]
# Step 2: Poll for report
for i in range(30):
r = requests.get(
"https://api.safeskill.io/api/v1/report",
params={"apikey": API_KEY, "sha256": sha256}
)
data = r.json().get("data", {})
if data.get("multi_verdict"):
mv = data["multi_verdict"]
print(f"LLM: {mv['llm']}, Static: {mv['static']}, Dynamic: {mv['dynamic']}")
print(f"Trust Score: {data['summary']['trust_score']}")
break
time.sleep(10)Enumerations
Threat Level Enumeration
All threat_level and risk_level fields use the following values:
| Value | Meaning | Badge |
|---|---|---|
malicious | Malicious — confirmed as a threat | Malicious |
suspicious | Suspicious — potential risk identified | Suspicious |
unknown | Unknown/undetermined — analyzed, insufficient evidence | Undetermined |
clean | Clean/benign — confirmed safe | Clean |
Trust Score (trust_score)
trust_score is an integer from 0 to 100. It measures overall Skill trustworthiness; higher scores indicate greater safety. In general, scores of 80 or above can be considered relatively safe. Score ranges:
| Score Range | Meaning |
|---|---|
80 – 100 | Verified safe (80+) |
71 – 79 | Attention needed (71–79) |
41 – 70 | At risk (41–70) |
0 – 40 | Confirmed malicious (0–40) |
risk_indicators[].category
| Parameter | Type | Required | Description |
|---|---|---|---|
data_theft | string | No | Data Theft |
network_risk | string | No | Network Risk |
autonomy_abuse | string | No | Autonomy Abuse |
rce | string | No | Remote Code Execution |
supply_chain | string | No | Supply Chain Risk |
prompt_injection | string | No | Prompt Injection |
persistence | string | No | Persistence |
obfuscation | string | No | Obfuscation |
social_engineering | string | No | Social Engineering |
cross_platform | string | No | Cross-Platform Attack |
agent_hijack | string | No | Agent Hijack |
discovery_abuse | string | No | Discovery/Recon Abuse |
risk_indicators[].severity
| Parameter | Type | Required | Description |
|---|---|---|---|
high | string | No | High |
medium | string | No | Medium |
low | string | No | Low |
external_urls_details[].trigger_type
| Parameter | Type | Required | Description |
|---|---|---|---|
auto | string | No | Auto |
manual | string | No | Manual |
conditional | string | No | Conditional |
external_urls_details[].platform
| Parameter | Type | Required | Description |
|---|---|---|---|
windows | string | No | Windows |
macos | string | No | macOS |
linux | string | No | Linux |
all | string | No | All platforms |
Field Quick Reference
Report response (data) field paths, types, and descriptions:
| Field path | Type | Description |
|---|---|---|
| data (top-level) | | |
summary | object | File summary |
skill_details | object | AI Agent detection details |
multi_verdict | object | Per-dimension verdict (llm, static, dynamic, subfiles, external_urls) |
external_urls_details | array | Detailed analysis of each external URL |
subfile_details | array | Subfile detection details (name, hashes, size, threat_level, file_type) |
llm_details | object | LLM semantic analysis results |
permalink | string | Online report link |
| summary | | |
summary.sha256 | string | File SHA256 |
summary.sha1 | string | File SHA1 |
summary.md5 | string | File MD5 |
summary.file_type | string | File type |
summary.file_name | string | File name |
summary.threat_level | string | Overall threat level (static + AV + dynamic) |
summary.trust_score | integer | Trust score (0–100) |
summary.first_seen | string | Submission time |
summary.last_seen | string | Last detection time |
summary.tags | array | Tags list |
| skill_details | | |
skill_details.type | string | Detected Skill type |
skill_details.basic_info | object | Basic info |
| multi_verdict | | |
multi_verdict.llm | string | LLM dimension verdict |
multi_verdict.static | string | Static analysis verdict |
multi_verdict.dynamic | string | Dynamic sandbox verdict |
multi_verdict.subfiles | string | Subfiles dimension verdict |
multi_verdict.external_urls | string | External URLs verdict |
| external_urls_details | | |
external_urls_details[].url | string | External URL |
external_urls_details[].threat_level | string | URL threat conclusion |
external_urls_details[].last_detection_time | string | Detection time |
| subfile_details | | |
subfile_details[].name | string | Subfile name |
subfile_details[].sha256 | string | Subfile SHA256 |
subfile_details[].sha1 | string | Subfile SHA1 |
subfile_details[].md5 | string | Subfile MD5 |
subfile_details[].size | integer | Subfile size (bytes) |
subfile_details[].threat_level | string | Subfile threat level |
subfile_details[].file_type | string | Subfile type |
| llm_details | | |
llm_details.analyzed_at | string | Analysis time |
llm_details.llm_model | string | LLM model |
llm_details.summary | string | Summary |
llm_details.risk_level | string | Risk level |
llm_details.intent_reconstruction | object | Intent reconstruction |
llm_details.intent_reconstruction.intent_confidence | integer | Intent consistency (0–100); higher values mean stronger alignment |
llm_details.extracted_iocs | object | Indicators extracted from the file; not necessarily malicious—use with caution. |
llm_details.risk_indicators[] | array | Risk indicators |
llm_details.risk_indicators[].indicator | string | Risk description |
llm_details.risk_indicators[].category | string | Risk category |
llm_details.risk_indicators[].severity | string | Severity: high / medium / low |
llm_details.risk_indicators[].evidence | string | Evidence |
llm_details.platform_analysis | object | Platform analysis (windows/macos/linux) |
Response Codes
The API uses standardized response_code. Check response_code and verbose_msg in every response.
| Response Code | Verbose Msg | Description |
|---|---|---|
| 0 | OK | Success |
| 2 | No Data | No data |
| 3 | In Progress | Task in progress |
| -1 | Invalid Account Status | Invalid account status |
| -1 | Invalid Access IP | Invalid access IP: {actual IP} |
| -1 | Invalid API Key | Invalid API key; please enter a correct API key |
| -1 | Invalid Key Status | API key status invalid |
| -1 | Invalid Parameter: {parameter} | Invalid API parameter: {parameter name} |
| -1 | No Access to API Method | No permission to access the API method |
| -1 | Expired API Key | API key expired |
| -1 | Empty File | Uploaded empty file |
| -1 | File Size Too Large | Uploaded file too large |
| -1 | File Name Too Long | Uploaded file name too long |
| -2 | Invalid API Method | Invalid API method |
| -3 | Required:{} | Required request parameter missing: specific missing item(s) |
| -4 | Frequent Limitation | Access rate limit triggered |
| -4 | BeyondLimitation | Access limit exceeded |
| -5 | System Error | System error |
Complete Response Examples
Malicious Skill
JSON
{
"response_code": 0,
"verbose_msg": "OK",
"data": {
"summary": {
"sha256": "a1b2c3d4e5f67890abcdef...",
"sha1": "b2c3d4e5f67890ab...",
"md5": "c3d4e5f67890abcd...",
"file_type": "application/zip",
"file_name": "linkedin-skill.zip",
"threat_level": "malicious",
"trust_score": 12,
"first_seen": "2026-03-11 14:20:00",
"last_seen": "2026-03-11 14:23:00",
"tags": ["zip", "openclaw_skill"],
},
"skill_details": {
"type": "OpenClaw Skill",
"basic_info": { "skill_name": "linkedin", ... }
},
"multi_verdict": {
"llm": "malicious",
"static": "malicious",
"dynamic": "unknown",
"subfiles": "unknown",
"external_urls": "malicious"
},
"external_urls_details": [ ... ],
"subfile_details": [
{ "name": "data_fetcher.py", "sha256": "af6a70...", "size": 9626, "threat_level": "unknown", "file_type": "PYTHON" }
],
"llm_details": {
"risk_level": "malicious",
"risk_indicators": [ ... ]
}
}
}Clean Skill
JSON
{
"response_code": 0,
"verbose_msg": "OK",
"data": {
"summary": {
"sha256": "f0e1d2c3b4a59678...",
"sha1": "e1d2c3b4a5967801...",
"md5": "d2c3b4a596780123...",
"file_type": "application/zip",
"file_name": "weather-skill.zip",
"threat_level": "clean",
"trust_score": 92,
"first_seen": "2026-03-10 09:15:00",
"last_seen": "2026-03-10 09:18:00",
"tags": ["zip", "openclaw_skill"],
},
"skill_details": {
"type": "OpenClaw Skill",
"basic_info": { ... }
},
"multi_verdict": {
"llm": "clean",
"static": "clean",
"dynamic": "clean",
"subfiles": "clean",
"external_urls": "clean"
},
"external_urls_details": [],
"subfile_details": [],
"llm_details": {
"risk_level": "clean",
"risk_indicators": []
}
}
}