Appearance
API reference
Use the Exploit Shield API to read and manage your exposures, reports, vendors, configurations, alerting, and users from your own scripts and tools, such as a SIEM.
Get started
Send HTTPS requests to the API host for your organization:
text
https://api.<your-domain><your-domain> is the domain of your Exploit Shield dashboard.
- All endpoints, except the health check, start with
/v1. For example,https://api.<your-domain>/v1/secrets. - Send request bodies as JSON with the
Content-Type: application/jsonheader. All responses are JSON. - Use HTTPS. HTTP requests are redirected to HTTPS.
To check that your API key works, get your own user record:
bash
curl -H "Authorization: Bearer $EXPLOIT_SHIELD_API_KEY" \
"https://api.<your-domain>/v1/users/me"Authentication
Every /v1 request needs an API key in the Authorization header:
http
Authorization: Bearer <your-api-key>To create a key, see API keys. A request with a key succeeds only when:
- The key isn't expired or archived.
- The key owner's sign-in account is confirmed, enabled, and not locked.
- The key owner is listed on the Users page.
When you archive a key or someone disables a sign-in account, the change takes effect within about one minute. Role changes and removals from the Users page take effect on the next request.
Permissions
A request runs with the current role of the key owner. For more information about roles, see Roles.
| Role | What the role can do |
|---|---|
user, viewer, manager, analyst | Call all GET endpoints, except Search users and List users by role. |
admin | Call all endpoints, including every POST, PUT, PATCH, and DELETE request. |
Protect secret values
Responses contain live secrets
Exposure responses include the full secret value in the secret_value field, and every role can read them. Treat API responses as you treat the credentials themselves:
- Store your API key in a secret manager.
- Don't write raw responses to logs.
- Before you forward exposures to another tool, such as a SIEM, remove
secret_valueunless the tool needs it.
Pagination
Endpoints that return pages accept these query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Maximum number of items in the response, from 1 to 100. |
offset | integer | 0 | Position of the first item to return, starting at 0. |
A page looks like this:
json
{
"items": [],
"total": 142,
"limit": 50,
"offset": 0
}To get the next page, add limit to offset. Stop when offset plus the number of items is equal to or greater than total.
Results are sorted by id in ascending order, with these exceptions:
- Vendors are sorted by
vendor_name. - Vendor incidents are sorted newest first.
- Alert events are sorted newest first.
Pages are stable while the data doesn't change. Items that are added or changed between requests can move to a different page. To collect new items over time, store the highest id that you received.
Rate limits
Each client IP address can send up to 20 requests per second, with bursts of up to 40 requests. If you send more, the API returns 429 Too Many Requests with a Retry-After header. Wait the number of seconds in Retry-After, and then try again.
Errors
Errors return a JSON object with a detail message. Most errors also include an error_code. Validation errors (422) also include an errors list:
json
{
"detail": "Validation failed",
"error_code": "VALIDATION_ERROR",
"errors": [
{
"type": "validation_error",
"loc": ["body", "user_email"],
"msg": "field required",
"input": ""
}
]
}| Status | error_code | Meaning |
|---|---|---|
400 Bad Request | The action isn't allowed. For example, you tried to delete your own user. | |
401 Unauthorized | The API key is missing, unknown, expired, or archived. Or the key owner isn't on the Users page, or their sign-in account is unconfirmed, disabled, or locked. Retrying doesn't help. | |
403 Forbidden | Your role can't call this endpoint, or you can't make this change, such as changing your own role. Write requests need the admin role. | |
404 Not Found | NOT_FOUND | The record doesn't exist or was deleted. |
409 Conflict | CONFLICT | The record already exists, such as a duplicate configuration or user email. Also returned when you try to change the name or domain of a vendor. |
422 Unprocessable Entity | VALIDATION_ERROR | A query parameter or body field isn't valid. |
429 Too Many Requests | You exceeded the rate limit. Wait for the time in Retry-After. | |
500 Internal Server Error | INTERNAL_ERROR or DATABASE_ERROR | An unexpected error occurred. Try again later. If the error continues, send email to support@exploitstrike.com. |
503 Service Unavailable | The sign-in service is temporarily unavailable. Try again with backoff. |
Data formats
- Timestamps use ISO 8601. Most timestamps end in
Z(UTC).repo_commit_datehas no time zone offset. - Severity uses two scales:
- Exposures, configurations, and vendor incidents use
0to10. A severity of8or higher is high. - Alert rules and alert events use
1to4:1is Low,2is Medium,3is High, and4is Critical.
- Exposures, configurations, and vendor incidents use
- JSON in strings. Some fields contain a JSON document encoded as a string:
result_data,details,scorecard_data, anddelivery_results_json. Parse the string to read the values. - Deleted records aren't returned. The
deletedfield in responses is alwaysfalse.
Versions and compatibility
The API version is part of the path, such as /v1. Use only the endpoints, parameters, and fields in this reference. Anything that isn't documented here can change or be removed without notice.
Changes we can make at any time
We can make these changes to /v1 without notice. Build your integration so that it keeps working when they happen:
- Add endpoints.
- Add optional query parameters and optional request body fields.
- Add fields to responses. Ignore fields that you don't recognize.
- Add values to fields that have a fixed set of values, such as
type,status,category, orsecret_type. Handle values that you don't recognize. - Change the order of fields in a response.
- Change the text of error messages. To handle errors, use the HTTP status code and
error_code, not thedetailtext. - Fix behavior that doesn't match this reference.
Breaking changes
A breaking change is a change that can stop a correct integration from working. For example:
- Removing or renaming an endpoint, parameter, or field.
- Changing the type or format of a field.
- Making an optional parameter or field required.
- Changing the meaning of an existing value.
We don't make breaking changes to /v1 without notice. Before a breaking change takes effect, we announce it in the Changelog. For large changes, we can release a new version, such as /v2.
To protect your data, we can make a breaking change without notice when it's needed to fix a security issue. We announce these changes in the Changelog.
Request logging
Exploit Shield logs every /v1 request with the user, method, path, query string, status code, duration, client IP address, user agent, and request ID.
Endpoints
| Area | Method | Path | Role | Description |
|---|---|---|---|---|
| Exposures | GET | /v1/secrets | Any | List exposures |
| Exposures | GET | /v1/secrets/search | Any | Search exposures |
| Exposures | GET | /v1/secrets/summary | Any | Count exposures by group |
| Exposures | GET | /v1/secrets/by-severity/{severity} | Any | List exposures by severity |
| Exposures | GET | /v1/secrets/unalerted | Any | List unalerted exposures |
| Exposures | GET | /v1/secrets/unremediated | Any | List unremediated exposures |
| Exposures | GET | /v1/secrets/{secret_id} | Any | Get an exposure |
| Exposures | PATCH | /v1/secrets/{secret_id}/false-positive | admin | Mark an exposure as a false positive |
| Exposures | PATCH | /v1/secrets/{secret_id}/remediated | admin | Mark an exposure as remediated |
| Exposures | PATCH | /v1/secrets/bulk/false-positive | admin | Mark exposures as false positives in bulk |
| Exposures | PATCH | /v1/secrets/bulk/remediated | admin | Mark exposures as remediated in bulk |
| Reports | GET | /v1/attribution-results | Any | List reports |
| Reports | GET | /v1/attribution-results/summary | Any | Count reports by group |
| Reports | GET | /v1/attribution-results/{result_id} | Any | Get a report |
| Reports | PATCH | /v1/attribution-results/{result_id}/false-positive | admin | Mark a report as a false positive |
| Reports | PATCH | /v1/attribution-results/{result_id}/remediated | admin | Mark a report as remediated |
| Reports | PATCH | /v1/attribution-results/bulk/false-positive | admin | Mark reports as false positives in bulk |
| Reports | PATCH | /v1/attribution-results/bulk/remediated | admin | Mark reports as remediated in bulk |
| Vendors | GET | /v1/vendors | Any | List vendors |
| Vendors | GET | /v1/vendors/{vendor_id}/incidents | Any | List vendor incidents |
| Vendors | GET | /v1/vendors/{vendor_id}/scorecard | Any | Get a vendor scorecard |
| Vendors | PATCH | /v1/vendor-incidents/{incident_id}/false-positive | admin | Mark a vendor incident as a false positive |
| Vendors | PATCH | /v1/vendor-incidents/{incident_id}/acknowledged | admin | Acknowledge a vendor incident |
| Configurations | GET | /v1/config | Any | List configurations |
| Configurations | GET | /v1/config/search | Any | Search configurations |
| Configurations | GET | /v1/config/third-party | Any | List third-party configurations |
| Configurations | GET | /v1/config/blacklisted | Any | List blocklisted configurations |
| Configurations | GET | /v1/config/{config_id} | Any | Get a configuration |
| Configurations | POST | /v1/config | admin | Create a configuration |
| Configurations | PUT | /v1/config/{config_id} | admin | Update a configuration |
| Configurations | DELETE | /v1/config/{config_id} | admin | Delete a configuration |
| Alerting | GET | /v1/alerting/destinations | Any | List alert destinations |
| Alerting | POST | /v1/alerting/destinations | admin | Create an alert destination |
| Alerting | PATCH | /v1/alerting/destinations/{destination_id} | admin | Update an alert destination |
| Alerting | DELETE | /v1/alerting/destinations/{destination_id} | admin | Delete an alert destination |
| Alerting | GET | /v1/alerting/rules | Any | List alert rules |
| Alerting | POST | /v1/alerting/rules | admin | Create an alert rule |
| Alerting | PATCH | /v1/alerting/rules/{rule_id} | admin | Update an alert rule |
| Alerting | DELETE | /v1/alerting/rules/{rule_id} | admin | Delete an alert rule |
| Alerting | GET | /v1/alerting/events | Any | List alert events |
| Users | GET | /v1/users/me | Any | Get the current user |
| Users | GET | /v1/users | Any | List users |
| Users | GET | /v1/users/search | admin | Search users |
| Users | GET | /v1/users/by-role/{role} | admin | List users by role |
| Users | GET | /v1/users/{user_id} | Any | Get a user |
| Users | POST | /v1/users | admin | Create a user |
| Users | PUT | /v1/users/{user_id} | admin | Update a user |
| Users | DELETE | /v1/users/{user_id} | admin | Delete a user |
| Statistics | GET | /v1/stats/secrets | Any | Get exposure counts |
| Statistics | GET | /v1/stats/users | Any | Get user counts |
| Statistics | GET | /v1/stats/configs | Any | Get configuration counts |
| Statistics | GET | /v1/stats/scorecard | Any | Get the organization scorecard |
| Changelog | GET | /v1/changelog | Any | Get the changelog |
| Health | GET | /health | None | Check API health |
Exposures
An exposure is a leaked credential, token, key, or other sensitive value that Exploit Shield found for your organization. For more information, see Exposures.
Exposure object
json
{
"id": 101,
"label": "secrets",
"secret_type": "AWS_ACCESS_KEY_ID",
"secret_key": "AWS_ACCESS_KEY_ID",
"secret_value": "AKIAIOSFODNN7EXAMPLE",
"comment": "Found in deployment script",
"file_reference": "deploy/env.sh",
"line_reference": 25,
"preview_lines": "24: export AWS_REGION=us-east-1\n25: export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE",
"repo_link": "https://github.com/example-org/infra",
"repo_commit": "4f8a2b1c9d0e",
"repo_commit_date": "2026-08-15T14:22:00",
"repo_branch": "main",
"severity": 9,
"assigned_to": null,
"remediation_status": "pending",
"affected_system": "production",
"alerted": true,
"repo_remediated": false,
"false_positive": false,
"deleted": false
}| Field | Type | Description |
|---|---|---|
id | integer | Exposure ID. |
label | string or null | Category label. |
secret_type | string or null | Type of secret, such as API_KEY or AWS_ACCESS_KEY_ID. |
secret_key | string or null | Variable name or key name in the source file. |
secret_value | string or null | The full secret value. See Protect secret values. |
comment | string or null | Note about the exposure. |
file_reference | string or null | Path of the file in the repository or source. |
line_reference | integer or null | Line number of the exposure, starting at 1. |
preview_lines | string or null | Lines around the exposure. |
repo_link | string or null | URL of the repository or source. |
repo_commit | string or null | Commit SHA. |
repo_commit_date | string or null | Commit date, without a time zone offset. |
repo_branch | string or null | Branch name. |
severity | integer or null | Severity from 0 to 10. 8 or higher is high. |
assigned_to | integer or null | ID of the user that the exposure is assigned to. |
remediation_status | string or null | Remediation state as text, such as pending. |
affected_system | string or null | Affected system or environment. |
alerted | boolean | true if an alert was sent for the exposure. |
repo_remediated | boolean | true if the exposure is marked as remediated. |
false_positive | boolean | true if the exposure is marked as a false positive. |
deleted | boolean | Always false. |
List exposures
GET /v1/secrets
Returns a page of exposure objects.
- Role: Any
- Query parameters:
limitandoffset
Search exposures
GET /v1/secrets/search
Returns a page of exposure objects that match all the filters you send. Text filters match any part of the value.
- Role: Any
| Parameter | Type | Description |
|---|---|---|
secret_type | string | Text in secret_type. |
severity | integer | Exact severity, from 0 to 10. |
remediation_status | string | Text in remediation_status. |
repo_link | string | Text in repo_link. |
file_reference | string | Text in file_reference. |
secret_key | string | Text in secret_key. |
comment | string | Text in comment. |
repo_branch | string | Text in repo_branch. |
affected_system | string | Text in affected_system. |
alerted | boolean | true or false. |
repo_remediated | boolean | true or false. |
false_positive | string | show returns all exposures, hide excludes false positives, and only returns only false positives. |
limit, offset | integer | See Pagination. |
bash
curl -H "Authorization: Bearer $EXPLOIT_SHIELD_API_KEY" \
"https://api.<your-domain>/v1/secrets/search?false_positive=hide&repo_remediated=false&limit=50&offset=0"Count exposures by group
GET /v1/secrets/summary
Returns the number of exposures for each value of a field, with the largest count first.
- Role: Any
- Query parameters:
group_byis one ofsecret_type(default),severity,remediation_status,repo_link, orfile_reference.
json
[
{
"group_key": "AWS_ACCESS_KEY_ID",
"transaction_count": 42
}
]transaction_count is the number of exposures in the group.
List exposures by severity
GET /v1/secrets/by-severity/{severity}
Returns a list, not a page, of exposure objects with the exact severity.
- Role: Any
- Path parameters:
severityis an integer from0to10.
List unalerted exposures
GET /v1/secrets/unalerted
Returns a page of exposure objects where alerted is false.
- Role: Any
- Query parameters:
limitandoffset
List unremediated exposures
GET /v1/secrets/unremediated
Returns a page of exposure objects where repo_remediated is false.
- Role: Any
- Query parameters:
limitandoffset
Get an exposure
GET /v1/secrets/{secret_id}
Returns one exposure object.
- Role: Any
- Path parameters:
secret_idis the exposure ID.
Mark an exposure as a false positive
PATCH /v1/secrets/{secret_id}/false-positive
Sets or clears the false positive flag on one exposure. Returns the updated exposure object.
- Role:
admin - Path parameters:
secret_idis the exposure ID.
json
{
"false_positive": true
}Mark an exposure as remediated
PATCH /v1/secrets/{secret_id}/remediated
Sets or clears the remediated flag on one exposure. Returns the updated exposure object.
- Role:
admin - Path parameters:
secret_idis the exposure ID.
json
{
"secret_id": 101,
"repo_remediated": true
}The body must include secret_id. The API updates the exposure in the path.
Mark exposures as false positives in bulk
PATCH /v1/secrets/bulk/false-positive
Sets or clears the false positive flag on several exposures.
- Role:
admin
json
{
"secret_ids": [101, 102, 105],
"false_positive": true
}Response:
json
{
"total_count": 3,
"updated_count": 2,
"failed_ids": [105]
}total_count is the number of distinct IDs that you sent. failed_ids lists the IDs that weren't found.
Mark exposures as remediated in bulk
PATCH /v1/secrets/bulk/remediated
Sets or clears the remediated flag on several exposures. The response has the same fields as Mark exposures as false positives in bulk.
- Role:
admin
json
{
"secret_ids": [101, 102, 105],
"repo_remediated": true
}Reports
A report is an attribution analysis of a repository. It includes ownership, severity, confidence, and evidence. For more information, see Reports.
Report object
json
{
"id": 12,
"repo_link": "https://github.com/example-org/service-api",
"repo_commit": "abc123def456",
"repo_commit_date": "2026-08-20T09:15:00",
"repo_branch": "main",
"result_data": "{\"severity\": \"High\", \"confidence\": 85, \"ownership\": \"first-party\"}",
"engine": "attribution-v1",
"ownership": "first-party",
"remediated": false,
"false_positive": false
}| Field | Type | Description |
|---|---|---|
id | integer | Report ID. |
repo_link | string or null | URL of the repository or source. |
repo_commit | string or null | Commit SHA. |
repo_commit_date | string or null | Commit date, without a time zone offset. |
repo_branch | string or null | Branch name. |
result_data | string or null | The report as a JSON string, with severity, confidence, summary, evidence, and the report text in Markdown. |
engine | string or null | Name of the analysis that created the report. |
ownership | string or null | first-party, third-party, or joint. The dashboard and scorecard count a report with no value as first-party. |
remediated | boolean | true if the report is marked as remediated. |
false_positive | boolean | true if the report is marked as a false positive. |
List reports
GET /v1/attribution-results
Returns a page of report objects that match all the filters you send.
- Role: Any
| Parameter | Type | Description |
|---|---|---|
repo_commit | string | Exact commit SHA. |
repo_branch | string | Exact branch name. |
repo_link | string | Exact repository URL. |
engine | string | Text in engine. |
remediated | boolean | true or false. |
false_positive | boolean | true or false. |
ownership | string | One exact value: first-party, third-party, or joint. Reports with no ownership value don't match. |
ownership_in | string | Comma-separated values, such as first-party,joint. If the list includes first-party, reports with no ownership value also match. |
limit, offset | integer | See Pagination. |
To get the same open first-party reports that the dashboard shows, use ownership_in:
bash
curl -H "Authorization: Bearer $EXPLOIT_SHIELD_API_KEY" \
"https://api.<your-domain>/v1/attribution-results?false_positive=false&remediated=false&ownership_in=first-party&limit=50&offset=0"Count reports by group
GET /v1/attribution-results/summary
Returns the number of reports for each value of a field, with the largest count first. The response has the same format as Count exposures by group.
- Role: Any
- Query parameters:
group_byis one ofrepo_branch(default),repo_link,remediated, orfalse_positive.
Get a report
GET /v1/attribution-results/{result_id}
Returns one report object.
- Role: Any
- Path parameters:
result_idis the report ID.
Mark a report as a false positive
PATCH /v1/attribution-results/{result_id}/false-positive
Sets or clears the false positive flag on one report. Returns the updated report object.
- Role:
admin - Path parameters:
result_idis the report ID.
json
{
"false_positive": true
}Mark a report as remediated
PATCH /v1/attribution-results/{result_id}/remediated
Sets or clears the remediated flag on one report. Returns the updated report object.
- Role:
admin - Path parameters:
result_idis the report ID.
json
{
"remediated": true
}Mark reports as false positives in bulk
PATCH /v1/attribution-results/bulk/false-positive
Sets or clears the false positive flag on several reports. The response has the same fields as Mark exposures as false positives in bulk.
- Role:
admin
json
{
"result_ids": [12, 15],
"false_positive": true
}Mark reports as remediated in bulk
PATCH /v1/attribution-results/bulk/remediated
Sets or clears the remediated flag on several reports. The response has the same fields as Mark exposures as false positives in bulk.
- Role:
admin
json
{
"result_ids": [12, 15],
"remediated": true
}Vendors
Vendors are the third parties that you monitor. Each vendor has incidents and a score. For more information, see Vendors.
List vendors
GET /v1/vendors
Returns a list of your monitored vendors, sorted by name, with the number of incidents and the date of the latest incident.
- Role: Any
json
[
{
"id": 4,
"vendor_name": "Acme Cloud",
"cnames": ["acmecloud.example"],
"incident_count": 3,
"latest_incident_date": "2026-09-10T12:00:00Z",
"created_at": "2026-07-01T00:00:00Z",
"updated_at": "2026-09-10T12:00:00Z"
}
]List vendor incidents
GET /v1/vendors/{vendor_id}/incidents
Returns a page of incidents for one vendor, newest first.
- Role: Any
- Path parameters:
vendor_idis the vendor ID. - Query parameters:
severity(optional): Exact severity, from0to10.false_positive(optional):trueorfalse.limitandoffset
json
{
"items": [
{
"id": 27,
"vendor_id": 4,
"incident_key": "acmecloud:secret_exposure:9f8e7d",
"short_summary": "2 secrets exposed in public repository",
"severity": 8,
"category": "secret_exposure",
"incident_date": "2026-09-10T12:00:00Z",
"confidence": 92,
"scorecard_data": "{\"secret_count\": 2, \"platform\": \"github\"}",
"false_positive": false,
"acknowledged": false,
"created_at": "2026-09-10T12:05:00Z",
"updated_at": "2026-09-10T12:05:00Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}Get a vendor scorecard
GET /v1/vendors/{vendor_id}/scorecard
Returns the vendor's score from 0 to 100 and its breakdowns. Incidents that are marked as false positives don't count. For more information, see Scoring and attribution.
- Role: Any
- Path parameters:
vendor_idis the vendor ID.
json
{
"vendor_id": 4,
"vendor_name": "Acme Cloud",
"score": 88,
"total_incidents": 3,
"active_incidents": 2,
"false_positive_incidents": 1,
"severity_counts": { "high": 1, "medium": 1 },
"category_counts": { "secret_exposure": 2 },
"aggregate_metrics": { "secret_count": 3.0 },
"latest_incident_date": "2026-09-10T12:00:00Z",
"severity_timeline": [
{ "date": "2026-09", "critical": 0, "high": 1, "medium": 1 }
],
"indicator_breakdown": [
{ "name": "secret_exposure", "count": 2, "pct": 100 }
],
"platform_breakdown": [
{ "name": "github", "count": 2, "pct": 100 }
]
}Mark a vendor incident as a false positive
PATCH /v1/vendor-incidents/{incident_id}/false-positive
Sets or clears the false positive flag on one incident. Incidents that are marked as false positives don't count toward the vendor's score. Returns the updated incident.
- Role:
admin - Path parameters:
incident_idis the incident ID.
json
{
"false_positive": true
}Acknowledge a vendor incident
PATCH /v1/vendor-incidents/{incident_id}/acknowledged
Sets or clears the acknowledged flag on one incident. Returns the updated incident.
- Role:
admin - Path parameters:
incident_idis the incident ID.
json
{
"acknowledged": true
}Configurations
Configurations are the domains, keywords, integrations, and vendors that Exploit Shield monitors for you. A new configuration is Pending until Exploit Strike reviews it, and then it's Active. For more information, see Configurations.
Add and change configurations in the dashboard
A domain and its keywords are stored as separate records, and the dashboard keeps them in sync. We recommend that you add and change configurations on the Configurations page, and use the API to read them.
Configuration object
json
{
"id": 7,
"risk_keyword": "example.com",
"risk_location": "domain",
"risk_severity": 1,
"is_third_party": false,
"is_blacklisted": false,
"alert_type": "none",
"alert_recipient": null,
"details": "{\"kind\": \"domain\", \"keywords\": [\"example\"], \"notes\": \"Primary corporate domain\"}",
"deleted": false,
"approved": false
}| Field | Type | Description |
|---|---|---|
id | integer | Configuration ID. The API assigns it. |
risk_keyword | string or null | The monitored value: a domain, keyword, integration match value, or vendor name. See Configuration types. |
risk_location | string or null | Type of configuration: domain, integration, or vendor. Keywords use domain. |
risk_severity | integer or null | Severity from 0 to 10. The dashboard sets 1, or 8 for a critical vendor. |
is_third_party | boolean | true for vendors. |
is_blacklisted | boolean | Blocklist flag. The dashboard sets false. |
alert_type | string | none, email, or sms. This field doesn't send alerts. To send alerts, use alert rules. |
alert_recipient | integer or null | A user ID. This field doesn't send alerts. |
details | string or null | More settings as a JSON string. The format depends on the type. See Configuration types. |
deleted | boolean | Always false. To delete a configuration, see Delete a configuration. |
approved | boolean | false while Pending and true when Active. Only Exploit Strike can change it. |
Configuration types
| Type | risk_location | risk_keyword | details |
|---|---|---|---|
| Domain | domain | The domain, such as example.com | {"kind": "domain", "keywords": ["example"], "notes": "..."} |
| Keyword | domain | The keyword, such as example | {"kind": "keyword", "parent_domain": "example.com"} |
| Integration | integration | The value to match | {"serviceName": "Okta", "matchType": "subdomain", "notes": "..."}. matchType is subdomain, path, or string. |
| Vendor | vendor | The vendor name | {"kind": "vendor", "domains": ["vendor.example"], "isCritical": true} |
notes is optional. A domain lists its keywords in keywords, and each keyword is also a separate configuration that names the domain in parent_domain.
List configurations
GET /v1/config
Returns a page of configuration objects.
- Role: Any
- Query parameters:
limitandoffset
Search configurations
GET /v1/config/search
Returns a page of configuration objects that match all the filters you send.
- Role: Any
| Parameter | Type | Description |
|---|---|---|
risk_keyword | string | Text in risk_keyword. |
risk_location | string | Text in risk_location, such as vendor. |
risk_severity | integer | Exact severity, from 0 to 10. |
is_third_party | boolean | true or false. |
is_blacklisted | boolean | true or false. |
limit, offset | integer | See Pagination. |
List third-party configurations
GET /v1/config/third-party
Returns a page of configuration objects where is_third_party is true.
- Role: Any
- Query parameters:
limitandoffset
List blocklisted configurations
GET /v1/config/blacklisted
Returns a page of configuration objects where is_blacklisted is true.
- Role: Any
- Query parameters:
limitandoffset
Get a configuration
GET /v1/config/{config_id}
Returns one configuration object.
- Role: Any
- Path parameters:
config_idis the configuration ID.
Create a configuration
POST /v1/config
Creates a configuration and returns the new configuration object. The new configuration is Pending until Exploit Strike reviews it.
- Role:
admin - Body: A configuration object. Use the format for the configuration type. The API ignores
id,approved, anddeleted.
Returns 409 Conflict if an active configuration already covers the same domain, the same keyword for the domain, the same integration match, or the same vendor.
Update a configuration
PUT /v1/config/{config_id}
Changes the fields that you send and returns the updated configuration object. The API ignores id, approved, and deleted.
- Role:
admin - Path parameters:
config_idis the configuration ID.
You can't change the name or domain of a vendor. The API returns 409 Conflict. To change them, delete the vendor and create it again.
Delete a configuration
DELETE /v1/config/{config_id}
Deletes one configuration.
- Role:
admin - Path parameters:
config_idis the configuration ID.
json
{
"message": "Configuration deleted successfully"
}- Deleting a domain doesn't delete its keywords. Delete each keyword too.
- When you delete the last configuration for a vendor, the vendor no longer appears in List vendors.
Alerting
Alerting sends new reports to your webhooks. An alert rule decides which reports to send, and an alert destination is a webhook that receives them. For more information, see Alerting.
List alert destinations
GET /v1/alerting/destinations
Returns a list of alert destinations.
- Role: Any
json
[
{
"id": 1,
"type": "siem",
"label": "SOC Webhook",
"endpoint": "https://siem.example.com/webhooks/exploitshield",
"enabled": true,
"created_at": "2026-08-25T15:00:00Z",
"updated_at": "2026-08-25T15:00:00Z"
}
]Create an alert destination
POST /v1/alerting/destinations
Creates an alert destination and returns it.
- Role:
admin
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | discord, teams, google_chat, siem, cti, or other. |
label | string or null | No | Display name. |
endpoint | string | Yes | Webhook URL that receives alerts. |
enabled | boolean | No | Default is true. |
Update an alert destination
PATCH /v1/alerting/destinations/{destination_id}
Changes the fields that you send (type, label, endpoint, or enabled) and returns the updated destination.
- Role:
admin - Path parameters:
destination_idis the destination ID.
Delete an alert destination
DELETE /v1/alerting/destinations/{destination_id}
Deletes an alert destination and removes it from your alert rules.
- Role:
admin - Path parameters:
destination_idis the destination ID.
json
{
"message": "Alert destination deleted successfully"
}List alert rules
GET /v1/alerting/rules
Returns a list of alert rules.
- Role: Any
json
[
{
"id": 1,
"name": "high-confidence-reports",
"source": "attribution_report",
"enabled": true,
"destination_ids": [1],
"min_severity_numeric": 3,
"min_confidence_numeric": 80,
"created_at": "2026-08-25T15:05:00Z",
"updated_at": "2026-08-25T15:05:00Z"
}
]Create an alert rule
POST /v1/alerting/rules
Creates an alert rule and returns it.
- Role:
admin
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Rule name. Must be unique, up to 255 characters. |
source | string | No | attribution_report, which is the default and the only value. |
enabled | boolean | No | Default is true. |
destination_ids | list of integers | Yes | IDs of one or more existing destinations. |
min_severity_numeric | integer or null | No | Lowest severity to send, from 1 (Low) to 4 (Critical). |
min_confidence_numeric | integer or null | No | Lowest confidence to send, from 0 to 100. |
Update an alert rule
PATCH /v1/alerting/rules/{rule_id}
Changes the fields that you send and returns the updated rule. You can send any field from Create an alert rule.
- Role:
admin - Path parameters:
rule_idis the rule ID.
Delete an alert rule
DELETE /v1/alerting/rules/{rule_id}
Deletes an alert rule.
- Role:
admin - Path parameters:
rule_idis the rule ID.
json
{
"message": "Alert rule deleted successfully"
}List alert events
GET /v1/alerting/events
Returns a page of alert events, newest first. An alert event records one alert and its delivery to each destination.
- Role: Any
- Query parameters:
limitandoffset
json
{
"items": [
{
"id": 9,
"rule_id": 1,
"rule_name": "high-confidence-reports",
"subject_type": "attribution_report",
"subject_id": "12",
"severity_numeric": 3,
"severity_label": "High",
"title": "High confidence attribution report",
"delivery_results_json": "[{\"destination_id\": 1, \"status_code\": 200, \"ok\": true}]",
"status": "sent",
"created_at": "2026-08-25T16:00:00Z",
"updated_at": "2026-08-25T16:00:00Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}status is sent, partial, or failed. subject_id is the report ID.
Users
Users are the people and integrations that can sign in to Exploit Shield or use an API key. For more information, see Users and Roles.
User object
json
{
"id": 1,
"user_role": "admin",
"user_name": "Jane Doe",
"user_email": "jane.doe@example.com",
"user_phone": "+14155552671"
}Get the current user
GET /v1/users/me
Returns the user object of the API key owner. Use it to test a new API key.
- Role: Any
List users
GET /v1/users
Returns a page of user objects.
- Role: Any
- Query parameters:
limitandoffset
Search users
GET /v1/users/search
Returns a page of user objects that match all the filters you send.
- Role:
admin - Query parameters:
user_role(optional): Exact role.user_email(optional): Text in the email address.limitandoffset
List users by role
GET /v1/users/by-role/{role}
Returns a list, not a page, of user objects with the role.
- Role:
admin - Path parameters:
roleisadmin,user,viewer,manager, oranalyst.
Get a user
GET /v1/users/{user_id}
Returns one user object.
- Role: Any
- Path parameters:
user_idis the user ID.
Create a user
POST /v1/users
Creates a user and returns the new user object.
- Role:
admin
json
{
"user_role": "analyst",
"user_name": "SOC SIEM poller",
"user_email": "siem@example.com",
"user_phone": "+14155550199"
}| Field | Type | Required | Description |
|---|---|---|---|
user_role | string | Yes | admin, user, viewer, manager, or analyst. |
user_name | string | Yes | Display name. |
user_email | string | Yes | Email address. It must be unique, and it's stored in lowercase. |
user_phone | string or null | No | Phone number in E.164 format, such as +14155550199. US numbers without a country code are also accepted. The API stores numbers in E.164 format and returns 422 for a number that isn't valid. An empty string clears the number. |
Returns 409 Conflict if a user with the email address already exists.
Update a user
PUT /v1/users/{user_id}
Updates a user and returns the updated user object.
- Role:
admin - Path parameters:
user_idis the user ID. - Body:
user_roleanduser_nameare required.user_emailanduser_phoneare optional. The fields have the same format as in Create a user. If you send a phone number that's different from the stored number, it must be valid.
You can't change your own role. The API returns 403 Forbidden. Ask another admin to change it.
Delete a user
DELETE /v1/users/{user_id}
Deletes a user. API keys that the user owns stop working right away.
- Role:
admin - Path parameters:
user_idis the user ID.
json
{
"message": "User deleted successfully"
}You can't delete your own user. The API returns 400 Bad Request.
Statistics
Statistics return the counts and scores that the dashboard shows. For more information, see Dashboard home.
Get exposure counts
GET /v1/stats/secrets
Returns exposure counts.
- Role: Any
json
{
"total_secrets": 120,
"alerted_secrets": 95,
"remediated_secrets": 40,
"high_severity_secrets": 18,
"unalerted_secrets": 25,
"unremediated_secrets": 80
}high_severity_secrets counts exposures with a severity of 8 or higher.
Get user counts
GET /v1/stats/users
Returns user counts.
- Role: Any
json
{
"total_users": 8,
"admin_users": 2,
"regular_users": 4
}regular_users counts only users with the user role. Users with the viewer, manager, or analyst role count only in total_users.
Get configuration counts
GET /v1/stats/configs
Returns configuration counts.
- Role: Any
json
{
"total_configs": 15,
"third_party_configs": 10,
"blacklisted_configs": 0,
"high_risk_configs": 6
}high_risk_configs counts configurations with a severity of 8 or higher.
Get the organization scorecard
GET /v1/stats/scorecard
Returns your organization's score and breakdowns. The score uses exposures that aren't false positives and open reports.
- Role: Any
json
{
"total_exposures": 115,
"unremediated_exposures": 75,
"high_severity_exposures": 16,
"total_reports": 14,
"open_reports": 4,
"first_party_open_reports": 2,
"third_party_open_reports": 2,
"score": 84,
"critical_open_reports": 0,
"false_positive_reports": 1,
"remediated_reports": 10,
"avg_dwell_days": 12.5,
"latest_report_date": "2026-09-18T10:30:00Z",
"severity_counts": { "high": 2, "medium": 2 },
"ownership_counts": { "first-party": 2, "third-party": 2 },
"source_counts": { "github": 3, "postman": 1 },
"severity_timeline": [
{ "date": "2026-09", "critical": 0, "high": 2, "medium": 2 }
],
"indicator_breakdown": [
{ "name": "domain", "count": 3, "pct": 75 },
{ "name": "keyword", "count": 1, "pct": 25 }
],
"platform_breakdown": [
{ "name": "github", "count": 3, "pct": 75 },
{ "name": "postman", "count": 1, "pct": 25 }
]
}Changelog
Get the changelog
GET /v1/changelog
Returns the product changelog in Markdown. For more information, see Changelog.
- Role: Any
json
{
"markdown": "# Changelog\n...",
"last_updated": "2026-10-01T00:00:00Z"
}Health
Check API health
GET /health
Returns 200 OK with "status": "healthy" when the API is available. Use it for uptime monitoring. This endpoint doesn't need an API key.