# Creating project-bound saved resources

> Project selection, ownership checks, and retry behavior for custom dashboards and feature flags.

Canonical page: https://anectico.com/docs/reference/project-bound-creation/


Custom dashboards and feature flags belong to a project, not just an organization.
A project ID must identify an existing, active project in the authenticated
organization. A correctly formatted UUID alone is not enough.

This applies to creating custom dashboards, cloning custom dashboards, and creating feature
flags. A clone keeps its source dashboard's project and checks that project again.

Feature flag creation (`POST /api/v1/flags`, MCP `create_flag`, and CLI
`flags create`) requires a project ID in its standard lower-case, hyphenated UUID
form. Organization-wide credentials must supply `project_id` in the creation
body. With a project-bound credential, its signed project is used even when
the body omits `project_id` or names another value. That signed project is checked
again for ownership and activation on every create. Creation requires
`flags:write`; it does not additionally require `projects:read`. A rejected create
stores no flag. A successfully created active flag is available to the same
project's flag list, lookup, and evaluation.

## Project selection and permissions

Organization-wide credentials must explicitly select a project when creating a
dashboard. Dashboard creation requires `project_id` explicitly, and it must match
a project-bound credential. Conflicting project selections are rejected.
With a project-bound credential, repeat the exact signed project value; another UUID
spelling still counts as a conflicting selection. Accepted organization-wide UUIDs
are stored in their standard lower-case, hyphenated form, and equivalent UUID
spellings use the same project identity for an idempotent retry.
See the [REST API reference](/docs/reference/rest-api) for the route-specific
selection and error contracts.

Dashboard creation and copying still require `dashboard:write` and an
authenticated owning user. They do not additionally require
`projects:read`. Existing owner, visibility, version, and idempotency rules still
apply. Cloning saved-insight widgets also retains those widgets' existing access
checks.

For API keys, the REST and MCP dashboard-clone routes require a key bound to the
source dashboard's project; those routes refuse organization-wide API keys. The
organization-wide project selection described above applies to dashboard creation.

## Rejections and retries

An unknown project, a deleted project, an inactive project, and a project owned by
another organization produce the same project-not-found response: HTTP `404`.
The response does not reveal which of those conditions applies, and no saved
resource is created by the rejected request.

When current project ownership cannot be verified because a dependency is
unavailable, creation fails rather than accepting an unchecked project. An outage
normally returns HTTP `503`; a deadline returns `504`. Missing service configuration
returns HTTP `400` and needs an operator correction, not a different
project ID. These are not successful creations.

An idempotency key does not bypass project validation. Every retry checks the
project's current state before it can create or replay a result. A project that
became inactive or was deleted after an earlier request is not accepted merely
because that earlier request succeeded.

These checks do not change the existing read, update, or delete permissions for
saved resources. They do not move, relabel, or automatically delete older records
that were created with an invalid project binding.

MCP project arguments follow the same rule for required-project reads and writes: a bound
credential supplies its project, including `instrumentation_doctor`, and an organization
credential supplies an explicit argument. Discovery marks the argument optional so bound
credentials can omit it. A contradictory project is refused before the operation.
