← Back to Blog

Using the Jira Cloud REST API to Audit Custom Fields

By David Day  ·   ·  12 min read
Key Takeaways
  • The field endpoint returns every field with its ID and schema, which is the raw material for a full audit without scrolling the admin UI.
  • Filtering names for "(migrated)" gives you the duplicate list, and a JQL count per field ID tells you which pairs actually hold data.
  • Field context calls show where each field is used, so you know whether deleting a duplicate is safe or still wired into a project.

The field list in the admin UI scrolls for a full minute and still will not tell you which fields hold data. The REST API will, in one call and a short loop, and that difference is what turns a messy cleanup into a plan.

This guide covers the endpoints that matter for auditing custom fields in Cloud, what the responses look like, and a repeatable script an admin can run before touching anything. All examples use API token authentication with basic auth.

Start With the Field Endpoint

One call returns every field on the site, system and custom, with an ID, a name and a schema block. Nothing else is this complete for the purpose of an audit.

curl -s -u you@example.com:$API_TOKEN \
  -H "Accept: application/json" \
  "https://your-domain.atlassian.net/rest/api/3/field"

The response is a JSON array. Each custom field entry looks like this.

{
  "id": "customfield_10112",
  "key": "customfield_10112",
  "name": "Severity (migrated)",
  "custom": true,
  "schema": {
    "type": "option",
    "custom": "com.atlassian.jira.plugin.system.customfieldtypes:select"
  }
}

Two things carry the audit. The name tells you what the field is called and reveals the "(migrated)" tag. The schema tells you the type, which is the field property that decides whether a merge is safe, as covered in the custom field types reference.

Find the Migrated Duplicates

Pipe the response through jq and filter names that contain the migrated marker. This returns the exact list of duplicate fields, one ID per line.

curl -s -u you@example.com:$API_TOKEN \
  -H "Accept: application/json" \
  "https://your-domain.atlassian.net/rest/api/3/field" \
  | jq -r '.[] | select(.name | contains("(migrated)")) | "\(.id)\t\(.name)"'

Each line gives you an ID and a label, which is all you need to work in batches. A field tagged "(migrated 2)" shows up the same way, so the filter catches repeat runs too. For the mechanics of how those duplicates form, see why JCMA creates duplicate fields.

Count Issues per Field Before You Merge

An ID with no data is a fast win, an ID with thousands of issues needs care. The search endpoint returns a total when you ask for zero results, so a tiny loop gives you a data map of the whole migration.

for id in $(curl -s -u you@example.com:$API_TOKEN \
  -H "Accept: application/json" \
  "https://your-domain.atlassian.net/rest/api/3/field" \
  | jq -r '.[] | select(.name | contains("(migrated)")) | .id'); do
  num=${id#customfield_}
  total=$(curl -s -u you@example.com:$API_TOKEN \
    -G "https://your-domain.atlassian.net/rest/api/3/search" \
    --data-urlencode "jql=cf[${num}] is not EMPTY" \
    --data-urlencode "maxResults=0" | jq '.total')
  echo "$id holds $total issues"
done

Run the same count against the original field in each pair. If the original already holds data everywhere, the migrated copy may be deletable after a check. If the original is empty, that is the pair where a value copy is safe, which is exactly the rule a good merge tool follows.

Check Where a Field Is Used

Deleting a field is only safe once it is off every screen and configuration. The context endpoint lists the contexts a field lives in, which tells you whether it is global or scoped to specific projects.

curl -s -u you@example.com:$API_TOKEN \
  -H "Accept: application/json" \
  "https://your-domain.atlassian.net/rest/api/3/field/customfield_10112/context"

A field with a single global context behaves differently from one with several project scoped contexts. Note the context IDs and the projects they apply to before you plan the deletion, then match them against the project level audit in the project settings guide.

A Repeatable Audit, Step by Step

  1. Generate an API token and confirm the account has Administer Jira at site level.
  2. Call the field endpoint and save the JSON to a file so you are not hammering the API.
  3. Filter names containing "(migrated)" to build the duplicate list.
  4. Loop the search count for each duplicate and its original, and record both totals.
  5. Fetch contexts for every duplicate to see which projects still use it.
  6. Merge the empty-original pairs first, then remove the duplicate from screens and configurations before deleting.

Do this once and you have a table the whole cleanup can run from. Skip it and you are guessing in the UI, which is how single fields get deleted with live data still inside them.

Resources

The API gives you the numbers, Migration Helper acts on them. It scans for "(migrated)" fields, matches each to its original, compares the schema, and merges in one click, filling the original only when it is empty so Cloud native data is never overwritten. It runs entirely on Forge, and teams of 50 or fewer users can scan and merge free. Install Migration Helper from the Atlassian Marketplace.

Ready to clean up duplicate fields?

Install Free →