Skip to content

Forminit Python SDK Reference

The official Python SDK for Forminit form backend service.


pip install forminit

Requirements: Python 3.8+


from forminit import ForminitClient

client = ForminitClient(api_key="fi_your_secret_api_key")

response = client.submit("YOUR_FORM_ID", {
    "blocks": [
        {
            "type": "sender",
            "properties": {
                "email": "john@example.com",
                "firstName": "John",
                "lastName": "Doe",
            },
        },
        {
            "type": "text",
            "name": "message",
            "value": "Hello world",
        },
    ],
})

if response.get("error"):
    print("Error:", response["error"]["message"])
else:
    print("Submission ID:", response["data"]["hashId"])

client.close()
from forminit import AsyncForminitClient

async with AsyncForminitClient(api_key="fi_your_secret_api_key") as client:
    response = await client.submit("YOUR_FORM_ID", {
        "blocks": [
            {
                "type": "sender",
                "properties": {
                    "email": "john@example.com",
                    "firstName": "John",
                },
            },
            {
                "type": "text",
                "name": "message",
                "value": "Hello world",
            },
        ],
    })

OptionTypeDescription
api_keystrServer-side API key for authentication
proxy_urlstrClient-side proxy URL to protect API key
base_urlstrCustom base URL (default: https://forminit.com)
# Server-side with API key
client = ForminitClient(api_key="fi_your_secret_api_key")

# With proxy URL
client = ForminitClient(proxy_url="http://localhost:8000/api/forminit")

Synchronous client using httpx. Supports context manager protocol.

ForminitClient(api_key=None, proxy_url=None, base_url="https://forminit.com")
client.submit(form_id, data, tracking=None)

Submits form data to Forminit.

Parameters:

ParameterTypeDescription
form_idstrYour Forminit form ID
datadictForm data (structured blocks or flat dict)
trackingdict | NoneOptional tracking parameters

Returns: FormResponse dict with data or error

client.set_user_info(ip=None, user_agent=None, referer=None)

Sets user information for server-side submissions. Used when submitting on behalf of a user.

Parameters:

ParameterTypeDescription
ipstr | NoneUser’s IP address
user_agentstr | NoneUser’s browser user agent
refererstr | NoneReferring page URL
client.close()

Closes the underlying HTTP client. Called automatically when using context manager.

with ForminitClient(api_key="fi_your_secret_api_key") as client:
    response = client.submit("YOUR_FORM_ID", data)
# client is automatically closed

Asynchronous client using httpx.AsyncClient. Supports async context manager protocol.

AsyncForminitClient(api_key=None, proxy_url=None, base_url="https://forminit.com")

Same as ForminitClient, but all methods are async:

async with AsyncForminitClient(api_key="fi_your_secret_api_key") as client:
    response = await client.submit("YOUR_FORM_ID", data)

Use the blocks format for typed, validated submissions:

response = client.submit("YOUR_FORM_ID", {
    "blocks": [
        {
            "type": "sender",
            "properties": {
                "email": "john@example.com",
                "firstName": "John",
                "lastName": "Doe",
                "phone": "+12025550123",
                "company": "Acme Corp",
            },
        },
        {
            "type": "text",
            "name": "message",
            "value": "Hello world",
        },
        {
            "type": "select",
            "name": "plan",
            "value": "Enterprise",
        },
        {
            "type": "rating",
            "name": "urgency",
            "value": 4,
        },
    ],
})

Use fi- prefixed keys for flat dictionary submissions. The SDK sends these as URL-encoded form data:

response = client.submit("YOUR_FORM_ID", {
    "fi-sender-firstName": "John",
    "fi-sender-lastName": "Doe",
    "fi-sender-email": "john@example.com",
    "fi-text-message": "Hello world",
})

Field Naming Patterns:

Block TypePatternExample
Sender propertiesfi-sender-{property}fi-sender-email
Textfi-text-{name}fi-text-message
Numberfi-number-{name}fi-number-quantity
Emailfi-email-{name}fi-email-invitee
Phonefi-phone-{name}fi-phone-emergency
URLfi-url-{name}fi-url-website
Datefi-date-{name}fi-date-appointment
Ratingfi-rating-{name}fi-rating-satisfaction
Selectfi-select-{name}fi-select-plan
Countryfi-country-{name}fi-country-shipping

Collects submitter information. Can only appear once per submission.

{
    "type": "sender",
    "properties": {
        "email": "john@example.com",       # Email address
        "firstName": "John",               # First name
        "lastName": "Doe",                 # Last name
        "fullName": "John Doe",            # Full name
        "phone": "+12025550123",           # Phone (E.164 format)
        "userId": "usr_123",               # User ID from your system
        "company": "Acme Corp",            # Company name
        "position": "Developer",           # Job title
        "address": "123 Main St",          # Street address
        "city": "New York",                # City
        "country": "US",                   # Country (ISO alpha-2)
        "title": "Mr",                     # Title (Mr, Mrs, Dr, Prof)
    },
}

At least one of userId, email, phone, firstName, lastName, or fullName is required.

Captures UTM parameters and attribution data. Can only appear once per submission.

{
    "type": "tracking",
    "properties": {
        "utmSource": "google",
        "utmMedium": "cpc",
        "utmCampaign": "spring_2026",
        "utmTerm": "form backend",
        "utmContent": "hero_cta",
        "gclid": "EAIaIQobChMI...",      # Google Ads
        "fbclid": "IwAR3x...",            # Facebook
        "msclkid": "a1b2c3...",           # Microsoft Ads
        "ttclid": "E.C.P...",             # TikTok
        "twclid": "abc123...",            # X (Twitter)
    },
}

You can also pass tracking data via the tracking parameter on submit():

response = client.submit("YOUR_FORM_ID", data, tracking={
    "utm_source": "google",
    "utm_medium": "cpc",
    "gclid": "EAIaIQobChMI...",
})

Each field block requires a unique name identifier.

# Text
{"type": "text", "name": "message", "value": "Hello world"}

# Number
{"type": "number", "name": "quantity", "value": 10}

# Email
{"type": "email", "name": "invitee", "value": "friend@example.com"}

# Phone (E.164 format)
{"type": "phone", "name": "emergency", "value": "+12025550123"}

# URL
{"type": "url", "name": "website", "value": "https://example.com"}

# Date (ISO 8601)
{"type": "date", "name": "appointment", "value": "2026-01-15"}

# Rating (1-5)
{"type": "rating", "name": "satisfaction", "value": 5}

# Select (single or multi)
{"type": "select", "name": "plan", "value": "Pro"}
{"type": "select", "name": "services", "value": ["web", "seo"]}

# Country (ISO 3166-1 alpha-2)
{"type": "country", "name": "shipping", "value": "US"}

{
    "data": {
        "hashId": "7LMIBoYY74JOCp1k",
        "date": "2026-01-01 21:10:24",
        "blocks": {
            "sender": {
                "firstName": "John",
                "lastName": "Doe",
                "email": "john@example.com"
            },
            "message": "Hello world"
        }
    },
    "redirectUrl": "https://forminit.com/thank-you"
}
FieldTypeDescription
data.hashIdstrUnique submission identifier
data.datestrSubmission timestamp
data.blocksdictSubmitted field values
redirectUrlstrThank you page URL
{
    "error": {
        "success": False,
        "error": "FI_SCHEMA_FORMAT_EMAIL",
        "code": 400,
        "message": "Invalid email format"
    }
}
FieldTypeDescription
error.errorstrError code
error.codeintHTTP status code
error.messagestrHuman-readable message

When submitting on behalf of a user from your server, pass their IP, user agent, and referer so Forminit can capture geolocation and attribution data:

client.set_user_info(
    ip=request.headers.get("X-Forwarded-For", request.remote_addr),
    user_agent=request.headers.get("User-Agent"),
    referer=request.headers.get("Referer"),
)

response = client.submit("YOUR_FORM_ID", data)

The SDK sends this information via X-Forwarded-For, X-Real-IP, User-Agent, and Referer headers.


Error CodeStatusDescription
MISSING_API_KEY401Server-side call without API key
FORM_NOT_FOUND404Form ID does not exist
FORM_DISABLED403Form is currently disabled
EMPTY_SUBMISSION400No fields with values submitted
FI_SCHEMA_FORMAT_EMAIL400Invalid email format
FI_RULES_PHONE_INVALID400Invalid phone number format
FI_SCHEMA_RANGE_RATING400Rating not between 1-5
FI_DATA_COUNTRY_INVALID400Invalid country code
TOO_MANY_REQUESTS429Rate limit exceeded

AuthenticationRate Limit
With API Key5 requests per second
Without API Key1 request per 5 seconds

  1. Store API keys in environment variables — Never hardcode keys in source code.
  2. Use context managers — Ensures the HTTP client is properly closed.
  3. Always use the sender block to identify form submitters.
  4. Handle errors gracefully — Check for error in the response.
  5. Use E.164 format for phone numbers (e.g., +12025550123).
  6. Use ISO 3166-1 alpha-2 codes for countries (e.g., US, GB, TR).
  7. Call set_user_info() when submitting on behalf of users to enable geolocation and attribution tracking.