---
title: "Forms"
description: "`forms.list`, `get`, `create`, `update`, `delete`, `publish`, `pause`, `resume`, `duplicate`, `analytics`, `list_starters`, `get_starter`, `list_submissions`, `get_submission`, `delete_submission`, `delete_submissions`, `approve_submission`, `resend_confirmation` and `subscribe`."
url: "https://openemail.uk/docs/python/forms"
area: "Python"
category: "Mailbox"
---

# Forms

`forms.list`, `get`, `create`, `update`, `delete`, `publish`, `pause`, `resume`, `duplicate`, `analytics`, `list_starters`, `get_starter`, `list_submissions`, `get_submission`, `delete_submission`, `delete_submissions`, `approve_submission`, `resend_confirmation` and `subscribe`.

## Every method

**forms.py**

```
from openemail import openemail

form = openemail.forms.create({
    'name': 'Newsletter sign-up',
    'starter': 'newsletter',
    'settings': {'audienceIds': ['aud_4c1b8e2a7d9f05c36b4e8a71']},
    'publish': True,
})

print(form['url'], form['subscribeUrl'])

saved = openemail.forms.update(form['id'], {
    'settings': {'doubleOptIn': True, 'senderAddress': 'news@acme.com'},
    'expectedUpdatedAt': form['updatedAt'],
})

signup = openemail.forms.subscribe(form['id'], {
    'email': 'ann@example.com',
    'first_name': 'Ann',
    'consent': True,
})

for submission in openemail.forms.iterate_submissions(form['id'], status='pending'):
    if submission['expired']:
        openemail.forms.resend_confirmation(form['id'], submission['id'])

stats = openemail.forms.analytics(form['id'], days=30)
starters = openemail.forms.list_starters()

openemail.forms.pause(form['id'])
openemail.forms.resume(form['id'])
copy = openemail.forms.duplicate(form['id'])
openemail.forms.delete(copy['id'])

print(saved['senderIssue'], signup['outcome'], stats['totals']['conversion'], len(starters))
```

A form keeps a draft `document` and the `publishedDocument` visitors see. `update` changes the draft and the settings, and `publish` puts the draft live. Settings take effect at once, published or not, and `expectedUpdatedAt` refuses a save that would overwrite someone else’s with 409 `version_conflict`.

Reading needs `forms:read` and changing needs `forms:write`. `approve_submission` also needs `contacts:write`, because it adds a contact. `resend_confirmation` also needs `emails:send`, and so does a call that makes the form send mail: turning on `doubleOptIn`, setting `senderAddress` or the confirmation email, or publishing or resuming a double opt-in form. `delete` asks an OAuth access token for a verification code, and an API key never.

> `subscribe` signs someone up as the form’s page does and sends no credential, even from a client that holds one. Every sign-up from one network shares a limit of 40 every ten minutes, so a server relaying sign-ups for many people reaches it quickly: add people you already know with `audiences.import_contacts` instead. Pass the page the form was on as `oe_source`, leave out `oe_started`, and send `oe_website` empty or not at all.

> A 422 from `subscribe` is `invalid_form_submission`, and the error’s `fields` lists each answer that is missing or not valid as `{'key': ..., 'error': ...}`, with reasons such as `required`, `email` and `option`. The client is for servers. In a browser, post the answers to the form’s `subscribeUrl` with `fetch`, as a JSON body or with an `Accept: application/json` header, and it answers JSON from any origin. Without either it answers with a 303 redirect to the hosted page.

