The manual.
How MotifEngine behaves today: the eight-step path from an empty workspace to a reward, the concepts that keep value honest, and the API shapes behind each one.
Quickstart
Create a workspace
Sign up from the console. Signup creates your workspace, its first environment, a starter plan and an integration credential in one flow.
Console → Create account workspace Acme Rewards environment Production → integration credential, shown once
Keep the key server-side
The raw integration key is returned only when it is created or rotated. Store it in your backend’s secret manager and never ship it in a browser bundle.
X-Motif-API-Key: <integration_key>
Register event contracts
Open Build → Events, or call the API. Contracts use a bounded JSON Schema subset and every registration creates a new immutable version.
POST /v1/admin/event-types { "name": "order.completed", "schema": { "type": "object", "required": ["order_id", "total", "currency"], "properties": { "order_id": {"type": "string"}, "total": {"type": "number", "minimum": 0}, "currency": {"type": "string"} } } }Define the catalog
From the Loyalty group, create only what the scenario needs: currencies, levels and XP thresholds, missions and achievements, free or paid rewards.
currencies loyalty, coins levels 1 Starter at 0 XP · 2 Regular at 250 XP missions lesson.completed × 5 rewards welcome_coupon · 100 loyalty
Publish an automation
Choose an event, add conditions, add one or more typed outcomes. Saving a draft and publishing are separate actions, so a draft never executes.
{ "event_type": "order.completed", "conditions": {"eq": ["$.payment_status", "paid"]}, "actions": [ {"type": "award_xp", "amount": 25}, {"type": "award_points", "currency": "loyalty", "amount": 10} ] }Send the fact
Your backend sends the event with a stable event id. 202 Accepted means the receipt and outbox row are committed, not that every effect has run.
curl -X POST $MOTIF/v1/events \ -H 'X-Motif-API-Key: <integration_key>' \ -H 'Content-Type: application/json' \ -d '{ "event_id": "order-1001-completed", "event_type": "order.completed", "user_id": "user-42", "payload": {"order_id": "order-1001", "total": 129.90, "currency": "USD", "payment_status": "paid"} }'Read the result
Check the receipt, then read the profile: balances, event count, mission progress, achievement progress and progression in one response.
GET /v1/events/order-1001-completed GET /v1/users/user-42/profile GET /v1/users/user-42/points/transactions
Inspect operations
The Overview workspace and the diagnostics endpoint show event counts, pending outbox rows, active rules, failed executions and failed redemptions.
GET /v1/admin/diagnostics GET /v1/admin/rule-executions GET /v1/admin/redemptions/{id}/attempts
Concepts
- Environment
- A boundary inside your workspace, such as sandbox or production.
- Integration credential
- A server-side key scoped to one environment.
- External user ID
- Your own stable customer id, mapped to MotifEngine state.
- Event
- A fact that happened in your product.
- Event contract
- An immutable, versioned payload schema.
- Rule
- A published when / if / then automation.
- Action
- A typed outcome: award_xp, award_points or log.
- Currency
- A spendable balance with its own policies.
- Ledger
- The append-only history behind every balance change.
- XP
- Non-spendable progression experience.
- Level
- A cumulative XP threshold and display name.
- Mission
- A count of matching events toward a target.
- Achievement
- A named milestone unlocked after a count of matching events.
- Reward
- A catalog item that is free or costs one active currency.
- Redemption
- One durable attempt to deliver a reward.
- Goal · Campaign
- Measurable targets and bounded event windows for reporting.
Rule language
Conditions are data, not executable customer code. Each condition object holds exactly one operator; paths use dot notation such as $.order.total. Trees are bounded to eight nesting levels, 64 nodes and 32 children per array.
| Operator | Meaning |
|---|---|
{} | Always matches |
all | Every child must match |
any | At least one child must match |
exists | The payload path exists |
eq · neq | Equal · not equal |
gt · gte · lt · lte | Numeric or string comparison |
| Action | Effect |
|---|---|
award_xp | Adds non-spendable XP to the external user. |
award_points | Appends an award entry to the named currency’s ledger. |
log | Records a rule action without changing user state. |
Events and contracts
Every event carries an event id. A repeated id returns the original receipt instead of creating a second event, so producers can retry safely.
Payloads are bounded and validated against the current contract version. A malformed payload returns 422 event_schema_mismatch instead of reaching the worker; accepted events keep the version they were received under.
202 Accepted receipt committed with an outbox row
422 event_schema_mismatch
GET /v1/events/{externalEventId} status of one receiptRules and schedule windows
Rules begin as drafts and only execute after a version is published. Editing a published rule creates a new immutable version; the old one stays readable for audit.
starts_at is inclusive, ends_at is exclusive, both are optional RFC 3339 timestamps. The worker checks the window at processing time, and every outcome uses its own ordinal in the idempotency key.
{
"name": "Weekend lesson bonus",
"event_type": "lesson.completed",
"conditions": {},
"actions": [
{"type": "award_xp", "amount": 25},
{"type": "award_points", "currency": "coins", "amount": 5}
],
"starts_at": "2026-10-17T00:00:00Z",
"ends_at": "2026-10-20T00:00:00Z"
}XP, levels, missions, achievements
XP is awarded by the award_xp action and accumulated per external user inside an environment. Level thresholds are cumulative and unique per environment.
Missions show a live count toward a target; achievements are durable recognition after a required count. They may listen to the same event and still remain separate concepts. Streaks read active UTC days.
GET /v1/users/user-42/progression
{
"total_xp": 275,
"level": 3,
"level_name": "Regular",
"next_level_xp": 500
}Points and the ledger
Each currency keeps an append-only ledger with expiring point lots and atomic spending. A correction is a new entry with its own idempotency key; the original row is never deleted.
Conversions move value between two currencies at a versioned rate in one operation. Transaction history is paginated with an opaque cursor.
POST /v1/users/{externalUserId}/points/transactions
{
"currency": "loyalty",
"amount": 100,
"type": "spend",
"idempotency_key": "refund-order-1001-loyalty-reversal"
}Rewards and recovery
A redemption reserves points, records every provider attempt and moves through explicit states. HTTP providers receive idempotency headers and may expose a status URL with a {redemption_id} placeholder.
Pending outcomes stay in delivering. Only a provider-confirmed failure releases reserved points; a retry reuses the durable redemption identity.
POST /v1/redemptions/{redemption_id}/retry
reserved → delivering → fulfilled
→ failed (points released)Access and identity
Console users work inside their own workspace; the console loads the workspace and its environment from the signed-in account.
Admin sessions are hashed and expire. Integration credentials are hashed, shown once, and can be rotated or revoked. Administrative actions are recorded in an append-only audit stream.
console user your workspace, signed in integration key one environment, server-side admin session hashed, expiring, revocable
Ready to wire it in?
Open the console(opens in a new tab)