Appearance
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"
}
]| Property | Values | Description |
|---|---|---|
owner | booking | property | contact | The model this field attaches to. |
key | ^[a-z0-9_]{1,64}$ | Identifier for this field within your app. Must be unique per owner type. |
type | string | number | boolean | date | Advisory type for display purposes. All values are stored as text. |
visibility | private | host | guest | Controls 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 12guest
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
notevalue 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
- Subscribe to
booking.checked_in(needsread_bookingsscope). - On delivery, generate a code with your lock provider.
- Call
metafieldSet(ownerType: "booking", ownerId: ..., key: "access_code", value: code). - Declare
"visibility": "guest"→ the code appears in the check-in email and in themes.
Guest screening — flag a booking
- Subscribe to
booking.confirmed(needsread_bookings,read_contactsscopes). - Submit the guest data to your screening provider.
- Store the result:
metafieldSet(ownerType: "booking", key: "screening_status", value: "approved"). - Declare
"visibility": "host"→ the host sees the verdict in the booking panel. - Optionally call
bookingFlagSetto show a colored badge (needswrite_bookings).
Dynamic pricing — annotate the booking with the pricing rationale
- Subscribe to
booking.confirmed. - Store a pricing note:
metafieldSet(ownerType: "booking", key: "pricing_note", value: "High demand period +15%"). - Declare
"visibility": "host"→ the host sees the rationale in the booking panel.