---
title: "Submit Form API Reference"
description: "Submit form entries programmatically using the Forminit REST API. Learn about authentication, request formats, block types, and code examples."
url: https://forminit.com/docs/submit-form-api/
---

# Submit Form API Reference

Submit form entries programmatically using the Forminit REST API.

> **Authentication:** Optional `X-API-KEY` header. Required for protected forms and enables higher rate limits.

---

## Endpoint

```
POST https://forminit.com/f/{formId}
```

| Method | URL | Description |
|--------|-----|-------------|
| `POST` | `/f/{formId}` | Create a new submission for a form |

## Content Types

| Content Type | Use Case |
|--------------|----------|
| `application/json` | Recommended for API integrations |
| `multipart/form-data` | Required for file uploads |
| `application/x-www-form-urlencoded` | HTML native form posts |

## Authentication

Include your API key in the `X-API-KEY` header for protected forms or higher rate limits.

```
X-API-KEY: sk_live_abc123xyz
```

To generate an API key:

1. Go to **Account - API Tokens** in your Forminit dashboard
2. Click **Create Token**
3. Copy and securely store your token

---

## Parameters

### Path Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `formId` | string | Yes | Form identifier (e.g., `YOUR-FORM-ID`) |

### Header Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `X-API-KEY` | string | No | API key for protected forms and higher rate limits |
| `Content-Type` | string | Yes | Request content type |

## Request Body

### JSON Format (Recommended)

```json
{
  "blocks": [
    {
      "type": "sender",
      "properties": {
        "email": "john@example.com",
        "firstName": "John",
        "lastName": "Doe"
      }
    },
    {
      "type": "text",
      "name": "message",
      "value": "Hello from Forminit!"
    }
  ]
}
```

### FormData Format

Use `fi-{blockType}-{property}` naming for fields:

```
fi-sender-email: john@example.com
fi-sender-firstName: John
fi-sender-lastName: Doe
fi-text-message: Hello from Forminit!
```

---

## Block Types

### Object Blocks

Can only appear once per submission.

| Block | Description |
|-------|-------------|
| `sender` | Submitter information (email, name, phone, etc.) |
| `tracking` | UTM parameters and attribution data |

### Field Blocks

Require a unique `name` identifier. Can have multiple instances with different names.

| Block | Value Type | Description |
|-------|------------|-------------|
| `text` | string | Free-form text |
| `number` | number | Numeric value |
| `email` | string | Email address (validated) |
| `phone` | string | Phone in E.164 format (validated) |
| `url` | string | Valid URL (validated) |
| `date` | string | ISO 8601 date/datetime |
| `rating` | integer | Rating 1-5 |
| `select` | string or string[] | Dropdown single or multi-select |
| `radio` | string | Radio button single choice |
| `checkbox` | string or string[] | Checkbox single or multi-choice |
| `file` | binary | File upload (FormData only) |
| `country` | string | ISO 3166-1 alpha-2 code |

---

## Request Examples

### Basic Contact Form

```bash
curl -X POST 'https://forminit.com/f/YOUR-FORM-ID' \
  -H 'Content-Type: application/json' \
  -d '{
    "blocks": [
      {
        "type": "sender",
        "properties": {
          "email": "john@example.com",
          "fullName": "John Doe"
        }
      },
      {
        "type": "text",
        "name": "message",
        "value": "Hello world"
      }
    ]
  }'
```

### With API Key

```bash
curl -X POST 'https://forminit.com/f/YOUR-FORM-ID' \
  -H 'Content-Type: application/json' \
  -H 'X-API-KEY: sk_live_abc123xyz' \
  -d '{
    "blocks": [
      {
        "type": "sender",
        "properties": {
          "email": "john@example.com"
        }
      }
    ]
  }'
```

### File Upload (FormData)

```bash
curl -X POST 'https://forminit.com/f/YOUR-FORM-ID' \
  -H 'X-API-KEY: sk_live_abc123xyz' \
  -F 'fi-sender-email=john@example.com' \
  -F 'fi-sender-fullName=John Doe' \
  -F 'fi-text-message=Please find my CV attached.' \
  -F 'fi-file-resume=@/path/to/resume.pdf'
```

### Complete Example

