Item Types

BriefGate items are typed. The agent declares what it needs; the client portal validates input in real time; get_intake_results returns data the agent can use directly without further parsing or type coercion.

Each item definition requires at minimum a key (unique within the intake), a label (shown to the client), and a type. Most types accept optional constraints that the portal enforces before the client can submit.

Who owes the item: assignee

Every item also has an assignee, which defaults to "client" — the thing the intake was created to collect.

Set "assignee": "owner" to put one of your own to-dos on the intake instead: "call the client", "register the domain", "book the photographer". An owner item

You tick it off in the dashboard, or with POST /v1/intakes/:id/items/:key/done. Use type: "boolean" for a plain tick-off task.

Because an owner item never reaches the portal, it cannot use the types that are submitted there: file, file_list, image and secret are rejected with assignee: "owner".

json
{
  "key": "call_client",
  "label": "Call the client about the launch date",
  "type": "boolean",
  "assignee": "owner"
}

text

A single-line text input. Use for short, structured strings such as tracking IDs, account names, or codes.

Constraints (inside constraints object)

Field Type Description
min_chars integer Minimum character count.
max_chars integer Maximum character count. Defaults to 2000 if not set.

Top-level item fields

Field Type Description
pattern string ECMAScript regular expression the value must match. Placed directly on the item definition, not inside constraints.

Example — Google Analytics tracking ID

json
{
  "key": "ga4_id",
  "label": "Google Analytics 4 Measurement ID",
  "help": "Found in GA4 > Admin > Data Streams. Format: G-XXXXXXXXXX",
  "type": "text",
  "required": true,
  "pattern": "^G-[A-Z0-9]+"
}

Returned by get_intake_results

json
"ga4_id": "G-K4M9X3R2B1"

longtext

A multi-paragraph textarea. Use for copy blocks, bios, mission statements, and any text where the client needs room to write.

Constraints

Field Type Description
min_chars integer Minimum character count.
max_chars integer Maximum character count. Defaults to 20000 if not set.

Example — hero section copy

json
{
  "key": "hero_copy",
  "label": "Homepage hero text",
  "help": "A short paragraph (up to 400 characters) that captures the spirit of the restaurant. Appears above the fold.",
  "type": "longtext",
  "required": true,
  "constraints": {
    "max_chars": 400
  }
}

Returned by get_intake_results

json
"hero_copy": "Since 1987, handcrafted Neapolitan pizza in the heart of the city. Come hungry, leave happy."

file

A single file upload. Use for documents, PDFs, spreadsheets, fonts, or any non-image binary.

Constraints

Field Type Description
formats string[] Allowed file extensions without the leading dot, e.g. ["pdf","docx"]. Case-insensitive.
max_bytes integer Maximum file size in bytes. Default is 52,428,800 (50 MB).

Example — signed contract

json
{
  "key": "signed_contract",
  "label": "Signed project contract",
  "help": "Upload the signed PDF you received by email.",
  "type": "file",
  "required": true,
  "constraints": {
    "formats": ["pdf"],
    "max_bytes": 10485760
  }
}

Returned by get_intake_results

json
"signed_contract": {
  "filename": "bella-napoli-contract-signed.pdf",
  "url": "https://files.briefgate.dev/in_8f3kQmR2/signed_contract.pdf?token=sig_abc&expires=1710615600",
  "mime": "application/pdf",
  "size": 283492,
  "checksum_sha256": "a3f2e1..."
}

The url is a signed URL valid for 24 hours. Fetch the file promptly or call get_intake_results again to obtain a fresh URL.


file_list

Multiple file uploads collected as a group. Use for photo galleries, asset packs, or any situation where you need several files of the same category.

Constraints

Field Type Description
formats string[] Allowed file extensions.
max_bytes integer Maximum size per individual file.
min_count integer Minimum number of files required.
max_count integer Maximum number of files accepted.

Example — restaurant photos

json
{
  "key": "photos",
  "label": "Food and interior photos",
  "help": "Upload between 5 and 15 photos of your food, interior, and ambience.",
  "type": "file_list",
  "required": true,
  "constraints": {
    "formats": ["jpg", "png", "heic"],
    "min_count": 5,
    "max_count": 15
  }
}

Returned by get_intake_results

json
"photos": [
  {
    "filename": "interior-01.jpg",
    "url": "https://files.briefgate.dev/in_8f3kQmR2/photos/interior-01.jpg?token=...",
    "mime": "image/jpeg",
    "size": 3204812,
    "checksum_sha256": "b4c1d2..."
  },
  {
    "filename": "pizza-margherita.jpg",
    "url": "https://files.briefgate.dev/in_8f3kQmR2/photos/pizza-margherita.jpg?token=...",
    "mime": "image/jpeg",
    "size": 2917034,
    "checksum_sha256": "f9e3a1..."
  }
]

image

An image upload with optional dimension and format constraints. Use instead of file when you need to enforce resolution or require transparency.

Constraints

