---
id: custom-fields
title: 'Custom Fields'
description: 'api/customFields — the custom fields visible for a given asset. A POST endpoint despite reading nothing but metadata.'
sidebar_label: 'Custom Fields'
sidebar_position: 3
tags: ['api', 'fields', 'custom-fields', 'visibility']
---

Returns the **custom** fields visible for one asset — the subset of
[visible fields](/apis/field-visibility/visible-fields) that an administrator added, rather than
those Agility ships with.

```http
POST ~/api/customFields?oidToken=Story:1234
Content-Length: 0
```

| Parameter | Where | Description |
| --- | --- | --- |
| `oidToken` | query string | OID token of the asset to report on |

No request body is required, but a `Content-Length` header is — see below.

## Response

```json
[{ "name": "Custom_BusinessUnit" }, { "name": "Custom_RiskTier" }]
```

An array of objects each carrying a single lowercase `name`, rather than an array of bare strings. That
differs from [`api/visibleFieldsByAsset`](/apis/field-visibility/visible-fields#by-asset), which
returns bare strings for the equivalent question over all fields.

:::danger This is a `POST`. A `GET` returns 405

Everything about this endpoint suggests `GET`: it reads metadata, changes nothing, takes its
only parameter in the query string, and sits directly beside two `GET` siblings. It is
nonetheless `POST`-only.

| Method | Result |
| --- | --- |
| `GET` | **405 Method Not Allowed** |
| `POST` | Reaches the authorization check |
| `PUT`, `DELETE` | 405 |

The cause is a routing convention, not a design decision. ASP.NET Web API infers the accepted
verb from the action-method name; the two siblings are declared with an explicit `[HttpGet]`
attribute, while this action is named `Index` — which matches no `Get*` or `Post*` prefix and
therefore falls through to `POST`.

Because there is no request body, IIS may answer **411 Length Required** before the request
reaches the application. Send `Content-Length: 0` explicitly if your client does not.

`GET api/customFields` returns 405 while `GET api/visibleFieldsByAsset`
returns 401 — the difference is the verb, not the route or the authorization
gate.

:::

## Filtering

A field is returned when it is a custom column, is visible in the asset's context, and its term
is itself visible. Results are de-duplicated by term.

The asset's Scope is resolved server-side and used as the visibility context, so two assets of
the same type in different projects can legitimately return different custom fields.


## Related

- [Visible fields](/apis/field-visibility/visible-fields) — all displayable fields, not just custom ones
- [Field visibility overview](/apis/field-visibility)
