pex

Schema

Your Schema is the canonical catalog of the events and attributes your product sends to Apex: their names, types, descriptions, surface coverage, and whether Apex has actually seen them in your live data. It is the single source of truth that the communication composer, segments, and goals all read from, so a variable looks and resolves the same way everywhere you reach for it.

Find it at Settings → Workspace → Schema (/dashboard/settings/workspace/schema). It populates automatically from your apex.identify() and apex.track() calls. You review and curate it here; you do not have to build it by hand.

Canonical attributes

Every workspace ships with a canonical attribute registry in snake_case. These are the standard identity traits Apex recognizes, grouped by entity (User, Account, Order, Product):

CanonicalTypeCommon aliases Apex maps
first_namestringfirstName, fname, given_name
last_namestringlastName, family_name, surname
emailemailemailAddress, email_address
avatar_urlurlavatarUrl, photoUrl, image, profile_image
postal_codestringzip, zipcode, postalCode
country / country_codestringcountryName / countryCode
planstringplanName, tier, subscription_plan
lifetime_valuenumberltv, lifetimeValue
lifecycle_stagestringlifecycle, funnel_stage, stage, customer_stage

Custom attributes stay first-class. The registry only defines what Apex recognizes as canonical; anything else you send shows up as a custom field you can keep, describe, or map.

Aliasing: send what you have, reference one clean name

You do not have to rename your traits to use Apex. If your app sends firstName or zip, Apex maps them onto the canonical first_name and postal_code. The composer shows one clean canonical variable, and {{first_name}} resolves at send time no matter which alias the payload used.

// Your app can send either of these:
apex.identify("u_123", { firstName: "Alex", zip: "94105" });
apex.identify("u_123", { first_name: "Alex", postal_code: "94105" });

// In a template, you always reference the canonical name:
// "Hi {{first_name}}" → "Hi Alex"

Info

Prefer canonical snake_case names at the source. They skip the mapping step entirely, so your Schema stays clean and every variable is green from day one. The SDK exports a CanonicalUserTraits type for autocomplete.

Wired vs not wired

Apex marks each variable wired (green) once it has observed it in a real payload, and not wired (red) when it is a canonical field you have not sent yet.

This is observation-based, never code analysis. A variable turns green only after a real identify or track flows through POST /api/events. Green proves your instrumentation works end to end, not just that the code was written. There is no way to mark something wired without data flowing, by design.

In the composer's Variables panel and the {{ autocomplete, an unwired variable shows a red dot and a Set up link that deep-links into the right install step. Fire the event (or a test event) and the next read shows green.

Surfaces

Surface is a dimension of a variable, not a separate copy. A single attribute observed on both web and iOS carries web and ios coverage chips, so you can see at a glance where each event and attribute is actually flowing.

Mapping a non-canonical field

If your workspace already sends a non-canonical name and you want it to resolve under its canonical name, map it:

  • In the dashboard: Settings → Workspace → Schema, then click Map to <canonical> on the field.
  • Programmatically: POST /api/schema/map with { entityKey, fieldName, canonicalName } (pass canonicalName: null to clear).
  • From an AI agent (MCP): the map_attribute tool, and get_schema to inspect the current Schema and coverage.

Next steps