Field Type Description
formats string[] Allowed file extensions, e.g. ["svg","png"]. No default — if omitted, any image file is accepted.
min_width integer Minimum image width in pixels. Ignored for svg uploads, which have no fixed pixel size.
max_width integer Maximum image width in pixels. Ignored for svg uploads.
min_height integer Minimum image height in pixels. Ignored for svg uploads.
max_height integer Maximum image height in pixels. Ignored for svg uploads.
max_bytes integer Maximum file size in bytes. Cannot exceed the account's upload size limit (default 52,428,800 / 50 MB) even if set higher.
transparent_background boolean If true, the portal warns the client if the image has no alpha channel.

Example — logo

json
{
  "key": "logo",
  "label": "Company logo",
  "help": "SVG or PNG with a transparent background. Minimum 512px on the shortest side.",
  "type": "image",
  "required": true,
  "constraints": {
    "formats": ["svg", "png"],
    "min_width": 512,
    "transparent_background": true
  }
}

Returned by get_intake_results

json
"logo": {
  "filename": "logo-transparent.png",
  "url": "https://files.briefgate.dev/in_8f3kQmR2/logo-transparent.png?token=...",
  "mime": "image/png",
  "width": 1024,
  "height": 512,
  "size": 48210
}

color_list

A color picker that collects one or more hex color values. The portal provides a visual color picker with hex input. The portal always validates that values are valid hex codes; every other constraint is optional.

Constraints (inside constraints object)

Field Type Description
min_count integer Minimum number of colors required.
max_count integer Maximum number of colors accepted. Defaults to 12 if not set.

Example — brand palette

json
{
  "key": "brand_colors",
  "label": "Brand colors",
  "help": "Select your primary and secondary brand colors. Add as many as you use.",
  "type": "color_list",
  "required": true
}

Returned by get_intake_results

json
"brand_colors": ["#1B2A4A", "#E8E2D9", "#C8382E"]

select

A dropdown or radio group where the client picks exactly one option from a list you define. Useful when you need a constrained vocabulary.

Required fields

Field Type Description
options array Array of {value, label} objects. value is what gets stored; label is what the client sees.

Example — website platform

json
{
  "key": "platform",
  "label": "Preferred website platform",
  "type": "select",
  "required": true,
  "options": [
    { "value": "wordpress", "label": "WordPress" },
    { "value": "webflow",   "label": "Webflow" },
    { "value": "shopify",   "label": "Shopify" },
    { "value": "custom",    "label": "Custom / I'm not sure" }
  ]
}

Returned by get_intake_results

json
"platform": "wordpress"

The result is always the value string, never the label.


multiselect

A checkbox group where the client picks any number of options from a list you define. Useful when the client may need to select more than one option, or none at all.

Required fields

Field Type Description
options array Array of {value, label} objects. value is what gets stored; label is what the client sees.

Constraints (inside constraints object)

Field Type Description
min_count integer Minimum number of options that must be selected.
max_count integer Maximum number of options that may be selected.

Example — services needed

json
{
  "key": "services_needed",
  "label": "Which services do you need?",
  "type": "multiselect",
  "required": true,
  "constraints": {
    "min_count": 1,
    "max_count": 3
  },
  "options": [
    { "value": "design",     "label": "Design" },
    { "value": "copywriting","label": "Copywriting" },
    { "value": "seo",        "label": "SEO" },
    { "value": "hosting",    "label": "Hosting" }
  ]
}

Returned by get_intake_results

json
"services_needed": ["design", "seo"]

The result is always an array of value strings, never the label, even when only one option is selected.


boolean

A yes/no toggle. The portal renders it as a pair of clearly labelled buttons or a checkbox, depending on the portal theme.

Example — existing website check

json
{
  "key": "has_existing_site",
  "label": "Do you have an existing website?",
  "type": "boolean",
  "required": true
}

Returned by get_intake_results

json
"has_existing_site": true

url

A URL input with built-in http/https validation. Optionally constrain to a specific domain or path pattern.

Top-level item fields

Field Type Description
pattern string ECMAScript regular expression the URL must match. Placed directly on the item definition, not inside constraints. Use to restrict to a specific domain.

Example — existing website URL

json
{
  "key": "existing_site_url",
  "label": "Existing website address",
  "help": "The full URL including https://",
  "type": "url",
  "required": false
}

Returned by get_intake_results

json
"existing_site_url": "https://old.bellanapoli.com"

secret

An encrypted credential input. The portal shows a password-style field with a lock icon and explicit messaging that the value is stored securely. The value travels over HTTPS and is sealed on the server with a libsodium sealed box before it is stored; it is never logged, indexed, or included in webhook payloads.

Secrets auto-expire after 30 days and can be revealed only once — with a short grace window (below) for a caller that never got the response.

Example — CMS admin login

json
{
  "key": "cms_credentials",
  "label": "WordPress admin credentials",
  "help": "Your current admin username and password. Stored encrypted and only accessible to your project team.",
  "type": "secret",
  "required": false
}

