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

# Create Form

> Create a new form to send to a contact.

## Request Parameters

### Required Fields

| Field       | Type   | Description              |
| ----------- | ------ | ------------------------ |
| `flow.slug` | string | Form template identifier |

### Optional Fields

| Field              | Type    | Description                                             |
| ------------------ | ------- | ------------------------------------------------------- |
| `company.slug`     | string  | Workspace identifier (if multiple authorized)           |
| `user.email`       | string  | Contact email address                                   |
| `user.phone`       | string  | Contact phone number                                    |
| `user.given_name`  | string  | Contact first name                                      |
| `user.family_name` | string  | Contact last name                                       |
| `user.locale`      | string  | Contact language (e.g., `en`, `fr`)                     |
| `data`             | object  | Pre-filled form data (keys must match form field keys)  |
| `external_args`    | object  | Your custom metadata                                    |
| `redirect_url`     | string  | HTTPS URL to redirect after completion                  |
| `draft`            | boolean | Create as draft (default: `false`)                      |
| `active_from`      | string  | ISO 8601 date when form becomes active                  |
| `active_until`     | string  | ISO 8601 date when form expires                         |
| `owner.email`      | string  | Form owner email address                                |
| `branding.slug`    | string  | Branding profile slug (see [Branding](#branding) below) |

## Form Statuses

| Status      | Description                          |
| ----------- | ------------------------------------ |
| `draft`     | Form created but not yet sent        |
| `pending`   | Form sent, waiting for completion    |
| `completed` | Contact submitted the form           |
| `declined`  | Contact declined to fill the form    |
| `processed` | Response has been reviewed/processed |

## Pre-filling Form Data

The `data` parameter allows you to pre-fill form fields with values. This is useful for importing data from your system or providing a better user experience by reducing the amount of information the contact needs to enter.

### How It Works

The keys in the `data` object **must exactly match the field keys** defined in your form template. When a contact opens the form, these fields will already contain the provided values.

**Example:**

If your form template has fields with keys:

* `company_name`
* `address_zip`
* `annual_revenue`

You can pre-fill them like this:

```json theme={null}
{
  "data": {
    "company_name": "Acme Corp",
    "address_zip": "10001",
    "annual_revenue": "500000"
  }
}
```

### Finding Field Keys

Field keys are defined in your form template configuration in Penbox. Common examples:

| Field Type       | Example Keys                                                       |
| ---------------- | ------------------------------------------------------------------ |
| **Company Info** | `company_name`, `company_vat`, `company_registration`              |
| **Address**      | `address_street`, `address_city`, `address_zip`, `address_country` |
| **Contact**      | `contact_name`, `contact_email`, `contact_phone`                   |
| **Financial**    | `annual_revenue`, `number_employees`, `bank_account`               |
| **Custom**       | Any custom field keys you've defined in your template              |

<Note>
  Field keys are case-sensitive and must match exactly. Use the Penbox app or contact your administrator to find the correct field keys for your form template.
</Note>

### Complete Example

```javascript theme={null}
const response = await fetch('https://connect.penbox.io/v1/forms', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    flow: { slug: 'client-onboarding' },
    user: {
      email: 'client@example.com',
      given_name: 'John',
      family_name: 'Doe'
    },
    // Pre-fill form fields
    data: {
      company_name: 'Acme Corporation',
      company_vat: 'BE0123456789',
      address_street: '123 Main Street',
      address_city: 'New York',
      address_zip: '10001',
      address_country: 'US',
      annual_revenue: '1500000',
      number_employees: '25'
    },
    external_args: {
      crm_id: '12345'
    },
    branding: {
      slug: 'partner-brand'
    }
  })
});
```

```bash cURL theme={null}
curl -X POST 'https://connect.penbox.io/v1/forms' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "flow": { "slug": "client-onboarding" },
    "user": {
      "email": "client@example.com",
      "given_name": "John",
      "family_name": "Doe"
    },
    "data": {
      "company_name": "Acme Corporation",
      "company_vat": "BE0123456789",
      "address_street": "123 Main Street",
      "address_city": "New York",
      "address_zip": "10001",
      "address_country": "US",
      "annual_revenue": "1500000",
      "number_employees": "25"
    },
    "external_args": {
      "crm_id": "12345"
    },
    "branding": {
      "slug": "partner-brand"
    }
  }'
```

### Use Cases

**Import from CRM:**

```javascript theme={null}
// Pull data from your CRM and pre-fill the form
const crmContact = await getCRMContact(contactId);

const formData = {
  company_name: crmContact.companyName,
  address_zip: crmContact.zipCode,
  annual_revenue: crmContact.revenue,
  contact_phone: crmContact.phone
};

await createForm({ 
  flow: { slug: 'onboarding' },
  user: { email: crmContact.email },
  data: formData 
});
```

**Progressive Forms:**

```javascript theme={null}
// Pre-fill with data collected in previous steps
const formData = {
  company_name: step1Data.company,
  address_zip: step2Data.zip,
  business_type: step3Data.type
};
```

**Reduce Friction:**

```javascript theme={null}
// Pre-fill known information to make the form faster
const formData = {
  company_name: user.organization,
  contact_email: user.email,
  contact_phone: user.phone
};
```

<Tip>
  Pre-filling data improves form completion rates and reduces errors. Always pre-fill what you know while allowing contacts to modify values if needed.
</Tip>

<Warning>
  If you provide a field key that doesn't exist in the form template, it will be silently ignored. Make sure your field keys match your template configuration.
</Warning>

## Branding

Use the `branding` parameter to apply a specific visual identity to a form — logo, colors, favicon, and related styling in the form experience and email notifications.

### Default behavior

When `branding` is omitted, the form uses your workspace's default branding — the profile configured under **Settings → Branding** in Penbox.

### How it works

Pass the slug of an existing branding profile in your workspace:

```json theme={null}
{
  "flow": { "slug": "client-onboarding" },
  "user": { "email": "client@example.com" },
  "branding": {
    "slug": "partner-brand"
  }
}
```

The slug must match a branding profile that already exists in the workspace. If the slug is invalid or not found, the API returns `404`.

<Note>
  To use the workspace default branding, omit the `branding` field entirely. The slug `default` is only a UI label for the primary workspace profile — it is not a valid API value.
</Note>

### Finding the branding slug

1. Open **Settings → Branding** in Penbox.
2. If your workspace has multiple branding profiles, select the profile you want and note its slug — it is displayed next to the profile selector (for example, `slug: partner-brand`).

See [Branding](/workspace/settings/branding) for how to create and manage branding profiles.

### Use cases

**White-label partner forms:**

```javascript theme={null}
await createForm({
  flow: { slug: 'onboarding' },
  user: { email: partner.contactEmail },
  branding: { slug: 'partner-acme' }
});
```

**Different brands per client segment:**

```javascript theme={null}
const brandingSlug = client.segment === 'enterprise'
  ? 'enterprise-brand'
  : 'self-serve-brand';

await createForm({
  flow: { slug: 'signup' },
  user: { email: client.email },
  branding: { slug: brandingSlug }
});
```

<Tip>
  Branding is set at form creation and applies to the form link and related emails for that form. Create separate branding profiles in Penbox when you need distinct visual identities for different clients or product lines.
</Tip>

## External Args

Use `external_args` to store your own metadata with forms for easy tracking:

```json theme={null}
{
  "external_args": {
    "crm_id": "12345",
    "order_id": "ORD-789",
    "source": "website",
    "campaign": "summer-2024"
  }
}
```

You can filter by external\_args when listing forms:

```json theme={null}
{
  "filter": {
    "external_args": {
      "order_id": "ORD-789"
    }
  }
}
```

## Response Codes

| Code  | Description                                       |
| ----- | ------------------------------------------------- |
| `201` | Created - New form created successfully           |
| `400` | Bad Request - Invalid parameters                  |
| `401` | Unauthorized - Invalid access token               |
| `403` | Forbidden - No access to this resource            |
| `409` | Conflict - Multiple form templates match criteria |
| `422` | Unprocessable - Validation failed                 |
| `429` | Too Many Requests - Rate limit exceeded           |
| `500` | Server Error - Internal error                     |

<Note>
  Created forms are immediately active unless `draft: true` is specified. Draft forms must be activated by setting `draft: false` via PATCH.
</Note>

<Tip>
  Use `external_args` to link Penbox forms back to your system's entities (orders, customers, tickets, etc.). This makes it easy to track and manage forms in your system.
</Tip>

<Warning>
  The `active_from` and `active_until` dates control when the form link is accessible. Set `active_until` to create expiring forms.
</Warning>


## OpenAPI

````yaml POST /forms
openapi: 3.0.0
info:
  title: Penbox API
  version: '1.0'
  description: >-
    The Penbox API provides programmatic access to Penbox's form management,
    case management, and document processing capabilities. Authenticate using
    Bearer tokens created at https://app.penbox.io/workspace/settings/api
servers:
  - url: https://connect.penbox.io/v1
    description: Production
  - url: https://connect.aiboov.com/v1
    description: Staging
security:
  - BearerAuth: []
paths:
  /forms:
    post:
      summary: Create Form
      description: Create a new form to send to a contact.
      operationId: create-form
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - flow
              properties:
                flow:
                  type: object
                  required:
                    - slug
                  properties:
                    slug:
                      oneOf:
                        - type: string
                          description: Form template slug identifier
                        - type: array
                          items:
                            type: string
                          minItems: 1
                          description: Array of form template slug identifiers
                    customization:
                      type: string
                      format: uuid
                      description: Form template customization UUID
                workspace:
                  type: object
                  properties:
                    slug:
                      type: string
                      description: Workspace slug
                user:
                  type: object
                  properties:
                    email:
                      type: string
                      format: email
                    phone:
                      type: string
                    given_name:
                      type: string
                    family_name:
                      type: string
                    company_name:
                      type: string
                    internal_ref:
                      type: string
                data:
                  type: object
                  description: Pre-filled form data
                external_args:
                  type: object
                  description: Your custom metadata
                redirect_url:
                  type: string
                  format: uri
                  description: HTTPS URL to redirect after completion
                draft:
                  type: boolean
                  default: false
                  description: Create as draft (not active)
                options:
                  type: object
                  description: Form-specific options
                  additionalProperties: true
                active_from:
                  type: string
                  format: date-time
                  description: ISO 8601 date when form becomes active
                active_until:
                  type: string
                  format: date-time
                  description: ISO 8601 date when form expires
                owner:
                  type: object
                  properties:
                    email:
                      type: string
                      format: email
                      description: Owner email address
                branding:
                  type: object
                  description: >-
                    Branding profile to apply to the form. Omit to use the
                    workspace default.
                  properties:
                    slug:
                      type: string
                      description: Branding profile slug from Settings → Branding
                  required:
                    - slug
            example:
              flow:
                slug: client-onboarding
              user:
                email: client@example.com
                given_name: John
                family_name: Doe
              data:
                company_name: Acme Corporation
                company_vat: BE0123456789
                address_street: 123 Main Street
                address_city: New York
                address_zip: '10001'
                address_country: US
                annual_revenue: '1500000'
                number_employees: '25'
              external_args:
                crm_id: '12345'
              branding:
                slug: partner-brand
      responses:
        '201':
          description: Form created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Form'
components:
  schemas:
    Form:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Form UUID
        created_at:
          type: string
          format: date-time
          description: Creation timestamp
        status:
          type: string
          enum:
            - draft
            - pending
            - completed
            - declined
            - processed
          description: Current form status
        archived:
          type: boolean
          description: Whether the form is archived
        archived_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when archived
        processed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when marked as processed
        active_from:
          type: string
          format: date-time
          nullable: true
          description: When the form becomes active
        active_until:
          type: string
          format: date-time
          nullable: true
          description: When the form expires
        links:
          type: object
          properties:
            fill:
              type: string
              format: uri
              description: Public form link for the contact
            app:
              type: string
              format: uri
              description: Internal app link to view the form
          description: URLs for accessing the form
        user:
          type: object
          properties:
            anonymous:
              type: boolean
            email:
              type: string
            phone:
              type: string
            given_name:
              type: string
            family_name:
              type: string
            company_name:
              type: string
            internal_ref:
              type: string
          description: Contact information
        owner:
          type: object
          nullable: true
          properties:
            id:
              type: string
              format: uuid
            email:
              type: string
          description: Form owner information
        flow:
          type: object
          properties:
            slug:
              type: string
              description: Form template slug identifier
          description: Form template information
        data:
          type: object
          description: Pre-filled form data
        external_args:
          type: object
          nullable: true
          description: Custom metadata
        options:
          type: object
          nullable: true
          description: Form-specific options
        responses:
          type: array
          items:
            $ref: '#/components/schemas/ResponseFlat'
          description: Array of form responses
        notifications:
          type: array
          items:
            $ref: '#/components/schemas/Notification'
          description: Array of notifications sent for this form
        webhooks:
          type: object
          nullable: true
          description: Webhook URLs with event subscriptions
          additionalProperties:
            type: array
            items:
              type: string
    ResponseFlat:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Response UUID
        completed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the response was completed
        updated_at:
          type: string
          format: date-time
          description: Last update timestamp
        data:
          type: object
          description: Form field values
        user:
          type: object
          properties:
            anonymous:
              type: boolean
            ip:
              type: string
            email:
              type: string
            phone:
              type: string
            locale:
              type: string
            given_name:
              type: string
            family_name:
              type: string
            user-agent:
              type: string
            accept-language:
              type: string
          description: User information
        attachments:
          type: array
          items:
            $ref: '#/components/schemas/AttachmentFlat'
          description: Uploaded files
        signatures:
          type: object
          description: Signature data
        files:
          type: object
          description: Organized files by category
    Notification:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Unique notification identifier
        status:
          type: string
          enum:
            - pending
            - sent
            - failed
            - skipped
          description: Current status of the notification
        method:
          type: string
          enum:
            - sms
            - email
          description: Delivery method
        at:
          type: string
          format: date-time
          description: Timestamp when the notification was sent
        to:
          type: string
          nullable: true
          description: Recipient address (email or phone number)
        from:
          type: string
          nullable: true
          description: Sender address
        cc:
          type: string
          nullable: true
          description: Carbon copy recipient
        bcc:
          type: string
          nullable: true
          description: Blind carbon copy recipient
        system:
          type: boolean
          description: Whether this is a system notification
        locale:
          type: string
          description: Language/locale code (e.g., 'fr', 'en')
        template:
          type: string
          nullable: true
          description: Template name used for the notification
        variables:
          type: object
          nullable: true
          description: Template variables used in the message
        active:
          type: boolean
          description: Whether the notification is active
        error:
          type: string
          nullable: true
          description: Error message if notification failed
        message_id:
          type: string
          nullable: true
          description: External message identifier from delivery provider
        attachments:
          type: object
          nullable: true
          description: Attached files
        deleted_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the notification was deleted
      required:
        - id
        - status
        - method
        - at
    AttachmentFlat:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Attachment UUID
        name:
          type: string
          description: Original filename
        type:
          type: string
          description: MIME type
        scope:
          type: string
          nullable: true
          description: Attachment scope
        data:
          type: string
          nullable: true
          description: Base64-encoded file content
        metadata:
          type: object
          properties:
            size:
              type: integer
              description: File size in bytes
            width:
              type: integer
              nullable: true
            height:
              type: integer
              nullable: true
        uri:
          type: string
          format: uri
          description: Direct download URL
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: token
      description: >-
        API token (starts with pnbx_). Create at
        https://app.penbox.io/workspace/settings/api. Include as: Authorization:
        Bearer {token}

````