Form Availability
Registration opens Monday. The workshop seats forty. The survey closes at the end of the quarter. Each of those is a rule about when a form accepts answers, and each one otherwise becomes a calendar reminder to go and edit the config by hand.
availability states the rule once and lets the server enforce it:
forms:
- id: 1
name: workshop-signup
title: Spring Workshop
submitTo: { table: registrations }
availability:
opensAt: '2026-03-01T09:00:00Z'
closesAt: '2026-03-20T23:59:59Z'
maxSubmissions: 40
fields:
- { kind: table-field, column: email, required: true }Availability Properties
Every property is optional. Omit the block and the form is open, forever, with no cap.
| Property | Description | Default |
|---|---|---|
opensAt |
ISO 8601 timestamp at which the form starts accepting submissions. | Open immediately. |
closesAt |
ISO 8601 timestamp at which it stops. | Never closes. |
maxSubmissions |
Positive integer cap. The submission after the cap is refused. | Unlimited. |
closedPage |
Custom page shown while the form is closed, for any of the three reasons. | Title + boilerplate copy. |
When both timestamps are set, opensAt must be strictly before closesAt. A window that closes before it opens accepts nothing and is almost always a typo, so it fails when the config is decoded, naming the form and both timestamps.
What a Closed Form Answers
Opening a closed form is not an error — the visitor gets a page explaining the situation. Posting to one is refused with a structured body so a programmatic client can tell the three cases apart.
| State | GET /forms/{name} |
POST status |
Error body |
|---|---|---|---|
Before opensAt |
Closed page | 403 |
{ error: 'form not yet open', opensAt } |
After closesAt |
Closed page | 403 |
{ error: 'form closed', closedAt } |
At maxSubmissions |
Form still renders | 403 |
{ error: 'submission limit reached', maxSubmissions, currentCount } |
A refused submission writes nothing — no ledger row, no table row, no automation run.
The Closed Page
Left unconfigured, the closed page shows the form's own title and a sentence explaining that it is not yet open (quoting opensAt) or no longer accepting answers. closedPage replaces that with your own copy and, optionally, a way forward:
availability:
closesAt: '2026-03-20T23:59:59Z'
closedPage:
title: Registration has closed
message: Spring places are full. The autumn cohort opens in July.
cta:
label: Join the waiting list
href: /waiting-list| Property | Description | Default |
|---|---|---|
title |
Page heading. | The form's title. |
message |
Body copy. | Default explanation for the reason. |
cta.label |
Link text. Requires cta.href. |
No link. |
cta.href |
Link target. Requires cta.label. |
No link. |
type |
Reserved discriminator; only page is accepted. |
page |
The same page serves all three closed states, so write copy that reads sensibly whether the form has not opened yet or has filled up.
Only real submissions consume a cap slot. A submission rejected as spam — a tripped honeypot, a rate-limit miss — and one that failed downstream never count toward maxSubmissions. A bot cannot exhaust your forty workshop seats in a burst, and a failed write does not quietly cost a genuine registrant their place. The cap is also enforced atomically, so concurrent submissions racing for the last slots cannot overshoot it.
Related Pages
- Anti-Spam & Attribution — the spam classification that is excluded from the cap.
- Access Control — the other reason a form may refuse a submitter.
- Submissions — the ledger status a refused submission does not create.
- Forms Overview — where
availabilitysits in the full form schema.
Last updated September 1, 2026
This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.