Skip to content

Metafields

Metafields are app-owned data fields that you attach to bookings, properties, or contacts. They let your app store structured data — access codes, screening verdicts, dynamic pricing notes, lock battery levels — directly against the platform record, rather than in your own database keyed by a Stayblox ID.

Platform surfaces then expose that data to the host (panel), to guests (email templates, themes), or keep it private — depending on the visibility you declare.

Define metafields in the manifest

Declare every field your app intends to write in the manifest's metafields array. The platform rejects writes to undeclared fields.

jsonc
"metafields": [
  {
    "owner": "booking",
    "key": "access_code",
    "type": "string",
    "visibility": "guest"
  },
  {
    "owner": "booking",
    "key": "screening_status",
    "type": "string",
    "visibility": "host"
  },
  {
    "owner": "property",
    "key": "lock_serial",
    "type": "string",
    "visibility": "private"
  }
]
PropertyValuesDescription
ownerbooking | property | contactThe model this field attaches to.
key^[a-z0-9_]{1,64}$Identifier for this field within your app. Must be unique per owner type.
typestring | number | boolean | dateAdvisory type for display purposes. All values are stored as text.
visibilityprivate | host | guestControls where the value is surfaced (see below).

Write and delete via the GraphQL API

Use metafieldSet and metafieldDelete. No extra scope is required beyond the owner's read scope (e.g. writing to a booking metafield needs read_bookings). Your app can only read and write its own metafields — other apps' fields are not visible.

Write a metafield

graphql
mutation SetAccessCode($bookingId: ID!, $code: String!) {
  metafieldSet(
    ownerType: "booking"
    ownerId: $bookingId
    key: "access_code"
    value: $code
  ) {
    metafield {
      key
      value
      type
      visibility
    }
    userErrors { field message }
  }
}
bash
curl -s https://app.stayblox.com/developer/api/2026-01/graphql \
  -H "Authorization: Bearer $STAYBLOX_APP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation($id: ID!, $v: String!){ metafieldSet(ownerType:\"booking\", ownerId:$id, key:\"access_code\", value:$v){ metafield{ key value } userErrors{ message } } }",
    "variables": { "id": "1234", "v": "7723-A" }
  }'

metafieldSet is an upsert — if the key already exists for this install + owner, it updates the value in place.

Delete a metafield

graphql
mutation DeleteLockSerial($propertyId: ID!) {
  metafieldDelete(
    ownerType: "property"
    ownerId: $propertyId
    key: "lock_serial"
  ) {
    deleted
    userErrors { field message }
  }
}

Read metafields

The metafields field is available on Booking, Property, and Contact types and returns only your app's own fields:

graphql
query BookingWithMetafields($id: ID!) {
  booking(id: $id) {
    id
    checkIn
    checkOut
    metafields {
      key
      value
      type
      visibility
    }
  }
}

Visibility and where values appear

private

Values are accessible only through the API. They never appear in the host panel or in any guest-facing surface. Use private for internal operational data (lock serial numbers, internal IDs, scoring intermediaries) that the host and guest don't need to see.

host

Values appear in an "App data" section on the relevant detail page in the host panel (booking detail, property detail, contact detail), grouped under your app's name. The host can see the key and value; they cannot edit them.

Useful for screening verdicts, risk scores, cleaning status, and any operational data the host should see at a glance:

Booking #1234
────────────────────────────────────
  Smart Lock Manager
    access_code        7723-A
    lock_battery_pct   84
  Screening Pro
    screening_status   approved
    risk_score         12

guest

All host display applies, plus:

1. Guest email templates. The value is available as a variable wherever booking variables are available in guest email templates. The variable key is metafields['{app-slug}.{key}']:

metafields['smart-lock-manager.access_code']

Use this to include an access code in check-in instructions:

Your access code for the property is: {{ metafields['smart-lock-manager.access_code'] }}

2. Twig themes. The app_data(booking) Twig function returns a map of all guest-visible metafields for a booking, keyed "{app-slug}.{field}":

twig
{% set app_data = app_data(booking) %}

{% if app_data['smart-lock-manager.access_code'] %}
  <p>Your access code: <strong>{{ app_data['smart-lock-manager.access_code'] }}</strong></p>
{% endif %}

Only fields with "visibility": "guest" are included; host and private fields are never returned by app_data(). See the Templating reference for full app_data documentation.

Isolation

Metafields are scoped per install. If two different apps both declare a metafield with owner: "booking" and key: "note":

  • Each app reads only its own note value via the API.
  • The host panel "App data" section shows each app's values under their respective app name.
  • Guest email variable and theme keys are namespaced by app slug ({app-slug}.note), so there's no collision.

A team's metafield data is also isolated by team — the TenantScope ensures an app can never read or write metafields for a team other than the one whose install token it's using.

Common patterns

Smart lock — deliver access code at check-in

  1. Subscribe to booking.checked_in (needs read_bookings scope).
  2. On delivery, generate a code with your lock provider.
  3. Call metafieldSet(ownerType: "booking", ownerId: ..., key: "access_code", value: code).
  4. Declare "visibility": "guest" → the code appears in the check-in email and in themes.

Guest screening — flag a booking

  1. Subscribe to booking.confirmed (needs read_bookings, read_contacts scopes).
  2. Submit the guest data to your screening provider.
  3. Store the result: metafieldSet(ownerType: "booking", key: "screening_status", value: "approved").
  4. Declare "visibility": "host" → the host sees the verdict in the booking panel.
  5. Optionally call bookingFlagSet to show a colored badge (needs write_bookings).

Dynamic pricing — annotate the booking with the pricing rationale

  1. Subscribe to booking.confirmed.
  2. Store a pricing note: metafieldSet(ownerType: "booking", key: "pricing_note", value: "High demand period +15%").
  3. Declare "visibility": "host" → the host sees the rationale in the booking panel.

© Stayblox — Developer Platform