> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kayanos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Serial and form-number expressions

> Build deterministic entity serial IDs and form reference numbers with the exact roots, helpers, and date tokens available in each context.

## Use numbering expressions for identity, not policy

Serial and form-number expressions format a number that has already been allocated by KayanOS. They are appropriate for readable references such as `CSR-2026-00042`; they are not a replacement for a status, permission, approval, or audit decision.

The two reserved helpers are documented in [Serial and form-number helpers](/reference/expressions/helpers/serial). Do not assume either helper is available in a regular calculated field.

![KayanOS Serial ID field configuration for the Citizen Service Request, showing namespace, format, and sequence settings.](https://kayanos.app/docs-images/en/reference/expressions-serial-and-numbering.png)

## Entity serial ID context

Namespace expressions receive:

| Root                                         | Meaning                                        |
| -------------------------------------------- | ---------------------------------------------- |
| `$`, `$record`                               | Record data being assigned a serial ID.        |
| `$organizationId`, `$entityKey`, `$fieldKey` | Stable scope identifiers.                      |
| `$timezone`                                  | `UTC` or the configured organization timezone. |
| `$now`                                       | Allocation-time Date value.                    |

Format expressions add `$namespace` and `$sequence`; `$sequence` is a string. A namespace determines which sequence is incremented, while a format determines how the allocated sequence is displayed.

```jexl theme={null}
// namespace
$organizationId + ":" + $entityKey + ":" + $fieldKey

// format
"CSR-" + serialDate("yyyy", $now, $timezone) + "-" + serialPad($sequence, 5)
```

## Form-numbering context

Form numbering uses a different root model. It provides `$`, `$record`, `$savedState`, `$variables`, `$fields`, `$organizationId`, `$formId`, `$formVersionId`, `$sessionId`, `$codePrefix`, `$profile`, `$status`, `$initiatorId`, `$initiatorType`, `$publicUserId`, `$preview`, `$timezone`, and `$now`. Format expressions add `$namespace` and `$sequence`.

```jexl theme={null}
$codePrefix + "-" + serialDate("yyyy", $now, $timezone) + "-" + serialPad($sequence, 4)
```

Do not copy an entity serial expression into form numbering without changing its roots. For example, form numbering has `$formId`; an entity serial has `$entityKey` and `$fieldKey`.

## The two helpers

```jexl theme={null}
serialPad($sequence, 5)             // 00042
serialPad($sequence, 5, "X")        // XXX42
serialDate("yyyy-MM", $now, $timezone)
```

`serialDate` understands only `yyyy`, `yy`, `MM`, and `dd`. It is intentionally different from general `dateFormat`, which uses uppercase `YYYY`, `DD`, and other tokens. An invalid date returns an empty string, so test the final rendered reference rather than only the individual helper.

## Deterministic design rules

* Keep namespaces stable. Changing a namespace changes the sequence stream.
* Use `$sequence`, `$namespace`, stable scope keys, and the configured clock. Do not use `random`, `shuffle`, `sample`, or a record field that can change after allocation.
* Use a readable, bounded format. Long display values are harder to use on forms, printed acknowledgements, and support calls.
* Test the first value, a value after padding width, a year boundary, and any allowed manual/request mode.
* Treat a rendered serial as a traceable reference; do not modify it merely to make a screen look nicer.

## Common patterns

| Need                              | Example                                                                        |
| --------------------------------- | ------------------------------------------------------------------------------ |
| One sequence per entity field     | `$organizationId + ":" + $entityKey + ":" + $fieldKey`                         |
| One sequence per service category | `$organizationId + ":" + $.service_category`                                   |
| Year-prefixed citizen request     | `"CSR-" + serialDate("yyyy", $now, $timezone) + "-" + serialPad($sequence, 5)` |
| Short printed form reference      | `$codePrefix + "-" + serialPad($sequence, 4)`                                  |

Use the category pattern only when service policy explicitly accepts a separate sequence per stored category value. A renamed label is not a stable category value.

## Troubleshooting

| Symptom                                | Check                                                                                     |
| -------------------------------------- | ----------------------------------------------------------------------------------------- |
| Empty serial format                    | Does every branch return text, and does `serialDate` receive a valid date?                |
| Unexpected sequence reset              | Did the namespace expression change or include a changing field?                          |
| Wrong year/month                       | Is `$timezone` set as intended, and are serial tokens lowercase `yyyy`/`dd`?              |
| Helper not found in a calculated field | It is reserved for serial/form-number contexts; use general helpers only where supported. |

## Related guides

* [Serial IDs](/build/serial-ids)
* [Expression contexts and availability](/reference/expressions/contexts)
* [Date and time helpers](/reference/expressions/helpers/date)
