API Reference
3 min read
Overview
The ThreatHarvest API provides programmatic access to findings, requirements, and attributes for your organization.
Base URL
https://api.threatharvest.com/v1
Versioning
The API is versioned via the URL path (/v1/). When breaking changes are introduced, a new version will be released (for example /v2/). Advance notice is provided before any API version is deprecated.
Authentication
All API requests (except /v1/health) require a Bearer token in the Authorization header. Manage keys in your ThreatHarvest account — see API keys.
Format:
Authorization: Bearer YOUR_API_KEY
Example:
curl -H "Authorization: Bearer hvst_live_abc123xyz789" https://api.threatharvest.com/v1/findings
Rate limiting
The API enforces rate limits for fair usage and stability. Limits are subject to change.
- Limit: 100 requests per hour
- Method: Sliding window
- Scope: All endpoints share the same rate limit
Response headers
Every API response includes rate-limit information:
X-RateLimit-Limit— maximum requests allowed per hourX-RateLimit-Remaining— requests remaining in the current windowX-RateLimit-Reset— ISO 8601 timestamp when the rate limit resets
When you exceed the limit, the API returns 429 Too Many Requests with a Retry-After header (seconds to wait).
Burst limit
In addition, more than 10 requests in 10 seconds from one IP address is blocked with 403 Forbidden for 10 seconds. If this happens, back off and retry after about 10 seconds.
Endpoints
Health
GET /v1/health
Check API status. No authentication required.
Response
{
"status": "ok",
"version": "v1"
}
List findings
GET /v1/findings
List findings for your organization.
Query parameters
| Parameter | Description |
|---|---|
limit | Optional. Max results. Default: 50, Max: 100 |
offset | Optional. Pagination offset. Default: 0 |
status | Optional. Filter by status. Values: pending, review, resolved |
requirement_id | Optional. Filter by requirement ID |
relevant | Optional. Filter by relevance. Values: true, false |
Response example
{
"data": [
{
"id": "finding-uuid",
"requirement": { "id": "req-uuid", "name": "Data Breach Monitoring" },
"source": { "description": "Example Breaches" },
"attribute": "user@example.com",
"summary": "Email found in breach",
"added": "2024-01-15",
"status": "pending",
"relevant": true,
"thp_score": 7.5
}
],
"meta": {
"total": 150,
"limit": 50,
"offset": 0,
"returned": 50
}
}
Get finding
GET /v1/findings/{finding_id}
Return detailed information for a specific finding.
Path parameters
| Parameter | Description |
|---|---|
finding_id | Unique identifier of the finding |
Field notes
thp_score— only present (non-null) for relevant findingsdiscovery.statusandlast_change— null if discovery is not applicable
Response example
{
"data": {
"id": "finding-uuid",
"requirement": { "id": "req-uuid", "name": "Data Breach Monitoring", "short_name": "Breach" },
"source": { "description": "Example Breaches", "notice": "Sample Data Source" },
"attribute": "user@example.com",
"added": "2024-01-15 10:30:45",
"content": [
{"name": "Breach Name", "value": "Example Breach"},
{"name": "Breach Date", "value": "2023-12-01"},
{"name": "Data Classes", "value": "Emails, Passwords"}
],
"discovery": {
"enabled": true,
"status": "Current (Active)",
"last_change": "2024-01-15 10:30:45"
},
"status": "pending",
"thp_score": 7.5
}
}
List requirements
GET /v1/requirements
List available requirements.
Response example
{
"data": [
{
"id": "req-uuid",
"name": "Data Breach Monitoring"
}
],
"meta": { "total": 10 }
}
List attributes
GET /v1/attributes
List active attributes for your organization.
Response example
{
"data": [
{
"id": "attr-uuid",
"requirement_id": "req-uuid",
"attribute_type": "Email Address",
"attribute_value": "user@example.com",
"created": "2024-01-01 10:30:45"
}
],
"meta": { "total": 25 }
}
Error responses
The API uses standard HTTP status codes.
Status codes
| Code | Description |
|---|---|
| 200 | OK — request successful |
| 400 | Bad Request — invalid input parameters |
| 401 | Unauthorized — missing or invalid API key |
| 404 | Not Found — resource not found or access denied |
| 429 | Too Many Requests — rate limit exceeded |
| 500 | Internal Server Error |
Format
{
"error": "Error message description",
"message": "Optional detailed message"
}
Pagination
List endpoints (for example /v1/findings) support limit and offset.
Example request:
curl -H "Authorization: Bearer KEY" "https://api.threatharvest.com/v1/findings?limit=100&offset=100"
Response metadata:
{
"meta": {
"total": 250,
"limit": 100,
"offset": 100,
"returned": 100
}
}
Examples
Python
import requests
API_KEY = "your-api-key-here"
BASE_URL = "https://api.threatharvest.com/v1"
headers = { "Authorization": f"Bearer {API_KEY}" }
# Get all pending findings
response = requests.get(
f"{BASE_URL}/findings",
headers=headers,
params={"status": "pending", "limit": 100}
)
if response.status_code == 200:
data = response.json()
print(f"Found {len(data['data'])} pending findings")
else:
print(f"Error: {response.json()['error']}")
cURL
#!/bin/bash
API_KEY="your-api-key-here"
BASE_URL="https://api.threatharvest.com/v1"
curl -H "Authorization: Bearer $API_KEY" \
"$BASE_URL/findings?status=pending&limit=100"
Guidance
- Keep API keys out of client-side code and public repositories.
- Use HTTPS for all requests.
- Watch
X-RateLimit-Remainingand back off on429responses. - Paginate large result sets with
limitandoffset.