```bash
curl -X POST 'https://forminit.com/f/YOUR-FORM-ID' \
  -H 'Content-Type: application/json' \
  -H 'X-API-KEY: sk_live_abc123xyz' \
  -d '{
    "blocks": [
      {
        "type": "sender",
        "properties": {
          "email": "john@example.com",
          "firstName": "John",
          "lastName": "Doe",
          "phone": "+12025550123",
          "company": "Acme Corp"
        }
      },
      {
        "type": "tracking",
        "properties": {
          "utmSource": "google",
          "utmMedium": "cpc",
          "utmCampaign": "summer_sale"
        }
      },
      {
        "type": "text",
        "name": "message",
        "value": "I would like to learn more."
      },
      {
        "type": "select",
        "name": "plan",
        "value": "Enterprise"
      },
      {
        "type": "rating",
        "name": "urgency",
        "value": 4
      }
    ]
  }'
```

---

## Response

### Success Response (200)

```json
{
  "success": true,
  "redirectUrl": "https://forminit.com/thank-you",
  "submission": {
    "hashId": "yuTRm1S6lCqIPhCH",
    "date": "2025-12-17 22:22:11",
    "blocks": {
      "sender": {
        "email": "john@example.com",
        "firstName": "John",
        "lastName": "Doe"
      },
      "message": "Hello world",
      "plan": "Enterprise"
    },
    "submissionInfo": {
      "ip": "78.163.141.101",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
      "referer": "https://example.com/",
      "location": {
        "country": {
          "name": "United States",
          "iso": "US"
        },
        "city": {
          "name": "New York"
        },
        "timezone": "America/New_York"
      }
    }
  }
}
```

### Response Fields

| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` on success |
| `redirectUrl` | string | Thank you page URL |
| `submission.hashId` | string | Unique submission identifier |
| `submission.date` | string | Timestamp (YYYY-MM-DD HH:mm:ss) |
| `submission.blocks` | object | All submitted field values |
| `submission.submissionInfo` | object | IP, user agent, and location data |

---

## Error Responses

### 400 Bad Request

```json
{
  "success": false,
  "error": "EMPTY_SUBMISSION",
  "code": 400,
  "message": "At least one field with a value is required."
}
```

### 401 Unauthorized

```json
{
  "success": false,
  "error": "MISSING_API_KEY",
  "code": 401,
  "message": "Missing X-API-KEY key in the header"
}
```

### 403 Forbidden

```json
{
  "success": false,
  "error": "FORM_DISABLED",
  "code": 403,
  "message": "This form is currently disabled."
}
```

### 404 Not Found

```json
{
  "success": false,
  "error": "FORM_NOT_FOUND",
  "code": 404,
  "message": "This form has been deleted and is no longer available."
}
```

### 429 Too Many Requests

Protected mode (with an API key), over 5 requests per second:

```json
{
  "success": false,
  "error": "TOO_MANY_REQUESTS",
  "code": 429,
  "message": "Rate limit exceeded. Maximum 5 requests per second allowed.",
  "suggest": "Wait a moment before making another request."
}
```

Public mode (no API key), more than one submission every 5 seconds:

```json
{
  "success": false,
  "error": "TOO_MANY_REQUESTS",
  "code": 429,
  "message": "You can send new submissions once every 5 seconds.",
  "suggest": "Wait for 5 seconds before making another request."
}
```

---

## Common Error Codes

| Error Code | Status | Description |
|------------|--------|-------------|
| `FORM_ID_REQUIRED` | 400 | Form ID is missing |
| `EMPTY_SUBMISSION` | 400 | No fields submitted |
| `FI_FIELD_TYPE_MISSING` | 400 | Block type is missing |
| `FI_FIELD_NAME_MISSING` | 400 | Field name is missing |
| `FI_FIELD_DUPLICATE_NAME` | 400 | Duplicate field name |
| `FI_SCHEMA_FORMAT_EMAIL` | 400 | Invalid email format |
| `FI_RULES_PHONE_INVALID` | 400 | Invalid phone format |
| `FI_SCHEMA_RANGE_RATING` | 400 | Rating not between 1-5 |
| `FI_DATA_COUNTRY_INVALID` | 400 | Invalid country code |
| `MISSING_API_KEY` | 401 | API key required but missing |
| `FORM_DISABLED` | 403 | Form is disabled |
| `LIMIT_EXPIRED` | 403 | Plan limit reached |
| `FORM_NOT_FOUND` | 404 | Form does not exist |
| `UNSUPPORTED_CONTENT_TYPE` | 415 | Invalid content type |
| `TOO_MANY_REQUESTS` | 429 | Rate limit exceeded |

---

## Rate Limits

| Authentication | Rate Limit | Counted per |
|----------------|------------|-------------|
| With API Key (Protected mode) | 5 requests per second | IP address |
| Without API Key (Public mode) | 1 request per 5 seconds | IP address |
| Legacy Forms | 1 request per 5 seconds | |

Requests over the limit are rejected with HTTP `429` and the `TOO_MANY_REQUESTS` error code, and the submission is not stored. Wait for the interval in the error's `suggest` field before sending again. See [429 Too Many Requests](#429-too-many-requests) for the response bodies.

---

## Code Examples

### Node.js

```js
const response = await fetch('https://forminit.com/f/YOUR-FORM-ID', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-KEY': process.env.FORMINIT_API_KEY,
  },
  body: JSON.stringify({
    blocks: [
      {
        type: 'sender',
        properties: {
          email: 'john@example.com',
          firstName: 'John',
          lastName: 'Doe',
        },
      },
      {
        type: 'text',
        name: 'message',
        value: 'Hello world',
      },
    ],
  }),
});

