# Field typing

> How every field type reads (value, formatted, blank) and writes, generated from the typing rule.

Source: https://developers.processcart.com/reference/field-typing

Every field type, with the JSON shape its `value` takes on read, how a blank reads, what a write accepts and whether `PATCH /v1/runs/{id}/fields` (or `fields` at `POST /v1/runs`) may write it. The table is generated from the same typing rule the API serializes and validates with; [Field values & typing](https://developers.processcart.com/guides/field-values) explains the rules around it.

| Field type | Format | `value` (read) | Blank | Write accepts | Example `value` → `formatted` | Writable |
| --- | --- | --- | --- | --- | --- | --- |
| `text` | `none` | string | null | a string; an empty or whitespace-only string clears | `"88 Birch Court"` → `"88 Birch Court"` | yes |
| `text` | `custom` | string matching the field's mask or pattern | null | a string the mask / pattern accepts | `"AB-1234"` → `"AB-1234"` | yes |
| `textarea` | — | string (multi-line) | null | a string; whitespace-only clears | `"Keys handed over at 3 pm."` → `"Keys handed over at 3 pm."` | yes |
| `number` | `number` | number | null | a JSON number (the canonical) or a string parsed by the format ("1,234.5" — a comma is always a thousands separator) | `1234.5` → `"1,234.5"` | yes |
| `number` | `currency` | number in whole currency units | null | a JSON number (the canonical) or a string parsed by the format ("$1,700.50" → 1700.5) | `1700.5` → `"$1,700.50"` | yes |
| `number` | `percent` | number — a FRACTION (0.125 means 12.5 %) | null | a JSON number (the canonical) or a string parsed by the format ("12.5%" → 0.125; a bare "12.5" follows the field's entry mode) | `0.125` → `"12.5%"` | yes |
| `date` | `date` | string, YYYY-MM-DD (no time zone) | null | a date string in any common form ("2026-06-25", "06/25/2026", "Jun 25 2026") | `"2026-06-25"` → `"Jun 25, 2026"` | yes |
| `time` | `time` | string, HH:mm (24-hour, no seconds, no time zone) | null | a time string ("14:30", "2:30 PM") | `"14:30"` → `"2:30 PM"` | yes |
| `dropdown` | — | string — one of the field's `choices` | null | one of `choices`, exactly | `"Yes"` → `"Yes"` | yes |
| `multi_choice` | — | string[] — labels from `choices`, in the field's order | null | an array of `choices` entries (an unknown entry is a 422, never dropped) | `["A","C"]` → `"A, C"` | yes |
| `checkbox` | — | boolean — never null; a never-set checkbox reads false | false | a boolean (false clears) | `true` → `"Yes"` | yes |
| `email` | `email` | string, lowercased | null | an email address | `"ada@example.com"` → `"ada@example.com"` | yes |
| `url` | `url` | string, normalized by the URL parser (a scheme is added) | null | an http(s) URL | `"https://processcart.com/"` → `"https://processcart.com/"` | yes |
| `phone` | `phone` | string, E.164 | null | a US phone number in any common form ("(555) 123-4567") | `"+15551234567"` → `"(555) 123-4567"` | yes |
| `members` | — | string[] of member user ids | null | an array of current member user ids (an unknown id is a 422) | `["11111111-1111-4111-8111-111111111111"]` → `"Ada Lovelace"` | yes |
| `subtasks` | — | string[] of checked item keys, in the field's order | null | an array of `items[].key` entries | `["photos"]` → `"1 of 2: Photos"` | yes |
| `file` | — | string[] of attachment ids | null | not writable here — upload through `POST /v1/runs/{id}/files` | `["22222222-2222-4222-8222-222222222222"]` → `"contract.pdf"` | no |
| `formula` | — | number \| string \| boolean \| null (engine output; dates as YYYY-MM-DD, date-times as YYYY-MM-DDTHH:mm:ss in the org's time zone) | null (also for a formula error) | not writable (computed) | `2400` → `"$2,400.00"` | no |
| `hidden` | — | whatever canonical shape was written (number \| string \| boolean \| string[]) | null | any canonical value — writable through the API when the field carries no formula (not shown in the app, not secret) | `"zapier"` → `"zapier"` | yes |
| `display_text` | — | — (never appears in `fields[]`; it carries no value) | — | not writable | — | no |

The effective **format** decides the shape first: a `text` field carrying a currency format reads and writes as a number, exactly like a `number` field would. `GET /v1/workflows/{id}/schema` applies the same rule per field and emits JSON Schema with `x-processcart-type` / `x-processcart-format`.
