---
title: "Retire a custom field definition, keeping the values already written"
method: DELETE
path: "/v1/custom-fields/{id}"
tags: ["custom-fields"]
---

# Retire a custom field definition, keeping the values already written

`DELETE /v1/custom-fields/{id}`

## Request

- Base URL: `https://api.indraft.io`
- URL: `https://api.indraft.io/v1/custom-fields/{id}`
- Auth: HTTP bearer

Retire a custom field definition. Values already written stay readable and exportable, because a field somebody stopped using is history rather than a mistake. The field stops appearing in the schema, stops accepting new values, and frees its quota slot.

## Path parameters

- `id` string, required

## Response `200`

Success

- object
  - `archived` object, required
    - `id` string, required
    - `key` string, required
    - `archivedAt` string, required
  - `mutation` object, required
    - `mutationId` string, required
    - `status` 'created' | 'updated' | 'matched' | 'archived' | 'merged' | 'reverted' | 'noop', required: What the write did. `noop` means it was accepted and changed nothing, because every value it carried already matched what was stored. IT IS NOT METERED: a noop does not count against your monthly change allowance, so a nightly sync that finds nothing new costs nothing. Neither does a write that only REDUCES what a workspace holds. `matched` means an upsert found an existing record on real identity evidence rather than creating a second one; `reverted` and `merged` are the undo and duplicate paths, and both are ordinary writes that count.
    - `targetId` string
    - `record` unknown
    - `changes` object[]
      - `field` string, required
      - `before` unknown
      - `after` unknown
    - `held` object[]: Fields this write asked to change and did not, because the value standing in the record was asserted more strongly. THIS IS WHY A WRITE CAN RETURN 200 AND CHANGE NOTHING, and a caller that ignores it will believe it wrote something it did not. Precedence is confirmed > user_supplied > observed > imported > inferred, and a write carrying no `assertionKind` is weakest of all. Each entry reports the field, what the record still says, what you proposed, which claim won, and who made it. Send `overrideStanding` to write anyway, per write, when your claim really does supersede theirs.
      - `field` string, required
      - `kept` unknown
      - `proposed` unknown
      - `standing` 'observed' | 'inferred' | 'imported' | 'user_supplied' | 'confirmed', required
      - `incoming` 'observed' | 'inferred' | 'imported' | 'user_supplied' | 'confirmed', required
      - `actorId` string, required
      - `assertedAt` string, required
    - `matchedBy` 'email' | 'domain' | 'external_id' | 'idempotency_key' | 'explicit_id'
    - `reversible` boolean, required
    - `replayed` boolean
    - `dryRun` boolean
  - `requestId` string, required

## Other responses

- `401`: No credential, or one that has been revoked.
- `402`: A product quota is spent, or the subscription is not active.
- `403`: Authenticated, and this capability is not held.
- `404`: No such record, or it belongs to another workspace.
- `409`: A conflict the caller can resolve: a stale expectedVersion, an idempotency key reused for different input, an ambiguous or duplicate identity, or a merge that no longer applies.
- `429`: Infrastructure protection tripped. This is not a product quota.
- `500`: A defect on our side. The hint says so, and carries an incident id.
- `507`: The workspace is at its storage ceiling.

---

[API](https://skmtc.dev/indraft/apis/indraft-api.md) · [All operations](https://skmtc.dev/indraft/apis/indraft-api/llms.txt) · [OpenAPI document](https://skmtc.dev/indraft/apis/indraft-api/revisions/d9bb05346d66?raw)
