Skip to main content
POST
/
api
/
v1
/
f
/
{form_token}
/
entries
Submit an entry to a published form
curl --request POST \
  --url https://formhug.ai/api/v1/f/{form_token}/entries \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "field_values": {
    "field_1": "Jane Doe",
    "field_2": "Welcome!"
  }
}
'
import requests

url = "https://formhug.ai/api/v1/f/{form_token}/entries"

payload = { "field_values": {
"field_1": "Jane Doe",
"field_2": "Welcome!"
} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({field_values: {field_1: 'Jane Doe', field_2: 'Welcome!'}})
};

fetch('https://formhug.ai/api/v1/f/{form_token}/entries', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
CURLOPT_URL => "https://formhug.ai/api/v1/f/{form_token}/entries",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'field_values' => [
'field_1' => 'Jane Doe',
'field_2' => 'Welcome!'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
package main

import (
"fmt"
"strings"
"net/http"
"io"
)

func main() {

url := "https://formhug.ai/api/v1/f/{form_token}/entries"

payload := strings.NewReader("{\n \"field_values\": {\n \"field_1\": \"Jane Doe\",\n \"field_2\": \"Welcome!\"\n }\n}")

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")

res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := io.ReadAll(res.Body)

fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://formhug.ai/api/v1/f/{form_token}/entries")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"field_values\": {\n \"field_1\": \"Jane Doe\",\n \"field_2\": \"Welcome!\"\n }\n}")
.asString();
require 'uri'
require 'net/http'

url = URI("https://formhug.ai/api/v1/f/{form_token}/entries")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"field_values\": {\n \"field_1\": \"Jane Doe\",\n \"field_2\": \"Welcome!\"\n }\n}"

response = http.request(request)
puts response.read_body
{
  "data": {
    "serial_number": 42,
    "token": "aB2cD9eF",
    "created_at": "2023-11-07T05:31:56Z",
    "updated_at": "2023-11-07T05:31:56Z"
  }
}
{
"error": "Authentication failed"
}
{
"error": "Name can't be blank",
"error_details": [
{
"attribute": "name",
"message": "can't be blank"
}
]
}
{
"error": "Form not found"
}

Authorizations

Authorization
string
header
required

Personal Access Token prefixed with fh_. Sent as Authorization: Bearer fh_xxx. The scope required by each endpoint is listed in that endpoint's description.

Headers

X-Form-Access-Password
string

Access password, when the form is password-protected

Path Parameters

form_token
string
required

Token of a published form

Body

application/json
field_values
object
required

Map keyed by field api_code; unknown keys are dropped silently

Example:
{
"field_1": "Jane Doe",
"field_2": "Welcome!"
}

Response

Submitted

data
object
required

A submitted entry. In addition to the fixed fields below, every field of the parent form appears as a top-level key on the entry under its api_code. The JSON value type for each such key is determined by the corresponding field's type.

Field value shapes

Each field of the parent form appears as a top-level key on the entry, keyed by its api_code. The JSON shape of the value depends on the field's type:

Field type (type)Submitted value
short_textString. The submitted text.
long_textString. Multi-line text.
radioObject { value, other_text?, extended_text? }, or null when unset. value is the api_code of the selected choice. other_text carries the respondent's free-text input and is only present when the selected choice has is_other: true. extended_text carries the free-text input for a choice that has allow_extended_text: true. The two text keys are mutually exclusive per choice (an is_other choice cannot also enable allow_extended_text) and both are omitted when blank. On write, a bare string is accepted as shorthand for { value: <string> }; null clears the field; text keys that don't match the selected choice's configuration are ignored.
checkboxArray of { value, other_text?, extended_text? } objects with the same per-choice semantics as radio. Empty array when nothing is selected. At most one element may carry other_text (the element whose value corresponds to the is_other choice). On write, null clears the field; bare strings in the array are accepted as shorthand for { value: <string> }; duplicate values are silently de-duplicated (first occurrence wins).
image_radioObject { value }, or null when unset. value is the api_code of the selected choice. Image choices support neither other_text nor extended_text. On write, a bare string is accepted as shorthand for { value: <string> }; null clears the field.
image_checkboxArray of { value } objects — value is the api_code of a selected choice. Empty array when nothing is selected. On write, null clears the field; bare strings in the array are accepted as shorthand; duplicate values are silently de-duplicated (first occurrence wins).
dropdownObject { value, other_text? }, or null when unset. Same value and other_text semantics as radio. dropdown does not support extended_text.
numberNumber. Stored as a float; integer-looking values may serialize without a decimal point.
emailString — an email address.
phoneObject { country_id, country_code, number }. country_id is an ISO 3166-1 alpha-2 country code (e.g. "CN", "US") and is required; country_code is the dialing code without + (e.g. "86", "1") and is optional on write — when omitted it is derived from country_id; number is the local number without the dialing-code prefix.
dateNaive wall-clock string formatted per the field's precision: "YYYY-MM" (month), "YYYY-MM-DD" (day), "YYYY-MM-DD HH:mm" (minute), "YYYY-MM-DD HH:mm:ss" (second). Values are interpreted in the form's timezone setting. When no timezone is supplied at creation time, the form uses your account's timezone, falling back to UTC if that is unset or invalid.
nameString — the submitted name.
urlString — a URL.
addressObject { address_line1, address_line2, city, state, postal_code, country }. country is an ISO 3166-1 alpha-2 country code; state is an ISO 3166-2 subdivision code (e.g. "CA", "NY"), not a localized label.
ratingInteger — the chosen rating level (1..rating_max).
npsInteger — the selected score (0..10).
attachmentArray of objects { id: string, name: string, url: string, file_size: integer, content_type: string }. url is a signed download link valid for 24 hours — refetch the entry to get a fresh link rather than caching it; name is the original filename.
audioRead-only object { id, name, url, file_size, content_type, duration } describing the recording (url is a signed download link valid for 24 hours; duration is the recording length). Null when no recording. Submitting a value for an audio field is not supported.
cascadeObject { level_1: <api_code>, level_2: <api_code>, ... } — one key per level (the field's levels setting, default 2). Each value is the api_code of the choice selected at that level.
rankingObject { <choice_api_code>: <rank> }rank is a positive integer, contiguous starting at 1 for the highest-ranked choice. Unranked choices are omitted.
matrixNested object { <statement_api_code>: { <dimension_api_code>: <cell_value> }, ... }. The inner cell value type depends on the matrix cell field type.
likertObject { <statement_api_code>: [<choice_api_code>, ...] }. The value is always an array — a single-choice answer is wrapped in a one-element array.
timeObject { hour: integer, minute: integer }, plus second: integer when the field has include_second enabled (e.g. { "hour": 9, "minute": 5 }).
locationObject { longitude: number, latitude: number, address: string }.
signatureRead-only string — a signed download URL for the signature image, valid for 24 hours. Refetch the entry to obtain a fresh link rather than caching it. Submitting a value for a signature field is not supported.
matrix_ratingNested object { <statement_api_code>: { <dimension_api_code>: <integer> } }. The inner integer is the chosen rating level (1..rating_max).
tableArray of row objects [{ <dimension_api_code>: <cell_value>, ... }]. The inner cell value type depends on each dimension's field type.
productArray [{ api_code, number, specification? }]. specification is present when the goods item has dimensions; it is an object of { <dim_api_code>: <option_api_code> }.
bookingArray of reservations. On write: [{ api_code, scheduled_at, end_at?, number? }]api_code is the reservation item; scheduled_at (and end_at) are ISO8601 date-time strings; number defaults to 1. For a weekly-schedule item send scheduled_at on the target day. For a per-day-of-week time-slot item send scheduled_at = day + slot start and end_at = day + slot end, matching one of the item's configured slots (quota_setting.daily_time_range_quotas[].start_time / end_time). item_name / time_range_code are server-derived and ignored on write. Send [] to clear. On read: [{ api_code, scheduled_at, end_at, number, item_name, time_range_code }].
linked_formOn write: string — the entry_token of an entry in the associated form, or null to clear. The server resolves the token against associated_form_token; an unknown token yields 422. On read: one of three shapes — (1) null if not linked; (2) { "deleted": true } if the linked entry has been deleted; (3) Object { entry_token, serial_number, associated_fields, display_fields } describing the linked entry, where associated_fields / display_fields map each api_code (from associated_field_api_codes / display_field_api_codes respectively) to that field's value, formatted per the linked field's own type (recursive — e.g. a date field renders as its naive wall-clock string, an attachment field renders as its array of file objects).
formulaThe computed result. A number, a naive date string (YYYY-MM-DD), or a string, depending on what the formula evaluates to.
page_breakNone — display-only field; never appears as an entry value.
descriptionNone — display-only field; never appears as an entry value.
Last modified on July 9, 2026