---
title: Replace the project's check-ins
description: Replaces the project's check-ins with the ones supplied.
url: https://docs.honeybadger.io/api/v3/check-ins/replace-check-ins/
---

API v3 is in preview

Endpoints and response shapes [can change before general availability](https://docs.honeybadger.io/api/v3/#preview). API v2 is unchanged.

PUT `https://app.honeybadger.io/v3/projects/{project_id}/check_ins/bulk_update`

[Required scope](https://docs.honeybadger.io/api/v3/authentication/#scopes) `checkins:write`

Replaces the project’s check-ins with the ones supplied. Each is matched to an existing check-in by `slug`: a matching check-in is updated, a new slug creates one, and any existing check-in that isn’t supplied is deleted. The response lists what happened to each slug.

If any create, update or delete fails, nothing changes, and `error.details` has an entry for each failed slug (field `check_ins.<slug>`). A cron entry needs cron on the plan.

Example request

```sh
curl -X PUT "https://app.honeybadger.io/v3/projects/$PROJECT_ID/check_ins/bulk_update" \
  -H "Authorization: Bearer $HONEYBADGER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "check_ins": [
    {
      "name": "Nightly billing job",
      "slug": "nightly-billing",
      "schedule_type": "simple",
      "report_period": "1 day",
      "grace_period": "15 minutes"
    }
  ]
}'
```

## Parameters

### Path parameters

| Field | Type | Description |
| - | - | - |
| `project_id` required | string | Project ID. |

## Request body

The project’s complete set of check-ins. Any check-in the project has that this list doesn’t name is deleted. Must be non-empty, and every entry needs a slug.

| Field | Type | Description |
| - | - | - |
| `check_ins` required | array\<object> | |
| `check_ins[].name` | string \| null | Display name. Null clears it; an unnamed check-in shows its ID. |
| `check_ins[].slug` required | string | Identifies which check-in an entry refers to, so it is required here. |
| `check_ins[].schedule_type` | string | Switching to `simple` clears `cron_schedule` and resets `cron_timezone` to `UTC`; switching to `cron` clears `report_period`. |
| `check_ins[].report_period` | string \| null | How often a report is expected, for `simple` schedules. Required unless `schedule_type` is `cron`, and may not be zero. A duration such as `5 minutes`, `1 hour 30 minutes` or `01:30:00`. Returned in long form: `1 week` comes back as `7 days`. |
| `check_ins[].grace_period` | string \| null | How long after the expected time before the check-in is considered missing. Same format as `report_period`; zero is `00:00:00`. Null resets it to zero. Default: `"00:00:00"`. |
| `check_ins[].cron_schedule` | string \| null | Cron expression, required when `schedule_type` is `cron`. |
| `check_ins[].cron_timezone` | string \| null | Timezone the cron schedule is evaluated in. A time zone name as the web app lists them, not an IANA identifier — `Central Time (US & Canada)`, not `America/Chicago`, which is rejected. Required when `schedule_type` is `cron`. Null resets it to `UTC`. Default: `"UTC"`. |

## Responses

### 200 Success

Example payload

```json
{
  "data": [
    {
      "operation": "create",
      "slug": "nightly-backup",
      "success": true
    }
  ],
  "meta": {
    "request_id": "6f1c2b0e-8d4a-4f6e-9b2a-3c5d7e9f1a2b"
  }
}
```

Response schema

| Field | Type | Description |
| - | - | - |
| `data` required | array\<object> | |
| `data[].operation` required | string | Allowed values: `create`, `update`, `delete`. |
| `data[].slug` required | string | |
| `data[].success` required | boolean | Always true; any failure makes the whole request a 422 and changes nothing. Allowed value: `true`. |
| `meta` | object | |
| `meta.request_id` | string | Unique identifier for the request, for correlating with support. |

## Errors

### 400 Bad Request

A query parameter is malformed or outside its allowed values. `error.details` names the parameter.

Example payload

```json
{
  "error": {
    "code": "invalid_parameter",
    "message": "unmapped must be true or false",
    "details": [
      {
        "field": "unmapped",
        "message": "must be true or false"
      }
    ]
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| 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. |

### 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)

```json
{
  "error": {
    "code": "unauthorized",
    "message": "Access denied"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Example payload: unsupported\_auth\_scheme (Sent as HTTP basic, which v3 does not accept)

```json
{
  "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)

```json
{
  "error": {
    "code": "credential_in_query",
    "message": "Credentials must be sent in the Authorization header"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| 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)

```json
{
  "error": {
    "code": "access_denied",
    "message": "Access denied"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Example payload: insufficient\_scope (The credential lacks the permission this endpoint requires)

```json
{
  "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)

```json
{
  "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)

```json
{
  "error": {
    "code": "project_restricted",
    "message": "Project-restricted tokens cannot create projects"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| 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

```json
{
  "error": {
    "code": "not_found",
    "message": "Resource not found"
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| 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

```json
{
  "error": {
    "code": "validation_error",
    "message": "Name can't be blank",
    "details": [
      {
        "field": "name",
        "message": "can't be blank"
      }
    ]
  },
  "meta": {
    "request_id": "abc123"
  }
}
```

Response schema

| 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. |

---

## Try Honeybadger for FREE

Intelligent logging, error tracking, and Just Enough APM™ in one dev-friendly platform. Find and fix problems before users notice.

[Start free trial](https://app.honeybadger.io/users/sign_up)

[See plans and pricing](https://www.honeybadger.io/plans/)