Returned by get_intake_results

On the first call, the decrypted plaintext is returned directly:

json
"cms_credentials": {
  "value": "username:password",
  "one_time": true,
  "first_reveal": true,
  "expires_at": "2024-04-15T10:22:00Z"
}

A call from the same API key within 5 minutes of the first reveal gets the same value again (a retry window for a response that never arrived). After that window, or from a different key, results.cms_credentials is null instead, and a companion meta.cms_credentials entry explains why:

json
"cms_credentials": null
json
"meta": {
  "cms_credentials": {
    "secret_unavailable": true,
    "reason": "Already revealed — secrets are one-time and cannot be shown again.",
    "revealed_at": "2024-04-15T09:10:00Z"
  }
}

Store the plaintext before proceeding — you cannot rely on retrieving it again.

Requires the secrets:read or admin scope on the API key.


structured

A JSON value matching a JSON Schema you define. The portal renders a dynamic form from the schema (simple flat schemas) or provides a JSON editor (complex or nested schemas). The submitted value is validated against the schema server-side before the item is accepted.

Required fields

Field Type Description
schema object A valid JSON Schema object, draft-07 (Ajv's default). Omit "$schema" or set it to the draft-07 meta-schema URI; a schema that declares "$schema": ".../2020-12/schema" fails to compile.

Example — opening hours

json
{
  "key": "opening_hours",
  "label": "Opening hours",
  "help": "Your regular weekly schedule. Use a simple time range like '12:00-22:00' or the word 'Closed'.",
  "type": "structured",
  "required": true,
  "schema": {
    "type": "object",
    "required": ["mon_fri", "sat", "sun"],
    "properties": {
      "mon_fri": { "type": "string", "title": "Monday to Friday", "example": "12:00-22:00" },
      "sat":     { "type": "string", "title": "Saturday",          "example": "12:00-23:00" },
      "sun":     { "type": "string", "title": "Sunday",            "example": "Closed" }
    }
  }
}

Returned by get_intake_results

json
"opening_hours": {
  "mon_fri": "12:00-22:00",
  "sat": "12:00-23:00",
  "sun": "13:00-21:00"
}

The returned object is guaranteed to conform to the declared schema.


Combining types: restaurant website example

The following items array covers the major item types in a realistic project:

json
[
  {
    "key": "logo",
    "label": "Restaurant logo",
    "type": "image",
    "required": true,
    "constraints": { "formats": ["svg","png"], "min_width": 512, "transparent_background": true }
  },
  {
    "key": "brand_colors",
    "label": "Brand colors",
    "type": "color_list",
    "required": true
  },
  {
    "key": "hero_copy",
    "label": "Hero section tagline",
    "type": "longtext",
    "required": true,
    "constraints": { "max_chars": 400 }
  },
  {
    "key": "ga4_id",
    "label": "Google Analytics 4 ID",
    "type": "text",
    "required": false,
    "pattern": "^G-[A-Z0-9]+"
  },
  {
    "key": "has_existing_site",
    "label": "Do you have an existing website?",
    "type": "boolean",
    "required": true
  },
  {
    "key": "existing_site_url",
    "label": "Existing website URL",
    "type": "url",
    "required": false
  },
  {
    "key": "platform",
    "label": "Preferred platform",
    "type": "select",
    "required": true,
    "options": [
      { "value": "wordpress", "label": "WordPress" },
      { "value": "webflow", "label": "Webflow" },
      { "value": "custom", "label": "Custom / I'm not sure" }
    ]
  },
  {
    "key": "cms_credentials",
    "label": "Existing CMS credentials",
    "type": "secret",
    "required": false
  },
  {
    "key": "menu_pdf",
    "label": "Menu (PDF)",
    "type": "file",
    "required": true,
    "constraints": { "formats": ["pdf"], "max_bytes": 10485760 }
  },
  {
    "key": "photos",
    "label": "Food and interior photos",
    "type": "file_list",
    "required": true,
    "constraints": { "formats": ["jpg","png","heic"], "min_count": 5, "max_count": 15 }
  },
  {
    "key": "opening_hours",
    "label": "Opening hours",
    "type": "structured",
    "required": true,
    "schema": {
      "type": "object",
      "required": ["mon_fri","sat","sun"],
      "properties": {
        "mon_fri": { "type": "string" },
        "sat":     { "type": "string" },
        "sun":     { "type": "string" }
      }
    }
  }
]

Validation

Validation is server-side and happens at upload time, before the item is marked submitted. The client receives immediate inline feedback in the portal if a file fails a constraint (wrong format, too small, below minimum count, pattern mismatch). They cannot submit an invalid item.

The agent's item definition — type, constraints, and schema — is the single source of truth. BriefGate does not infer constraints from file content or other heuristics. If you need to tighten constraints after an intake is live, use add_items to add a replacement item with a new key, then use request_revision to direct the client to the new field.