POST
Required scope https://app.honeybadger.io/v3/projects/{project_id}/sites
uptime:write
Creates an uptime monitoring site. Requires uptime monitoring on the plan.
Example request
curl -X POST "https://app.honeybadger.io/v3/projects/$PROJECT_ID/sites" \ -H "Authorization: Bearer $HONEYBADGER_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "url": "https://www.example.com/health"}'Parameters
1Path parameters
| Field | Type | Description |
|---|---|---|
project_id required | string | Project ID. |
Request body
name defaults to the URL.
| Field | Type | Description |
|---|---|---|
name | string | Name shown for the site in Honeybadger and on status pages. |
url required | uri | Must start with http:// or https://, with no surrounding whitespace. |
match_type | string | null | How a check decides the site is up (see SiteMatchType). Null resets it to success. How a response is judged. success: any 2xx; match must be left out. exact: the response status code equals match. include / exclude: the body does / doesn't contain match. jmespath: match is a JMESPath expression evaluated against the JSON body; numbers in it use backticks, not quotes. Allowed values: success, exact, include, exclude, jmespath. Default: "success". |
match | string | null | What match_type compares against (see SiteMatchType). Required unless match_type is success, and must be left out with success. Null clears it. Max length 255. |
request_method | string | null | HTTP method each check sends. Null resets it to GET. Allowed values: GET, POST, PUT, PATCH, DELETE. Default: "GET". |
validate_ssl | boolean | null | Fail the check when the TLS certificate does not validate. Null resets it to true. Default: true. |
request_body | string | null | Body to send with the request, up to 32 KB. Null clears it. Max length 32768. |
request_headers | object | null | Headers to send with the request, as header name to value. Replaces the stored headers; null or {} clears them. Default: {}. |
request_headers.* | string | Any other keys. |
frequency | integer | null | Minutes between checks. The plan sets the most frequent allowed. Null resets it to 5. A value below the plan's floor is refused. Allowed values: 1, 2, 5, 15. Default: 5. |
locations | array | null | A set of location names to check from. Null or empty means every location. A set; order is ignored and duplicates are dropped. Allowed values: Virginia, Frankfurt, Singapore, London, Oregon. Default: []. |
outage_threshold | integer | null | Consecutive failures before an outage is declared. null means down once failures reach 50% of locations. Min 1. |
active | boolean | null | Whether monitoring is active. After 740 consecutive failed checks the server sets it to false. Null resets it to true. Default: true. |
timeout | integer | null | Request timeout in seconds, 1 to 120, default 30, and less than the frequency in seconds. Changing it requires the uptime timeout feature on the account; without it, only the current value (on create, the default) is accepted. Null resets it to the default. |
Responses
1201 Site created
Example payload
{ "data": { "id": "9f8b6d2e-4c1a-4b7f-9e35-2a6c8d0f1b47", "project_id": "Xk9mZp", "name": "Production App", "url": "https://app.example.com", "active": true, "state": "up", "last_checked_at": "2026-01-01T00:00:00Z", "match_type": "success", "match": null, "request_method": "GET", "frequency": 1, "locations": [ "Virginia", "London" ], "validate_ssl": true, "request_headers": {}, "request_body": null, "outage_threshold": 2, "timeout": 30, "created_at": "2026-01-01T00:00:00Z", "links": { "web": "https://app.honeybadger.io/projects/Xk9mZp" } }, "meta": { "request_id": "6f1c2b0e-8d4a-4f6e-9b2a-3c5d7e9f1a2b" }}Response schema24
| Field | Type | Description |
|---|---|---|
data required | object | A URL Honeybadger checks for uptime from several locations on a schedule, alerting when it goes down and when it recovers. |
data.id required | uuid | |
data.project_id required | string | ID of the project this site belongs to. |
data.name required | string | Display name for the site. |
data.url required | string | URL to monitor. Includes the scheme. |
data.active required | boolean | Whether monitoring is active. After 740 consecutive failed checks the server sets it to false. |
data.state required | string | Current state of the site. Allowed values: pending, up, down. |
data.last_checked_at required | date-time | null | When the site was last checked. |
data.match_type required | string | How a response is judged. success: any 2xx; match must be left out. exact: the response status code equals match. include / exclude: the body does / doesn't contain match. jmespath: match is a JMESPath expression evaluated against the JSON body; numbers in it use backticks, not quotes. Allowed values: success, exact, include, exclude, jmespath. |
data.match required | string | null | Value to match in the response. |
data.request_method required | string | Allowed values: GET, POST, PUT, PATCH, DELETE. |
data.frequency required | integer | Minutes between checks. A value below the plan's floor is refused. Allowed values: 1, 2, 5, 15. |
data.locations required | array<string> | Locations checks run from. Unordered. [] means every location. Allowed values: Virginia, Frankfurt, Singapore, London, Oregon. |
data.validate_ssl required | boolean | Whether to validate SSL certificates. |
data.request_headers required | object | Custom headers sent with check requests, as header name to value; {} when there are none. |
data.request_headers.* | string | Any other keys. |
data.request_body required | string | null | Request body for POST/PUT checks. |
data.outage_threshold required | integer | null | Number of failed checks before declaring an outage. |
data.timeout required | integer | null | The stored request timeout in seconds; null means the default, 30. On a plan without custom timeouts the default applies whatever is stored. |
data.created_at required | date-time | When the site was created. |
data.links required | object | Links into the Honeybadger web UI. |
data.links.web required | uri | The resource's page in the Honeybadger web UI, as an absolute URL. Resources without a page, such as outages and deploys, don't have links. For a project provisioned through Heroku, error, notice and comment links go through Heroku's single sign-on. |
meta | object | |
meta.request_id | string | Unique identifier for the request, for correlating with support. |
Errors
4
401
Unauthorized
The credential is missing, invalid, expired or revoked (unauthorized), or was sent in a way v3 doesn’t accept (see the examples).
Example payload: unauthorized (Missing, malformed, expired or revoked credential)
{ "error": { "code": "unauthorized", "message": "Access denied" }, "meta": { "request_id": "abc123" }}Example payload: unsupported_auth_scheme (Sent as HTTP basic, which v3 does not accept)
{ "error": { "code": "unsupported_auth_scheme", "message": "Send the credential as `Authorization: Bearer <token>`; v3 does not accept HTTP basic" }, "meta": { "request_id": "abc123" }}Example payload: credential_in_query (Sent as the `auth_token` query parameter)
{ "error": { "code": "credential_in_query", "message": "Credentials must be sent in the Authorization header" }, "meta": { "request_id": "abc123" }}Response schema6
| Field | Type | Description |
|---|---|---|
error required | object | |
error.code required | string | Machine-readable code. Branch on this, not the message. Allowed values: unauthorized, unsupported_auth_scheme, credential_in_query, access_denied, insufficient_scope, requires_user_token, project_restricted, account_inactive, account_parked, feature_unavailable, not_found, validation_error, delete_failed, limit_reached, rate_limit_exceeded, concurrent_request, streams_provisioning, ingestion_key_not_accepted, maintenance_mode, invalid_parameter, forbidden_attributes, service_unavailable, ambiguous_account, fault_merged. |
error.message required | string | Human-readable explanation. |
error.details | array<object> | object | A list of {field, message} on validation_error and invalid_parameter, and on feature_unavailable or limit_reached when one field caused the refusal; {required_scope, token_scopes} on insufficient_scope; {merged_into, location} on fault_merged. Absent when there's nothing to add. |
meta | object | |
meta.request_id | string | Unique identifier for the request, for correlating with support. |
403
Forbidden
The credential isn’t allowed to do this. error.code says why. An account or project the credential doesn’t cover is 404 not_found, not 403.
Example payload: access_denied (The credential isn't allowed to do this to this record)
{ "error": { "code": "access_denied", "message": "Access denied" }, "meta": { "request_id": "abc123" }}Example payload: insufficient_scope (The credential lacks the permission this endpoint requires)
{ "error": { "code": "insufficient_scope", "message": "Insufficient scope", "details": { "required_scope": "faults:write", "token_scopes": [ "faults:read", "insights:read" ] } }, "meta": { "request_id": "abc123" }}Example payload: requires_user_token (The endpoint records who acted, and an account token has nobody)
{ "error": { "code": "requires_user_token", "message": "This endpoint records the person who acted, so it requires a user credential rather than an account token" }, "meta": { "request_id": "abc123" }}Example payload: project_restricted (A project-restricted credential cannot create a project)
{ "error": { "code": "project_restricted", "message": "Project-restricted tokens cannot create projects" }, "meta": { "request_id": "abc123" }}Response schema6
| Field | Type | Description |
|---|---|---|
error required | object | |
error.code required | string | Machine-readable code. Branch on this, not the message. Allowed values: unauthorized, unsupported_auth_scheme, credential_in_query, access_denied, insufficient_scope, requires_user_token, project_restricted, account_inactive, account_parked, feature_unavailable, not_found, validation_error, delete_failed, limit_reached, rate_limit_exceeded, concurrent_request, streams_provisioning, ingestion_key_not_accepted, maintenance_mode, invalid_parameter, forbidden_attributes, service_unavailable, ambiguous_account, fault_merged. |
error.message required | string | Human-readable explanation. |
error.details | array<object> | object | A list of {field, message} on validation_error and invalid_parameter, and on feature_unavailable or limit_reached when one field caused the refusal; {required_scope, token_scopes} on insufficient_scope; {merged_into, location} on fault_merged. Absent when there's nothing to add. |
meta | object | |
meta.request_id | string | Unique identifier for the request, for correlating with support. |
404
Not Found
Resource not found
Example payload
{ "error": { "code": "not_found", "message": "Resource not found" }, "meta": { "request_id": "abc123" }}Response schema6
| Field | Type | Description |
|---|---|---|
error required | object | |
error.code required | string | Machine-readable code. Branch on this, not the message. Allowed values: unauthorized, unsupported_auth_scheme, credential_in_query, access_denied, insufficient_scope, requires_user_token, project_restricted, account_inactive, account_parked, feature_unavailable, not_found, validation_error, delete_failed, limit_reached, rate_limit_exceeded, concurrent_request, streams_provisioning, ingestion_key_not_accepted, maintenance_mode, invalid_parameter, forbidden_attributes, service_unavailable, ambiguous_account, fault_merged. |
error.message required | string | Human-readable explanation. |
error.details | array<object> | object | A list of {field, message} on validation_error and invalid_parameter, and on feature_unavailable or limit_reached when one field caused the refusal; {required_scope, token_scopes} on insufficient_scope; {merged_into, location} on fault_merged. Absent when there's nothing to add. |
meta | object | |
meta.request_id | string | Unique identifier for the request, for correlating with support. |
422
Unprocessable Content
Validation error
Example payload
{ "error": { "code": "validation_error", "message": "Name can't be blank", "details": [ { "field": "name", "message": "can't be blank" } ] }, "meta": { "request_id": "abc123" }}Response schema6
| Field | Type | Description |
|---|---|---|
error required | object | |
error.code required | string | Machine-readable code. Branch on this, not the message. Allowed values: unauthorized, unsupported_auth_scheme, credential_in_query, access_denied, insufficient_scope, requires_user_token, project_restricted, account_inactive, account_parked, feature_unavailable, not_found, validation_error, delete_failed, limit_reached, rate_limit_exceeded, concurrent_request, streams_provisioning, ingestion_key_not_accepted, maintenance_mode, invalid_parameter, forbidden_attributes, service_unavailable, ambiguous_account, fault_merged. |
error.message required | string | Human-readable explanation. |
error.details | array<object> | object | A list of {field, message} on validation_error and invalid_parameter, and on feature_unavailable or limit_reached when one field caused the refusal; {required_scope, token_scopes} on insufficient_scope; {merged_into, location} on fault_merged. Absent when there's nothing to add. |
meta | object | |
meta.request_id | string | Unique identifier for the request, for correlating with support. |