---
title: Create a project
description: Creates a new project in the account.
url: https://docs.honeybadger.io/api/v3/projects/create-project/
---

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.

POST `https://app.honeybadger.io/v3/projects`

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

Creates a new project in the account.

Example request

```sh
curl -X POST "https://app.honeybadger.io/v3/projects" \
  -H "Authorization: Bearer $HONEYBADGER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Billing API"
}'
```

## Request body

| Field | Type | Description |
| - | - | - |
| `name` required | string | Project name. |
| `resolve_errors_on_deploy` | boolean \| null | Resolve every open fault when a deploy is recorded. Null resets it to true. Default: `true`. |
| `disable_public_links` | boolean \| null | Disallow shareable public fault links. Null resets it to false. Default: `false`. |
| `language` | string \| null | Primary language, used to format backtraces. Null clears it. |
| `user_url` | string \| null | Template for linking a fault's affected user into your own system. `[user_id]` and `[user_email]` are substituted. Null clears it. |
| `source_url` | string \| null | Template for linking a backtrace line to your source host. `[file]` and `[line]` are substituted. Null clears it. |
| `user_search_field` | string \| null | Context key identifying the affected user, for when it is not in the default `context.user_email` or `context.user_id`. Null clears it. |
| `asana_workspace_id` | string \| null | Asana workspace used by the project's Asana integration. Null clears it. |
| `customer_throttle` | integer \| null | Notices accepted per minute before throttling kicks in. Null clears it. |
| `purge_days` | integer \| null | Days to retain notices. Changing it requires custom retention on the account; without it, only the current value (on create, the default) is accepted. Null clears it. |
| `disable_email_notifications` | boolean | Create-only. Members added with the project get email notifications switched off. Not stored or returned. |
| `team_id` | string | Puts the new project in this team. Create-only: afterwards the team's `project_ids` owns membership. Including it requires `team:write` in addition to the operation's project scope, and the user must be allowed to manage the team. Without `team:write` the entire request is rejected with 403 `insufficient_scope`; no other fields are saved. |

## Responses

### 201 Project created

Example payload

```json
{
  "data": {
    "id": "Xk9mZp",
    "account_id": "Ab3kL9",
    "name": "My Rails App",
    "active": true,
    "disable_public_links": true,
    "environments": [
      "production",
      "staging",
      "development"
    ],
    "resolve_errors_on_deploy": true,
    "user_url": "https://admin.example.com/users/[user_id]",
    "source_url": "https://github.com/acme/app/blob/main/[file]#L[line]",
    "user_search_field": "context.account_id",
    "asana_workspace_id": null,
    "customer_throttle": 0,
    "language": "Ruby",
    "fault_count": 128,
    "unresolved_fault_count": 12,
    "last_notice_at": "2026-01-01T00:00:00Z",
    "earliest_notice_at": "2026-01-01T00:00:00Z",
    "purge_days": 90,
    "created_at": "2026-01-01T00:00:00Z",
    "links": {
      "web": "https://app.honeybadger.io/projects/Xk9mZp"
    }
  },
  "meta": {
    "request_id": "6f1c2b0e-8d4a-4f6e-9b2a-3c5d7e9f1a2b"
  }
}
```

Response schema

| Field | Type | Description |
| - | - | - |
| `data` required | object | A Honeybadger project: one application or service. Errors, Insights data, uptime sites, check-ins, deploys and integrations all belong to a project. |
| `data.id` required | string | |
| `data.account_id` required | string | ID of the account this project belongs to. |
| `data.name` required | string | Project name. |
| `data.active` required | boolean | Whether the project is active. |
| `data.disable_public_links` required | boolean | Whether public error links are disabled. |
| `data.environments` required | array\<string> | List of environment names seen in this project. |
| `data.resolve_errors_on_deploy` required | boolean | Whether recording a deploy resolves every open fault. |
| `data.user_url` required | string \| null | Template linking a fault's affected user into your own system. `[user_id]` and `[user_email]` are substituted. |
| `data.source_url` required | string \| null | Template linking a backtrace line to your source host. `[file]` and `[line]` are substituted. |
| `data.user_search_field` required | string \| null | Context key identifying the affected user, when it is not in the default `context.user_email` or `context.user_id`. |
| `data.asana_workspace_id` required | string \| null | Asana workspace used by the project's Asana integration. |
| `data.customer_throttle` required | integer \| null | Notices accepted per minute before throttling kicks in. |
| `data.language` required | string \| null | Primary programming language. |
| `data.fault_count` required | integer | Total number of faults (errors) in this project. |
| `data.unresolved_fault_count` required | integer | Number of unresolved faults. |
| `data.last_notice_at` required | date-time \| null | When the last error was received. |
| `data.earliest_notice_at` required | date-time \| null | The start of the retention window: now minus the project's `purge_days` (or the account's retention when unset), at most 180 days. Computed on each read, so it moves forward with the clock. |
| `data.purge_days` required | integer \| null | Data retention period in days. |
| `data.created_at` required | date-time | When the project 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

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

### 429 Too Many Requests

Another project is being created in this account at the same moment (`concurrent_request`), or the rate limit is exceeded (`rate_limit_exceeded`). Nothing was created. Wait `Retry-After` seconds and retry.

Example payload

```json
{
  "error": {
    "code": "concurrent_request",
    "message": "Another project is being created in this account; retry shortly"
  },
  "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/)
