# Tags and custom fields Tags and custom fields, which work across every module. **Common tasks** - [List tags](#get-organizations-organization-tags) - [Create a tag](#post-organizations-organization-tags) **Only in the app:** Nothing. Tags and custom fields can be managed with a token. **How it works in the app:** [help article](https://infranest.io/docs/tags). **Scopes:** Read with `monitoring.read`, change with `monitoring.write`. See [Tokens and scopes](../tokens-and-scopes.md#scopes).
[Custom field values](#custom-field-values) 2 · [Custom fields](#custom-fields) 4 · [Tags](#tags) 4
Every endpoint below takes a token in the `Authorization: Bearer` header and answers JSON. Errors use the shared format in [Errors](../errors.md). Base address: `https://api.infranest.io/api`. ## Custom field values ### List custom field values for a record {#get-organizations-organization-custom-field-values}
`GET` `/organizations/{organization}/custom-field-values` **Scope:** `monitoring.read` · **Changes data:** no The custom field values set on one record. `entity_type` and `entity_id` are required; returns 404 when the record is not in this organization. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `entity_type`
body · required | string | | | `entity_id`
body · required | integer | | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`not_found`](../errors.md#not_found), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl "https://api.infranest.io/api/organizations/42/custom-field-values?entity_type=%3Centity_type%3E&entity_id=16" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" ``` **Response** · 200 ```json [ { "id": 1, "custom_field_definition_id": 1, "value": "Platform" }, { "id": 2, "custom_field_definition_id": 2, "value": "Web platform" } ] ```
--- ### Set a custom field value {#put-organizations-organization-custom-field-values}
`PUT` `/organizations/{organization}/custom-field-values` **Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization Sets the `value` of one field (`definition_id`) on one record (`entity_type`, `entity_id`), checked against the field’s type and options. A null value clears it and returns 204. Requires a plan that includes custom fields. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `entity_type`
body · required | string | | | `entity_id`
body · required | integer | | | `definition_id`
body · required | integer | | | `value`
body | string | | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`validation_failed`](../errors.md#validation_failed), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl -X PUT "https://api.infranest.io/api/organizations/42/custom-field-values" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"entity_type":"server","entity_id":1,"definition_id":1,"value":"Platform"}' ``` **Response** · 200 ```json { "id": 1, "custom_field_definition_id": 1, "value": "Platform" } ```
## Custom fields ### List custom fields {#get-organizations-organization-custom-fields}
`GET` `/organizations/{organization}/custom-fields` **Scope:** `monitoring.read` · **Changes data:** no The organization’s custom field definitions in display order. Pass `entity_type` to list only the fields that apply to that kind of record. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `entity_type`
body | string | | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`not_found`](../errors.md#not_found), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl "https://api.infranest.io/api/organizations/42/custom-fields" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" ``` **Response** · 200 ```json [ { "id": 1, "organization_id": 1, "entity_types": [ "server", "domain" ], "key": "cost_centre", "label": "Cost centre", "type": "select", "options": [ "Platform", "Marketing" ], "required": false, "sort": 0, "show_on_detail": true, "show_as_column": true, "created_at": "2026-01-15T12:00:00.000000Z", "updated_at": "2026-01-15T12:00:00.000000Z", "deleted_at": null, "purge_after": null, "purge_reminder_sent_at": null, "deleted_by_id": null, "deleted_by_label": null, "deletion_reason": null }, { "id": 2, "organization_id": 1, "entity_types": [ "server" ], "key": "owner_team", "label": "Owning team", "type": "text", "options": null, "required": false, "sort": 1, "show_on_detail": true, "show_as_column": false, "created_at": "2026-01-15T12:00:00.000000Z", "updated_at": "2026-01-15T12:00:00.000000Z", "deleted_at": null, "purge_after": null, "purge_reminder_sent_at": null, "deleted_by_id": null, "deleted_by_label": null, "deletion_reason": null } ] ```
--- ### Create a custom field {#post-organizations-organization-custom-fields}
`POST` `/organizations/{organization}/custom-fields` **Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization Defines a custom field with `entity_types`, a unique `key`, a `label` and a `type`; select and multi-select fields also need `options`. Requires a plan that includes custom fields. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`idempotency_in_progress`](../errors.md#idempotency_in_progress), [`validation_failed`](../errors.md#validation_failed), [`idempotency_key_reused`](../errors.md#idempotency_key_reused), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl -X POST "https://api.infranest.io/api/organizations/42/custom-fields" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"entity_types":["server"],"key":"cost_center","label":"Cost center","type":"text"}' ``` **Response** · 201 — Created ```json { "entity_types": [ "server" ], "key": "cost_center", "label": "Cost center", "type": "text", "options": null, "required": false, "sort": 0, "show_on_detail": true, "show_as_column": false, "organization_id": 1, "updated_at": "2026-01-15T12:00:00.000000Z", "created_at": "2026-01-15T12:00:00.000000Z", "id": 4 } ```
--- ### Update a custom field {#patch-organizations-organization-custom-fields-customfielddefinition}
`PATCH` `/organizations/{organization}/custom-fields/{customFieldDefinition}` **Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization Replaces the field’s definition; send the full set of fields, as on create. Requires a plan that includes custom fields. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `customFieldDefinition_id`
path · required | integer | The customFieldDefinition's ID. | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`validation_failed`](../errors.md#validation_failed), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl -X PATCH "https://api.infranest.io/api/organizations/42/custom-fields/1" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"entity_types":["server","domain"],"key":"cost_centre","label":"Responsible team","type":"select","options":["Platform","Marketing","Data","Internal tools"]}' ``` **Response** · 200 ```json { "id": 1, "organization_id": 1, "entity_types": [ "server", "domain" ], "key": "cost_centre", "label": "Responsible team", "type": "select", "options": [ "Platform", "Marketing" ], "required": false, "sort": 0, "show_on_detail": true, "show_as_column": false, "created_at": "2026-01-15T12:00:00.000000Z", "updated_at": "2026-01-15T12:00:00.000000Z", "deleted_at": null, "purge_after": null, "purge_reminder_sent_at": null, "deleted_by_id": null, "deleted_by_label": null, "deletion_reason": null } ```
--- ### Delete a custom field {#delete-organizations-organization-custom-fields-customfielddefinition}
`DELETE` `/organizations/{organization}/custom-fields/{customFieldDefinition}` **Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization Deletes the field definition together with every value stored for it. Requires a plan that includes custom fields. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `customFieldDefinition_id`
path · required | integer | The customFieldDefinition's ID. | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl -X DELETE "https://api.infranest.io/api/organizations/42/custom-fields/1" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" ``` **Response** · 204 — no content
## Tags ### List tags {#get-organizations-organization-tags}
`GET` `/organizations/{organization}/tags` **Scope:** `monitoring.read` · **Changes data:** no Every tag in the organization, with its colour, whether it names a client, its uptime target and how many resources carry it (`usage_count`). | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`not_found`](../errors.md#not_found), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl "https://api.infranest.io/api/organizations/42/tags" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" ``` **Response** · 200 ```json [ { "id": 3, "organization_id": 1, "name": "Customer-facing", "color": "#3b82f6", "uptime_target_pct": null, "is_client": false, "created_at": "2026-01-15T12:00:00.000000Z", "usage_count": 12 }, { "id": 4, "organization_id": 1, "name": "Internal", "color": "#8b5cf6", "uptime_target_pct": null, "is_client": false, "created_at": "2026-01-15T12:00:00.000000Z", "usage_count": 11 } ] ```
--- ### Create a tag {#post-organizations-organization-tags}
`POST` `/organizations/{organization}/tags` **Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization Creates a tag from a `name` (up to 50 characters) and a hex `color` such as `#ff8800`; `is_client` is optional. Refused with 422 when a tag with that name already exists. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `name`
body · required | string | Must not be greater than 50 characters. | | `color`
body · required | string | Must match the regex /^#[0-9A-Fa-f]{6}$/. | | `is_client`
body | boolean | | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`idempotency_in_progress`](../errors.md#idempotency_in_progress), [`validation_failed`](../errors.md#validation_failed), [`idempotency_key_reused`](../errors.md#idempotency_key_reused), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl -X POST "https://api.infranest.io/api/organizations/42/tags" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"name":"Payments","color":"#3B82F6"}' ``` **Response** · 201 — Created ```json { "name": "Payments", "color": "#3B82F6", "organization_id": 1, "updated_at": "2026-01-15T12:00:00.000000Z", "created_at": "2026-01-15T12:00:00.000000Z", "id": 7 } ```
--- ### Update a tag {#patch-organizations-organization-tags-tag}
`PATCH` `/organizations/{organization}/tags/{tag}` **Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization Changes any of `name`, `color`, `is_client` and `uptime_target_pct` (0 to 100, or null to clear it). Refused with 422 when the new name is already taken. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `tag_id`
path · required | integer | The tag's ID. | | `name`
body | string | Must not be greater than 50 characters. | | `color`
body | string | Must match the regex /^#[0-9A-Fa-f]{6}$/. | | `uptime_target_pct`
body | number, nullable | The availability agreed with this client. Null clears it, and a cleared target is reported as "none agreed" rather than as 100%. Must be at least 0. Must not be greater than 100. | | `is_client`
body | boolean | This tag names a client: attention items on what it tags are grouped under it. | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`validation_failed`](../errors.md#validation_failed), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl -X PATCH "https://api.infranest.io/api/organizations/42/tags/1" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"color":"#22C55E","uptime_target_pct":99.9}' ``` **Response** · 200 ```json { "id": 1, "organization_id": 1, "name": "Production", "color": "#22C55E", "created_at": "2026-01-15T12:00:00.000000Z", "updated_at": "2026-01-15T12:00:00.000000Z", "deleted_at": null, "purge_after": null, "purge_reminder_sent_at": null, "deleted_by_id": null, "deleted_by_label": null, "deletion_reason": null, "uptime_target_pct": "99.900", "is_client": false } ```
--- ### Delete a tag {#delete-organizations-organization-tags-tag}
`DELETE` `/organizations/{organization}/tags/{tag}` **Scope:** `monitoring.write` · **Changes data:** yes — only where API writes are switched on for the organization Deletes the tag and removes it from every resource that carried it. The resources themselves are kept. | Field | Type | Notes | |---|---|---| | `organization_id`
path · required | integer | Your organization's ID. | | `tag_id`
path · required | integer | The tag's ID. | **Errors:** [`unauthenticated`](../errors.md#unauthenticated), [`scope_missing`](../errors.md#scope_missing), [`wrong_organization`](../errors.md#wrong_organization), [`test_token_required`](../errors.md#test_token_required), [`test_token_sandbox_only`](../errors.md#test_token_sandbox_only), [`permission_denied`](../errors.md#permission_denied), [`write_disabled`](../errors.md#write_disabled), [`organization_suspended`](../errors.md#organization_suspended), [`not_found`](../errors.md#not_found), [`rate_limited`](../errors.md#rate_limited)
**Request** ```sh curl -X DELETE "https://api.infranest.io/api/organizations/42/tags/1" \ -H "Authorization: Bearer $INFRANEST_TOKEN" \ -H "Accept: application/json" ``` **Response** · 204 — no content