const result = await response.json();

if (result.success) {
  console.log('Submission ID:', result.submission.hashId);
} else {
  console.error('Error:', result.message);
}
```

### Python

```python
import requests
import os

response = requests.post(
    'https://forminit.com/f/YOUR-FORM-ID',
    headers={
        'Content-Type': 'application/json',
        'X-API-KEY': os.environ.get('FORMINIT_API_KEY'),
    },
    json={
        'blocks': [
            {
                'type': 'sender',
                'properties': {
                    'email': 'john@example.com',
                    'firstName': 'John',
                    'lastName': 'Doe',
                },
            },
            {
                'type': 'text',
                'name': 'message',
                'value': 'Hello world',
            },
        ],
    },
)

result = response.json()

if result.get('success'):
    print('Submission ID:', result['submission']['hashId'])
else:
    print('Error:', result.get('message'))
```

### PHP

```php
<?php

$data = [
    'blocks' => [
        [
            'type' => 'sender',
            'properties' => [
                'email' => 'john@example.com',
                'firstName' => 'John',
                'lastName' => 'Doe',
            ],
        ],
        [
            'type' => 'text',
            'name' => 'message',
            'value' => 'Hello world',
        ],
    ],
];

$ch = curl_init('https://forminit.com/f/YOUR-FORM-ID');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'X-API-KEY: ' . getenv('FORMINIT_API_KEY'),
    ],
    CURLOPT_POSTFIELDS => json_encode($data),
]);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);

if ($result['success']) {
    echo 'Submission ID: ' . $result['submission']['hashId'];
} else {
    echo 'Error: ' . $result['message'];
}
```

---

## Validation Rules

| Field | Rule |
|-------|------|
| `sender.email` | Valid email format |
| `sender.phone` | E.164 format (+12025550123) |
| `sender.country` | ISO 3166-1 alpha-2 code |
| `email` block | Valid email format |
| `phone` block | E.164 format |
| `url` block | Valid URL format |
| `rating` block | Integer 1-5 |
| `date` block | ISO 8601 format |
| `country` block | ISO 3166-1 alpha-2 code |

---

## Limits

| Limit | Value |
|-------|-------|
| Maximum field blocks per submission (`sender` and `tracking` don't count toward this limit) | 100 |
| Maximum blocks of same type | 50 |
| Maximum file blocks per submission | 20 |
| Maximum file upload size | 25 MB per submission (all files combined) |
| Object blocks per type (`sender`, `tracking`) | 1 |

---

## Related Documentation

- [Form Blocks Reference](https://forminit.com/docs/form-blocks/) - Complete block type reference
- [File Uploads](https://forminit.com/docs/file-upload/) - File upload guide
- [Get Submissions API](https://forminit.com/docs/list-submissions-api/) - Retrieve submissions
- [Node.js Integration](https://forminit.com/docs/nodejs/) - Node.js setup guide