- [Errors](https://openemail.uk/docs/python/errors.md): `OpenEmailApiError`, its `code` and `fields`, and the checks to branch on.

## Response: FormDetailResource

`list` returns one page of `FormResource`, newest first, without `document` and `settings`, and `list_all` and `iterate` walk every page. `get`, `create`, `update`, `publish`, `pause`, `resume` and `duplicate` return a `FormDetailResource`, which adds `document`, `publishedDocument`, `settings`, `audiences`, `senderIssue` and `senderProblem`.

- `id` (str): The durable handle, `frm_` followed by 24 hex characters.
- `status` (Literal['draft', 'live', 'paused']): `draft` until the first publish, then `live` while it takes sign-ups and `paused` while it does not. A form never goes back to `draft`.
- `url` (str): The hosted page of the published form, to share as a link.
- `subscribeUrl` (str): Where a plain HTML form, or `fetch`, posts the answers.
- `document` (FormDocument): The draft: `fields` in order, the `copy` around them and the `style`.
- `publishedDocument` (FormDocument | None): What visitors see now. `None` until the first publish.
- `settings` (FormSettings): Where sign-ups go and what happens after one: `audienceIds`, `doubleOptIn`, `senderAddress`, the confirmation email, `successAction`, `redirectUrl` and `notifyAddresses`.
- `hasUnpublishedChanges` (bool): `True` when the draft differs from what visitors see. Always `False` before the first publish.
- `senderIssue` (Literal['missing', 'not_sendable', 'not_allowed'] | None): Why a double opt-in form cannot send its confirmation emails right now, or `None` when it can.
- `stats` (FormStats): `views`, `submissions`, `added`, `pending` and `lastSubmittedAt`, counted at the moment of the read.

## Submissions

`list_submissions` pages newest first, with `q` to search email addresses and `status` for `pending` or `added`, and `list_all_submissions` and `iterate_submissions` walk every page. Each `FormSubmissionResource` keeps the answers as they were sent, labels included, so it still reads right after the form changes.

`resend_confirmation` returns the submission with `confirmationSent`. It is `False` when nothing went out: one address gets one confirmation per form every ten minutes and five a day across the workspace, and an added submission gets none. `expired` marks a pending sign-up whose latest link has run out.

## Reference

- [`forms.list()`](https://openemail.uk/docs/python/reference/forms#list): full reference
- [`forms.list_all()`](https://openemail.uk/docs/python/reference/forms#listAll): full reference
- [`forms.iterate()`](https://openemail.uk/docs/python/reference/forms#iterate): full reference
- [`forms.get()`](https://openemail.uk/docs/python/reference/forms#get): full reference
- [`forms.create()`](https://openemail.uk/docs/python/reference/forms#create): full reference
- [`forms.update()`](https://openemail.uk/docs/python/reference/forms#update): full reference
- [`forms.delete()`](https://openemail.uk/docs/python/reference/forms#delete): full reference
- [`forms.publish()`](https://openemail.uk/docs/python/reference/forms#publish): full reference
- [`forms.pause()`](https://openemail.uk/docs/python/reference/forms#pause): full reference
- [`forms.resume()`](https://openemail.uk/docs/python/reference/forms#resume): full reference
- [`forms.duplicate()`](https://openemail.uk/docs/python/reference/forms#duplicate): full reference
- [`forms.analytics()`](https://openemail.uk/docs/python/reference/forms#analytics): full reference
- [`forms.list_starters()`](https://openemail.uk/docs/python/reference/forms#listStarters): full reference
- [`forms.get_starter()`](https://openemail.uk/docs/python/reference/forms#getStarter): full reference
- [`forms.list_submissions()`](https://openemail.uk/docs/python/reference/forms#listSubmissions): full reference
- [`forms.list_all_submissions()`](https://openemail.uk/docs/python/reference/forms#listAllSubmissions): full reference
- [`forms.iterate_submissions()`](https://openemail.uk/docs/python/reference/forms#iterateSubmissions): full reference
- [`forms.get_submission()`](https://openemail.uk/docs/python/reference/forms#getSubmission): full reference
- [`forms.delete_submission()`](https://openemail.uk/docs/python/reference/forms#deleteSubmission): full reference
- [`forms.delete_submissions()`](https://openemail.uk/docs/python/reference/forms#deleteSubmissions): full reference
- [`forms.approve_submission()`](https://openemail.uk/docs/python/reference/forms#approveSubmission): full reference
- [`forms.resend_confirmation()`](https://openemail.uk/docs/python/reference/forms#resendConfirmation): full reference
- [`forms.subscribe()`](https://openemail.uk/docs/python/reference/forms#subscribe): full reference
