Skip to main content

Field Mapping

Every input in a builder doc can carry a mapping. When the contact completes the flow, SendSeven writes the answer to the contact. You do not need any code for this. Every answer, mapped or not, is also delivered in the completion webhook and to automations.

{
"type": "TextInput",
"name": "email",
"label": "E-Mail",
"input_type": "email",
"required": true,
"mapping": { "target": "contact_field", "field": "email" }
}
targetWrites to
contact_fieldA standard contact field
custom_fieldA custom field
tagAdds tags
list_subscriptionSubscribes to lists (with consent)
variable_onlyNothing; the answer is only stored with the response

Write-back rules​

  • Empty answers never clear a value. An untouched optional field leaves the contact as it was.
  • Tags are only added, never removed.
  • The phone number is never writable. It identifies the contact on WhatsApp.
  • An e-mail address that belongs to another contact is not moved. The answer is kept in the response and reported as skipped (owned_by_other_contact).
  • A value that cannot be converted (for example an invalid e-mail) is skipped with a reason; the rest is still written.
  • Write-back is safe to repeat: subscriptions are idempotent, tags add-only, fields set-only.

The outcome of each write is reported in the writeback object.

Contact field​

{ "target": "contact_field", "field": "first_name" }
fieldAllowed componentsNotes
first_name, last_nameTextInput, TextArea, Dropdown, RadioButtonsGroupWhitespace is collapsed.
emailsameLower-cased and checked. Use input_type: "email" (otherwise warning mapping.email_input_type).
languagesameA language code such as de or de-AT.
birthdayDatePicker, CalendarPicker, TextInputISO date (YYYY-MM-DD).

Other components return mapping.wrong_component.

Custom field​

{ "target": "custom_field", "custom_field_id": "3f1c…" }

Only active custom fields marked as editable by contact can be filled (mapping.custom_field_unknown, mapping.custom_field_not_editable). The value is converted to the field's type (text, number, date, boolean, select). For select fields, use the custom_field_options resolver to show the field's real choices.

Tag​

{ "target": "tag", "tag_id": "b7d2…" }
  • tag_id: added when the answer is "truthy" (a ticked OptIn, a non-empty answer).
  • option_tags: for selection inputs (Dropdown, RadioButtonsGroup, CheckboxGroup, ChipsSelector), a map from option id to tag id. Each selected option adds its tag.
{
"type": "RadioButtonsGroup",
"name": "budget",
"label": "Budget",
"options": [
{ "id": "small", "title": "Unter 5.000 €" },
{ "id": "large", "title": "Über 5.000 €" }
],
"mapping": { "target": "tag", "option_tags": { "large": "tag_hot_lead" } }
}

Codes: mapping.tag_missing (neither set), mapping.tag_unknown, mapping.option_unknown, mapping.wrong_component (option_tags on a non-selection input).

List subscription​

List subscriptions need recorded consent. consent must be true and consent_text must contain the exact wording the contact agrees to. SendSeven stores a snapshot of this text, the flow version and the time with the subscription. Because the contact ticks the box themselves inside WhatsApp, no extra double opt-in message is sent.

Only an OptIn or a CheckboxGroup can subscribe (mapping.list_wrong_component).

OptIn: one list​

{
"type": "OptIn",
"name": "newsletter",
"label": "Ja, ich möchte den Newsletter erhalten",
"mapping": {
"target": "list_subscription",
"list_id": "a9c4…",
"consent": true,
"consent_text": "Ja, ich möchte den Newsletter per WhatsApp erhalten. Abmeldung jederzeit möglich.",
"consent_version": "2026-10"
}
}

An OptIn needs a list_id (mapping.list_missing).

CheckboxGroup: several lists​

Either map each option to a list with option_lists, or leave option_lists empty and use list ids as option ids, which is what the lists resolver produces:

{
"type": "CheckboxGroup",
"name": "topics",
"label": "Themen",
"options": "${data.lists}",
"init_value": "${data.subscribed}",
"mapping": {
"target": "list_subscription",
"mode": "sync",
"consent": true,
"consent_text": "Ich möchte zu den gewählten Themen Nachrichten per WhatsApp erhalten."
}
}
modeEffect
add (default)Ticked lists are subscribed. Nothing is unsubscribed.
syncTicked lists are subscribed, unticked lists that were offered are unsubscribed. Use it for a preference centre. CheckboxGroup only (mapping.sync_needs_checkbox).

Safety rules:

  • Only static and newsletter lists can be subscribed (list_type_not_allowed).
  • Only lists that were actually shown to the contact count (not_offered). A forged reply cannot subscribe to other lists.
  • sync only unsubscribes lists that were offered and are visible in the preference centre.

With static options and no option_lists, the validator warns mapping.option_ids_as_lists to remind you that the option ids must be list ids.

Tags on completion​

To tag every contact that completes the flow, regardless of the answers, use on_complete at the top level of the builder doc:

{ "on_complete": { "tag_ids": ["tag_lead_qualified"] } }

Variable only​

{ "target": "variable_only" }

No mapping, or variable_only, stores the answer only with the response. It is still in the webhook, the sessions API and automation variables.

PhotoPicker and DocumentPicker are always variable only (mapping.media_not_mappable). Uploaded files are stored with the response and listed in writeback.media.

Sensitive fields​

Add field names to a screen's sensitive list to hide them in WhatsApp's response summary on the contact's phone, for example a customer number or date of birth:

{ "id": "VERIFY", "title": "Identität", "sensitive": ["customer_number"], "components": [ … ] }

The sessions API and the whatsapp_flow.completed webhook mask these answers as •••• as well. Field mapping and automations inside SendSeven still receive the real values.