apex-spec v1.5.0
The Apex Spec
The event vocabulary your app fires through the snippet or SDK. Templates, journeys, and conversions read these names. Fireuser_signed_up when a person creates an account,waitlist_joined when they join a waitlist.
Your app
Events
119 declaredWhat your customer-facing app fires. Commerce, identity, engagement, communication — the vocabulary you stand up day one.
apex.track('user_signed_up', { method, referrer })Three nouns, one vocabulary
- The Apex Spec — the global contract on this page: every canonical event + attribute, shared by all merchants.
- Schema — your workspace's slice of the Spec: the events + attributes you've wired, plus any you define yourself.
- PLG event catalog — a convenience set of lifecycle events the SDK helps you fire; each one maps to a canonical Spec event.
Which revenue event do I use?
Several events carry a money value. Pick by where the truth lives, not by what's easiest to fire:
- Web / server commerce →
order_placed(the money-truth lane; fire it from your server). This is the dollar source of record. - Mobile in-app purchase →
in_app_purchase(store-verified). checkout_completedis the client-side mirror — great for funnel/UX analysis, but it can duplicate or be blocked, so don't use it as the revenue source of record whenorder_placedexists.
App events
What your customer-facing app fires. Field names are flat snake_case (e.g. product_id, order_id).
Commerce
Cart, checkout, and revenue. Drives attribution + abandonment journeys.
add_to_cart
Primary metricUser added a product to their cart.
- product_id*
- string
- prod_atlas_runner_blue_42
- product_name
- string
- Atlas Trail Runner
- value
- number
- 129.99
- cart_value
- number
- currency
- string
- USD
- quantity
- number
- 1
- item_count
- number
- cart_id
- string
- cart_9f2e1a
remove_from_cart
User removed a product from their cart.
- product_id*
- string
- prod_atlas_runner_blue_42
- product_name
- string
- Atlas Trail Runner
- value
- number
- 129.99
- currency
- string
- USD
- quantity
- number
- 1
- cart_id
- string
- cart_9f2e1a
product_view
User viewed a product detail screen.
- product_id*
- string
- prod_atlas_runner_blue_42
- product_name
- string
- Atlas Trail Runner
- category
- string
- Footwear / Running
- value
- number
- 129.99
- currency
- string
- USD
add_to_wishlist
User added a product to a wishlist or saved-for-later list.
- product_id*
- string
- prod_atlas_runner_blue_42
- product_name
- string
- Atlas Trail Runner
- value
- number
- 129.99
- currency
- string
- USD
cart_view
User viewed their cart. The funnel stage between add_to_cart and checkout_started (GA4's view_cart).
- value
- number
- 259.98
- currency
- string
- USD
- item_count
- number
- 2
- cart_id
- string
- cart_9f2e1a
cart_snapshot
Full cart state at a point in time — powers abandoned-cart recovery journeys with the exact items to recover.
- items*
- array
- value
- number
- 259.98
- currency
- string
- USD
- item_count
- number
- 2
- cart_id
- string
- cart_9f2e1a
checkout_started
Primary metricUser began the checkout flow.
- value
- number
- 259.98
- currency
- string
- USD
- item_count
- number
- 2
- cart_id
- string
- cart_9f2e1a
checkout_completed
Primary metricClient-side checkout success. The browser/app-side completion signal — `order_placed` (server) and `in_app_purchase` (IAP) remain the money-truth lanes when both exist.
- order_id
- string
- ord_2024_03_45891
- value*
- number
- 259.98
- currency*
- string
- USD
- item_count
- number
- 2
- products
- array
- items
- array
- cart_id
- string
- cost
- number
- subtotal
- number
- 244
- total
- number
- 259.98
- tax
- number
- 15.98
- shipping
- number
- 0
- handling
- number
- discount
- number
- coupon
- string
- account_id
- string
in_app_purchase
Primary metricRevenue event: user completed a purchase inside the app.
- order_id*
- string
- ord_2024_03_45891
- value*
- number
- 259.98
- currency*
- string
- USD
- product_id
- string
- prod_atlas_runner_blue_42
- product_name
- string
- Atlas Trail Runner
- transaction_id
- string
- txn_stripe_3PqXyZ
- products
- array
- items
- array
- is_restored
- boolean
- false
- cost
- number
- subtotal
- number
- total
- number
- tax
- number
- shipping
- number
- handling
- number
- discount
- number
- coupon
- string
- account_id
- string
purchase_refunded
Primary metricA prior purchase was refunded.
- order_id*
- string
- ord_2024_03_45891
- value*
- number
- 129.99
- currency*
- string
- USD
- reason
- string
- Customer requested refund within return window
- product_id
- string
- prod_atlas_runner_blue_42
- account_id
- string
subscription_event
Primary metricSubscription lifecycle transition (start, renew, cancel, trial conversion, etc).
- product_id*
- string
- atlas_pro_annual
- action*
- string
- start
- amount
- number
- 299
- currency
- string
- USD
- period_type
- string
- annual
- transaction_id
- string
- txn_stripe_3PqXyZ
- expires_at
- string
- 2027-05-21T00:00:00Z
- is_trial
- boolean
- false
- seat_count
- number
- 25
- account_id
- string
subscription_started
Primary metricA subscription began (first activation, including trial start). Renewals and plan changes flow through subscription_event.
- product_id*
- string
- atlas_pro_annual
- amount
- number
- 299
- currency
- string
- USD
- period_type
- string
- annual
- transaction_id
- string
- is_trial
- boolean
- false
- account_id
- string
subscription_canceled
Primary metricA subscription was canceled by the user or by billing failure. The churn moment win-back journeys trigger on.
- product_id*
- string
- atlas_pro_annual
- reason
- string
- user_canceled
- expires_at
- string
- 2027-05-21T00:00:00Z
- account_id
- string
payment_failed
Primary metricA subscription/invoice payment attempt failed. Triggers the dunning (payment-recovery) journey.
- invoice_id*
- string
- in_3PqXyZ
- amount*
- number
- 299
- currency*
- string
- USD
- subscription_id
- string
- sub_3PqXyZ
- transaction_id
- string
- txn_stripe_3PqXyZ
- attempt_number
- number
- 1
- next_retry_at
- string
- 2026-06-22T00:00:00Z
- update_payment_url
- string
- https://billing.example.com/update
- account_id
- string
payment_recovered
Primary metricA previously-failed payment succeeded on retry or after the customer updated billing. The dunning journey's goal/exit event.
- invoice_id*
- string
- in_3PqXyZ
- amount*
- number
- 299
- currency*
- string
- USD
- subscription_id
- string
- sub_3PqXyZ
- transaction_id
- string
- txn_stripe_3PqYZ2
- account_id
- string
order_placed
Primary metricAn order was placed (server-confirmed purchase). The money-truth lane: this is the dollar source of record for revenue and order-confirmation comms. Fire it from your server, not the browser.
- order_id*
- string
- ord_2024_03_45891
- value*
- number
- 129.99
- currency
- string
- USD
- item_count
- number
- 2
- product_name
- string
- Atlas Trail Runner
- order_url
- string
- /orders/ord_2024_03_45891
- products
- array
- cost
- number
- subtotal
- number
- total
- number
- tax
- number
- shipping
- number
- handling
- number
- discount
- number
- coupon
- string
- account_id
- string
Where this is used
first_sale_completed
A marketplace seller's first sale completed. Drives the seller-activation comm.
- order_id
- string
- ord_2024_03_45891
- value
- number
- 49.99
- currency
- string
- USD
- buyer_name
- string
- Alex Rivera
- product_name
- string
- Vintage Film Camera
- payout_days
- number
trial_expiring
Primary metricA trial is about to end (Stripe-style trial_will_end). Distinct from trial_expired, which fires after.
- plan
- string
- atlas_pro
- days_remaining
- number
- 3
- value_summary
- string
- built real momentum
trial_expired
Primary metricA trial ended without converting (distinct from trial_expiring, which fires BEFORE).
- plan
- string
- atlas_pro
invoice_paid
Primary metricAn invoice was paid successfully (normal billing success; distinct from payment_recovered).
- invoice_id*
- string
- in_3PqXyZ
- amount*
- number
- 299
- currency*
- string
- USD
- subscription_id
- string
- sub_3PqXyZ
- next_billing_date
- string
- 2026-07-20
subscription_renewed
Primary metricA subscription renewed for another period. The renewal moment (was subscription_event action=renew).
- product_id
- string
- atlas_pro_annual
- amount
- number
- 299
- currency
- string
- USD
- period_type
- string
- annual
- transaction_id
- string
subscription_upgraded
Primary metricA subscription moved to a higher plan or more seats (expansion). Carry the NEW recurring amount so MRR expansion is computable.
- product_id
- string
- atlas_pro_annual
- from_plan
- string
- Starter
- to_plan
- string
- Pro
- amount
- number
- 299
- currency
- string
- USD
- period_type
- string
- annual
- seat_count
- number
- 25
- account_id
- string
Where this is used
subscription_downgraded
Primary metricA subscription moved to a cheaper plan or fewer seats (contraction). Carry the NEW recurring amount so MRR contraction is computable.
- product_id
- string
- atlas_starter_monthly
- from_plan
- string
- Pro
- to_plan
- string
- Starter
- amount
- number
- 49
- currency
- string
- USD
- period_type
- string
- monthly
- seat_count
- number
- 5
- reason
- string
- seat_reduction
- account_id
- string
Where this is used
Identity
Sign-up, waitlist, invite, sign-in, and identity stitching.
user_signed_up
Primary metricA person signed up.
- method
- string
- referrer
- string
- https://google.com/search?q=atlas+running
Where this is used
waitlist_joined
Primary metricA person joined a waitlist.
- string
- ada@acme.com
- source
- string
- homepage
- waitlist_name
- string
- early_access
- referrer
- string
- https://acme.com/pricing
Where this is used
user_invited
Someone invited a person to join.
- inviter_name
- string
- Sarah Chen
- invitee_email
- string
- alex@example.com
- role
- string
- admin
- accept_url
- string
- https://app.example.com/invite/accept
Where this is used
user_invite_accepted
An invited person accepted and joined.
- member_name
- string
- Alex Rivera
- inviter_name
- string
- Sarah Chen
- role
- string
- admin
- invitee_email
- string
- alex@example.com
Where this is used
password_reset_requested
A person requested a password reset.
- string
- ada@acme.com
- reset_url
- string
Where this is used
user_signed_in
User authenticated into the app.
- method
- string
user_signed_out
User signed out of the app.
No payload fields required.
user_identified
Anonymous visitor was linked to a known user identity.
- user_id*
- string
- usr_atlas_8f3a92
- traits
- object
Lifecycle
Install, open, background, uninstall. Session foundation.
app_install
Primary metricFirst install of the app on this device.
No payload fields required.
app_open
Primary metricApp was foregrounded by the user. Foundational session signal.
- source
- string
- push_notification
app_background
App was backgrounded.
No payload fields required.
app_uninstall
App was uninstalled from the device (server-inferred from push silent failure).
No payload fields required.
app_crash
The native app crashed. A harm signal for mobile experiment guardrails.
- message
- string
- NSInvalidArgumentException
- stack
- string
- fatal
- boolean
- true
app_reinstall
App was reinstalled within the reinstall window.
No payload fields required.
user_churned
Primary metricA customer churned (lapsed/cancelled past the win-back window). Drives win-back.
- reason
- string
- stopped_using
user_reactivated
Primary metricA churned customer came back. Drives reactivation-welcome comms.
- inactive_days
- number
- 92
- changes_summary
- string
- New mobile app + faster checkout
Session
Explicit session boundaries with duration.
session_start
Beginning of a session (gap from last event > session timeout).
- session_id
- string
- sess_2026_05_21_abc123
session_end
End of a session (background or timeout).
- session_id
- string
- sess_2026_05_21_abc123
- duration_ms
- number
- 187320
Engagement
Page views, screens, searches, content interactions.
page_view
User viewed a screen or page. Canonical name across web and mobile.
- path
- string
- /products/atlas-runner
- title
- string
- Atlas Runner — Atlas Athletics
- referrer
- string
- https://google.com/search?q=atlas+running
pageview
Deprecated · use page_viewLegacy web pageview. Prefer `page_view` for new integrations.
- path
- string
- /products/atlas-runner
- title
- string
- Atlas Runner — Atlas Athletics
- referrer
- string
- https://google.com/search?q=atlas+running
screen_view
Mobile screen render. Equivalent to `page_view` for native screens.
- screen_name*
- string
- ProductDetail
- previous_screen
- string
- ProductList
search
User executed a search query.
- query*
- string
- trail running shoes
- results_count
- number
- 24
share
User shared content to an external surface.
- content_id
- string
- prod_atlas_runner_blue_42
- channel
- string
content_view
User viewed a piece of content (article, video, etc).
- content_id*
- string
- blog_2026_05_running_form_guide
- content_type
- string
- article
- duration_ms
- number
- 42500
form_submit
Form was submitted by the user.
- form_id
- string
- newsletter_signup
click
A click the snippet or SDK recorded. Prefer `ui_action` when you know the control's name. The snippet auto-fires this for outbound links.
- target
- string
- button#hero-cta
- href
- string
- https://partners.example.com/apply
- text
- string
- Apply now
ui_action
A named in-product control was used. One event for buttons, tabs, nav, widget chrome — distinguish with `action`, `element_type`, `name`, and `location`. Do not invent a new event per button.
- action*
- string
- click
- element_type
- string
- button
- name*
- string
- Wire it in Cursor
- location
- string
- setup.experiments
- href
- string
engagement
End-of-page composite: time on page and max scroll depth. Auto-fired by the web snippet on hide. Prefer `ui_action` / `page_view` for a readable journey.
- duration
- number
- 42
- scroll_depth
- number
- 75
heartbeat
Periodic heartbeat indicating the user is still active on a page.
No payload fields required.
rage_click
Multiple rapid clicks on the same element — frustration signal.
- target
- string
- button#submit-disabled
dead_click
A click that produced no observable effect after a short wait (no URL change, no mutation on the clicked node). Frustration signal. Not a click on a table row that then navigates.
- selector
- string
- div.banner-image
- text
- string
- Decorative hero
- x
- number
- y
- number
goal_conversion
Primary metricUser completed a defined conversion goal.
- goal_id*
- string
- demo_booked
- value
- number
- 25
Where this is used
onboarding_step_completed
User finished one step of a guided onboarding / activation flow. A proximal funnel signal — emit one per step from the client where the step happens.
- step_id
- string
- connect_data_source
- step_index
- number
- 2
- step_name
- string
- Connect a data source
Where this is used
feature_used
User used a specific product feature. Powers expansion + adoption comms.
- feature_name*
- string
- advanced_reports
- count
- number
- 1
webinar_registered
Primary metricUser registered for a webinar. A campaign conversion signal.
- webinar_topic
- string
- Scaling growth experiments
- webinar_date
- string
- 2026-07-10
survey_started
User began a survey (e.g. NPS).
- survey_id
- string
- nps_2026_q2
survey_completed
Primary metricUser completed a survey. A campaign conversion signal.
- survey_id
- string
- nps_2026_q2
- score
- number
- 9
report_viewed
User viewed a report or dashboard. A core SaaS engagement signal.
- report_id
- string
- rpt_8821
- report_name
- string
- Weekly performance
content_viewed
User viewed a piece of content (article, video, screen). A core engagement signal for content + mobile apps.
- content_id
- string
- cnt_4410
- content_type
- string
- video
task_completed
User completed a task / unit of work. A depth-of-use engagement signal.
- task_id
- string
- tsk_5567
- task_type
- string
- onboarding_step
api_request_completed
User's integration made a successful API request. The core active signal for API-first / developer products.
- endpoint
- string
- /v1/messages
- count
- number
- 1
Product
Product-led-growth outcomes: onboarding completion and activation.
onboarding_completed
User finished the onboarding flow. Source-of-truth milestone — emit server-side when onboarding state flips to complete.
- duration_ms
- number
- 420000
- steps_completed
- number
- 4
activated
Primary metricUser reached the activation / 'aha' milestone (the moment they got first value). The PLG north-star outcome. Emit server-side when the activation criterion is met.
- criterion
- string
- connected_first_integration
project_created
User created their first/Nth project or workspace. A common SaaS + agency activation milestone.
- project_id
- string
- prj_2231
- project_name
- string
- Q3 Launch
Marketing
Merchant-fired triggers that prompt a comm (price drop, restock, review request). Not goal-tier events.
price_dropped
Price dropped on a product a customer viewed or saved. Drives price-drop alerts.
- product_id
- string
- prod_atlas_runner_blue_42
- product_name*
- string
- Atlas Trail Runner
- old_price
- number
- 129.99
- new_price
- number
- 99.99
- discount_percent
- number
- currency
- string
- USD
- product_url
- string
- /products/atlas-trail-runner
restock_due
A back-in-stock / restock reminder is due for a product. Drives restock comms.
- product_id
- string
- prod_atlas_runner_blue_42
- product_name*
- string
- Atlas Trail Runner
- days_since_purchase
- number
- product_url
- string
- /products/atlas-trail-runner
review_request_due
A post-purchase review request is due. Drives review-request comms.
- product_id
- string
- prod_atlas_runner_blue_42
- product_name*
- string
- Atlas Trail Runner
- order_id
- string
- ord_2024_03_45891
- days_ago
- number
- review_url
- string
- /orders/ord_2024_03_45891/review
Fulfillment
Post-purchase shipping + delivery. Drives shipping + review-request comms.
order_shipped
A placed order shipped. Drives shipping-notification comms.
- order_id*
- string
- ord_2024_03_45891
- carrier
- string
- UPS
- tracking_url
- string
- https://ups.com/track?n=1Z999
- delivery_estimate
- string
- 2026-06-24
- shipped_at
- string
order_delivered
A shipped order was delivered. Drives review-request + post-purchase comms.
- order_id*
- string
- ord_2024_03_45891
- delivered_at
- string
- 2026-06-24T18:02:00Z
return_requested
A buyer asked to send goods back. Starts the returns story — distinct from purchase_refunded (money back).
- order_id*
- string
- ord_2024_03_45891
- product_id
- string
- prod_atlas_runner_blue_42
- reason
- string
- wrong_size
- quantity
- number
- 1
return_completed
Returned goods were received back. The return-rate numerator; fire purchase_refunded separately when money moves.
- order_id*
- string
- ord_2024_03_45891
- product_id
- string
- prod_atlas_runner_blue_42
- reason
- string
- wrong_size
- condition
- string
- resellable
- refunded
- boolean
- true
Marketplace
Seller + buyer lifecycle: signups, listings, payouts, reviews, trust badges.
seller_signup
Primary metricA seller joined the marketplace. The marketplace-side activation conversion.
- seller_id
- string
- sel_4821
- store_name
- string
- Atlas Outfitters
listing_created
A seller created a listing. Drives first-listing + activation nudges.
- listing_id
- string
- lst_99213
- product_name
- string
- Atlas Trail Runner
- price
- number
- 129.99
- currency
- string
- USD
buyer_review_requested
A buyer is due to review a marketplace purchase.
- order_id
- string
- ord_2024_03_45891
- product_name
- string
- Atlas Trail Runner
- seller_name
- string
- Atlas Outfitters
payout_sent
A seller payout was sent. Drives payout-confirmation comms.
- amount*
- number
- 482.5
- currency*
- string
- USD
- payout_id
- string
- po_8841
- transaction_count
- number
- 12
- payment_method
- string
- bank_transfer
- processing_days
- number
- 2
trust_badge_earned
A seller earned a trust badge (e.g. Top Rated).
- badge_name*
- string
- Top Rated Seller
listing_viewed
A buyer viewed a marketplace listing. A demand-side engagement signal.
- listing_id
- string
- lst_99213
- product_name
- string
- Atlas Trail Runner
message_sent
A user sent a message (buyer↔seller). A liquidity + engagement signal for marketplaces.
- thread_id
- string
- thr_7781
offer_submitted
A buyer submitted an offer / bid on a listing. A high-intent demand signal.
- listing_id
- string
- lst_99213
- amount
- number
- 110
- currency
- string
- USD
transaction_completed
Primary metricA marketplace transaction closed (buyer + seller). The two-sided activation/outcome moment.
- transaction_id
- string
- txn_55621
- amount
- number
- 129.99
- fee_amount
- number
- 15.6
- cost_amount
- number
- 4.1
- currency
- string
- USD
- buyer_id
- string
- u_buyer_812
- seller_id
- string
- sel_4821
- listing_id
- string
- lst_99213
- category
- string
- footwear
- geo
- string
- US
- price_band
- string
- 100-250
seller_viewed
A buyer viewed a seller's profile/storefront. A demand-side trust signal.
- seller_id
- string
- sel_4821
- store_name
- string
- Atlas Outfitters
item_saved
A buyer saved/favorited a listing. A mid-funnel demand signal.
- listing_id
- string
- lst_99213
- product_name
- string
- Atlas Trail Runner
inquiry_started
A buyer opened an inquiry/conversation about a listing. High-intent demand.
- listing_id
- string
- lst_99213
- thread_id
- string
- thr_7781
match_created
Supply and demand matched (offer accepted / booking confirmed) before payment. The liquidity moment for negotiated marketplaces.
- listing_id
- string
- lst_99213
- buyer_id
- string
- u_buyer_812
- seller_id
- string
- sel_4821
- amount
- number
- 110
- currency
- string
- USD
transaction_canceled
A marketplace transaction was canceled before fulfillment. The cancellation-rate numerator.
- transaction_id
- string
- txn_55621
- reason
- string
- out_of_stock
- canceled_by
- string
- seller
review_submitted
A post-transaction review was submitted. Powers average rating + review coverage (trust metrics).
- transaction_id
- string
- txn_55621
- listing_id
- string
- lst_99213
- rating
- number
- 5
- reviewer_side
- string
- buyer
dispute_opened
A buyer or seller opened a dispute on a transaction. The dispute-rate numerator (trust metric).
- transaction_id
- string
- txn_55621
- reason
- string
- item_not_as_described
- opened_by
- string
- buyer
Agency
Client lifecycle: onboarding, campaign milestones, renewals, new capabilities.
client_onboarded
Primary metricAn agency onboarded a new client. The agency-side activation conversion.
- client_id
- string
- cli_2231
- client_name
- string
- Northwind Co
- manager_name
- string
- Jordan Lee
campaign_milestone_reached
A client campaign hit a milestone. Drives results/update comms.
- campaign_id
- string
- cmp_5521
- campaign_name
- string
- Spring Launch
- milestone
- string
- 100 conversions
- business_impact
- string
- +$24k pipeline
contract_renewal_approaching
A client contract renewal is approaching. Drives renewal comms.
- contract_id
- string
- ct_7781
- days_remaining
- number
- 30
- renewal_date
- string
- 2026-07-20
- contract_period
- string
- annual
new_capability_launched
The agency launched a new capability/service. Drives announcement comms.
- capability_id
- string
- cap_312
- capability_name
- string
- Paid Social
- capability_description
- string
- Full-funnel paid social management
report_ready
A report is ready. Distinct from report_viewed, which is the person opening it.
- report_type
- string
- Monthly performance
- report_id
- string
- rpt_8821
- period
- string
- May 2026
- highlights
- string
- revenue up 12%
task_updated
An agency team member updated a task. A core agency activity signal.
- task_id
- string
- tsk_5567
- status
- string
- in_progress
asset_uploaded
A team member uploaded an asset/deliverable. A core agency activity + activation signal.
- asset_id
- string
- ast_3312
- asset_type
- string
- creative
comment_added
A user added a comment / collaboration note. A depth-of-use signal.
- target_id
- string
- ast_3312
time_logged
A team member logged time against a client/project. A core agency activity signal.
- minutes
- number
- 90
- project_id
- string
- prj_2231
client_report_viewed
A client viewed an agency results report. A retention + value-delivery signal.
- report_id
- string
- rpt_8821
- client_id
- string
- cli_2231
Loyalty
Loyalty + usage milestones that prompt reward and celebration comms.
loyalty_milestone_reached
A customer hit a loyalty milestone (points/tier). Drives reward comms.
- points
- number
- 5000
- reward
- string
- $50 credit
- milestone
- string
- Gold tier
usage_milestone_reached
A customer crossed a usage milestone. Drives celebratory + expansion comms.
- milestone
- string
- 1,000 events tracked
- percentile
- number
- 95
Communication
Push, email, in-app message delivery + interaction.
push_received
Device received a push notification (delivery confirmation).
- message_id
- string
- msg_2026_05_21_abc
- campaign_id
- string
- cmp_atlas_spring_2026
push_opened
User tapped/opened a push notification.
- message_id
- string
- msg_2026_05_21_abc
- campaign_id
- string
- cmp_atlas_spring_2026
- deep_link
- string
- atlas://product/atlas-runner
email_opened
Email open tracked via pixel.
- message_id
- string
- msg_2026_05_21_abc
- campaign_id
- string
- cmp_atlas_spring_2026
email_clicked
Link in email was clicked.
- message_id
- string
- msg_2026_05_21_abc
- campaign_id
- string
- cmp_atlas_spring_2026
- link
- string
- https://atlasathletics.com/products/atlas-runner
unsubscribed
Recipient unsubscribed from a message/list. A harm signal for messaging experiment guardrails.
- message_id
- string
- msg_2026_05_21_abc
- campaign_id
- string
- cmp_atlas_spring_2026
- list_id
- string
in_app_message_seen
In-app message was rendered to the user.
- message_id
- string
- msg_2026_05_21_abc
- campaign_id
- string
- cmp_atlas_spring_2026
in_app_message_clicked
User interacted with an in-app message CTA.
- message_id
- string
- msg_2026_05_21_abc
- campaign_id
- string
- cmp_atlas_spring_2026
- cta
- string
- upgrade_now
Deep links
Deferred + direct deep-link opens with attribution context.
deep_link_open
App opened via a deep link.
- url*
- string
- atlas://product/atlas-runner
- source
- string
- campaign_id
- string
- cmp_atlas_spring_2026
- referrer
- string
- https://atlasathletics.com
Attribution
Reattribution and reengagement signals.
reattribution
A re-install was matched to a prior install.
- partner_id
- string
- partner_facebook_ads
- original_install_id
- string
- inst_2025_11_xyz
reengagement
A returning user opened the app after a period of inactivity.
- partner_id
- string
- partner_email_winback
- inactive_days
- number
- 30
System
Custom events and internal lifecycle transitions.
custom
Custom event type. Stored with the original event name preserved in `data.eventName`. Use canonical events when possible.
No payload fields required.
lifecycle_transition
Internal Apex lifecycle/level transition event (not user-generated).
No payload fields required.
js_error
JavaScript runtime error captured by the web SDK.
- message
- string
- ReferenceError: window.atlas is not defined
- stack
- string
- at fn (https://atlasathletics.com/app.js:123:45)
Attributes
Identity + entity traits you set via identify() and reference in templates as {{first_name}} or {{order.total}}. Generated from the Spec, so this list never drifts.
user
| Field | Type | Description | Example |
|---|---|---|---|
| id | string | Stable end-user id passed to apex.identify(). | u_8c21 |
| emailPII | End-user email. Required for transactional sends. | alex@example.com | |
| email_verified | boolean | Whether the email has been confirmed. | true |
| first_name | string | Given name. Use in greetings. | Alex |
| last_name | string | Family name. | Rivera |
| full_name | string | Full display name. | Alex Rivera |
| username | string | Handle or login. | arivera |
| phonePII | string | Phone number in E.164 where possible. | +14155550100 |
| avatar_url | url | Profile image URL. | |
| title | string | Job title or role. | Head of Growth |
| company | string | Company the user belongs to. | Atlas |
| gender | string | Self-reported gender. | |
| birthdayPII | date | Date of birth. | 1990-04-12 |
| address_line1PII | string | Street address line 1. | 1 Market St |
| address_line2PII | string | Street address line 2. | Suite 400 |
| city | string | City. | San Francisco |
| region | string | State or province. | California |
| postal_codePII | string | Postal / ZIP code. | 94105 |
| country | string | Country display name. | United States |
| country_code | string | ISO 3166-1 alpha-2 country code. | US |
| latitudePII | number | Geo latitude. | 37.7749 |
| longitudePII | number | Geo longitude. | -122.4194 |
| timezone | string | IANA timezone. | America/Los_Angeles |
| locale | string | Locale or language. | en-US |
| created_at | date | When the user account was created. | 2026-01-15 |
| last_seen_at | date | Most recent activity timestamp. | 2026-06-01 |
| plan | string | Subscription plan or tier. | pro |
| subscription_status | string | Billing/subscription status. | active |
| lifecycle_stage | string | Merchant-defined relationship/funnel stage for this user (e.g. lead, trial, active, churned). Maps to the contact's lifecycle field on a verified identify (last-write-wins). | active |
| trial_ends_at | date | When the user's trial expires. | 2026-07-01 |
| lifetime_value | number | Total revenue from this user. | 480 |
| marketing_opt_in | boolean | Marketing email consent. | true |
| referrer | string | Acquisition referrer. | |
| utm_source | string | Acquisition UTM source. | newsletter |
| utm_medium | string | Acquisition UTM medium. | |
| utm_campaign | string | Acquisition UTM campaign. | spring_launch |
| utm_term | string | Acquisition UTM term. | |
| utm_content | string | Acquisition UTM content. | |
| marketplace_side | string | Which side(s) of the marketplace this user is on: buyer, seller, or both. | seller |
| is_seller | boolean | True when the user sells on the marketplace. | true |
| is_buyer | boolean | True when the user buys on the marketplace. | true |
| store_name | string | The seller's storefront display name. | Atlas Outfitters |
| seller_id | string | The marketplace's stable seller identifier. | sel_4821 |
| payout_method | string | How the seller receives payouts. One of: stripe, paypal, bank_transfer, other — never account details. | stripe |
account
| Field | Type | Description | Example |
|---|---|---|---|
| id | string | Stable account / org id. | acct_42 |
| name | string | Account or company name. | Atlas Inc |
| website | url | Account website. | https://atlas.example.com |
| domain | string | Email/company domain. | atlas.example.com |
| plan | string | Account plan or tier. | enterprise |
| mrr | number | Monthly recurring revenue. | 2400 |
| arr | number | Annual recurring revenue. | 28800 |
| seat_count | number | Number of licensed seats. | 25 |
| employee_count | number | Company headcount. | 120 |
| industry | string | Industry or vertical. | SaaS |
| country | string | Account country. | United States |
| created_at | date | When the account was created. | 2025-11-02 |
| trial_ends_at | date | When the account trial expires. | 2026-07-01 |
| renewal_date | date | Next renewal date. | 2027-01-01 |
| owner_emailPII | Account owner email. | owner@atlas.example.com |
order
| Field | Type | Description | Example |
|---|---|---|---|
| id | string | Order id or number. | ord_1009 |
| total | number | Order grand total. | 129.99 |
| subtotal | number | Order subtotal before tax/shipping. | 119.99 |
| tax | number | Tax amount. | 10.00 |
| shipping | number | Shipping cost. | 5.00 |
| discount | number | Discount amount applied. | 15.00 |
| cost | number | Order-level cost of goods (COGS) — optional. Send when you know the order's total cost but not per-item cost. Apex computes gross profit = net revenue − cost. Opt-in; never inferred. | 62.00 |
| currency | string | ISO 4217 currency code. | USD |
| status | string | Order / fulfillment status. | shipped |
| item_count | number | Number of line items. | 3 |
| coupon_code | string | Coupon / promo code used. | SPRING20 |
| payment_method | string | Payment method. | card |
| created_at | date | When the order was placed. | 2026-05-20 |
product
| Field | Type | Description | Example |
|---|---|---|---|
| id | string | Product id. | prod_77 |
| name | string | Product name. | Atlas Trail Runner |
| sku | string | Stock-keeping unit. | ATR-42 |
| brand | string | Brand or vendor. | Atlas |
| price | number | Unit price. | 129.99 |
| unit_cost | number | Per-unit cost of goods (COGS) — optional. Send it on EVERY line item of a purchase and Apex computes true gross profit (net revenue − cost × quantity) and reports LTGP:CAC alongside LTV:CAC. An order with an uncosted line is treated as cost-unknown rather than partially costed, so a half-instrumented catalog never inflates margins. Must be PER UNIT — Apex multiplies it by quantity. If you only know the total cost of the order, send `cost` at the order level instead. Opt-in; never inferred or defaulted. | 48.50 |
| currency | string | ISO 4217 currency code. | USD |
| category | string | Product category. | footwear |
| variant | string | Variant / option. | size-10 |
| quantity | number | Quantity. | 1 |
| image_url | url | Product image URL. | |
| product_url | url | Product page URL. |
Extend + build on the Spec
The Spec is the global contract — but you can extend it, get type-safe SDKs from it, and rely on it to validate your data.
Define your own events
When your business has an event the Spec doesn't cover, govern it: Settings → Workspace → Schema → Custom events, or ask your agent (the define_event MCP tool). A governed event is typed and versioned (SchemaVer model-revision-addition), behaves like a canonical event (trigger/goal-selectable, token-resolvable, validated at ingest), and can be scoped to one workspace or shared across your org. A custom name can never shadow a canonical Spec event.
Type-safe tracking
The TypeScript SDK ships a generated payload map so wrong payloads fail to compile:
import type { ApexEventPayloads } from "@apex-inc/sdk/generated/event-payloads";
const order: ApexEventPayloads["order_placed"] = {
order_id: "ord_123",
value: 129.99, // required — the money-truth lane needs the amount
currency: "USD",
};Validation rules
Spec fields can declare constraints — allowed-value enums, regex patterns, numeric bounds, and formats (e.g. currency must be ISO-4217). At ingest, payloads that violate a constraint are quarantined (or rejected in strict mode), so bad data is caught at the door instead of corrupting reports downstream.