Skip to content
Skip to main content

Use metadata in workflow templates

Last updated:

One booking email template can show a different logo for each of your customers. Store each customer’s logo URL in a hidden field on their Scheduler configuration. Read the URL in the template, and show a default logo when the URL is missing.

Which metadata can a workflow template read?

Section titled “Which metadata can a workflow template read?”

A workflow template can read custom values from 2 places. Scheduler bookings carry the configuration’s hidden metadata fields on all 5 booking.* triggers. Events carry their metadata object on event.created and event.updated.

The two share a name but work differently. An event’s metadata object is key-value data you write through the Events API. A Scheduler metadata field is a hidden field on the booking form: the scheduling page sends its value with each booking, and the guest can read it in the browser.

SourceWhere you set itTemplate variable
Scheduler bookingA type: "metadata" field in the configuration’s scheduler.additional_fieldsbooking_info.additional_fields.<key>
Eventmetadata on an Events API requestmetadata.<key>

Other objects that accept metadata aren’t a reliable source for customer email. Message workflows send to the grant owner. A message.created payload can arrive without the message’s metadata. Tracking triggers such as message.opened carry the message’s tracking label, not its metadata.

Add a metadata field to a Scheduler configuration

Section titled “Add a metadata field to a Scheduler configuration”

A Scheduler configuration has no top-level metadata object. Instead, add an entry to scheduler.additional_fields with type: "metadata" and the value in default. The scheduling page doesn’t show the field to the guest, but it sends the default value with each booking.

For a logo, host the image anywhere, such as your own storage or the customer’s website, and put its public URL in the field. Nylas stores only the URL.

PUT /v3/grants/{grant_id}/scheduling/configurations/{id} merges the body into the existing configuration. scheduler.additional_fields is the exception. The request replaces it as a whole, so include every field the configuration already has.

curl -X PUT "https://api.us.nylas.com/v3/grants/$GRANT_ID/scheduling/configurations/$CONFIGURATION_ID" \
-H "Authorization: Bearer $NYLAS_API_KEY" -H 'Content-Type: application/json' \
-d '{
"scheduler": {
"additional_fields": {
"notify_individually": {
"label": "Notify individually",
"type": "metadata",
"required": false,
"default": "true"
},
"logo_url": {
"label": "Logo URL",
"type": "metadata",
"required": false,
"default": "https://cdn.example.com/customers/acme/logo.png"
}
}
}
}'

Bookings made on a scheduling page get the value automatically. When a guest books through the hosted page or the nylas-scheduling component, the page sends each hidden metadata field’s default along with the guest’s answers. The component’s bookingInfo.additionalFields overrides the default, so 2 embeds of one configuration can pass 2 different logos.

If your own code creates bookings with POST /v3/scheduling/bookings, include the value in the request. The Bookings API doesn’t read default:

{
"start_time": 1790182800,
"end_time": 1790184600,
"guest": { "name": "Leyah Miller", "email": "[email protected]" },
"participants": [],
"additional_fields": {
"notify_individually": "true",
"logo_url": "https://cdn.example.com/customers/acme/logo.png"
}
}

The Bookings API checks that each key exists in the configuration and returns 400 Additional field '<key>' not found in configuration if it doesn’t. It doesn’t check the value.

Use the value in a template with a fallback

Section titled “Use the value in a template with a fallback”

Always include a fallback. A booking has no value in 3 cases: your code booked through the API without the value, the booking is older than the field, or the trigger is booking.reminder for a group event. That reminder sends additional_fields as null.

Templates render in strict mode, so a missing value stops the email from sending. Check additional_fields first, then check the key. Put the default in each {{else}}:

{{#if booking_info.additional_fields}}{{#if booking_info.additional_fields.logo_url}}
<img src="{{booking_info.additional_fields.logo_url}}" alt="Company logo" style="max-width: 150px;" />
{{else}}
<img src="https://cdn.example.com/brand/default-logo.png" alt="Company logo" style="max-width: 150px;" />
{{/if}}{{else}}
<img src="https://cdn.example.com/brand/default-logo.png" alt="Company logo" style="max-width: 150px;" />
{{/if}}

A booking with logo_url shows that logo in every copy of the email. A booking without it shows the default logo. The same pattern works for other values, such as a brand_color in an inline style.

Each booking keeps the values it was created with. If you change a field’s default, only new bookings get the new value.

An event.created or event.updated template reads event metadata at metadata.<key>. Each event holds up to 50 metadata pairs, with keys up to 40 characters and values up to 500. Check that metadata exists before you read a key, as in the booking example.

Two sets of keys have fixed meanings:

  • notify_individually: when the value is the string "true", the workflow sends one message per participant and fills in recipient. Any other value, including the boolean true, sends one message to all participants.
  • Keys Scheduler sets: events that Scheduler creates for non-group Configurations carry source (scheduler), key5 (the configuration ID), scheduler_last_start, scheduler_last_end, and scheduler_updated_at. Don’t overwrite them.

Which values are safe to store in metadata?

Section titled “Which values are safe to store in metadata?”

Store only values a guest could see and change without harm, such as logos, colors, and display names. Scheduling pages load the configuration’s hidden fields in the browser, so a guest can read them and change what the page submits.

Don’t use hidden fields for routing, pricing, authorization, or secrets. Workflows also can’t skip a send based on a field’s value. For values that must be authoritative, handle the booking webhook yourself. All 5 booking.* webhooks include configuration_id. Use it to look up the value in your own database.