Appearance
Event Reference
The platform delivers events to your runner via HTTPS POST requests. Every event is wrapped in a standard envelope and signed with HMAC-SHA256.
Events are delivered to runners whose manifest subscribes to the event — the platform filters every dispatch against your manifest's runner.events list. Both the legacy short app.* and canonical wire token.app.* forms match each other, and an empty events list receives everything (back-compat). test.ping from runner verification is always delivered regardless of the list. See Event Subscriptions.
Event Envelope
Every event delivered to your runner has this structure:
json
{
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"eventType": "token.claimed",
"timestamp": "2025-01-15T10:30:00Z",
"appId": "my-app",
"crownId": "doge.arb",
"chainId": "arb",
"crownConfig": { "threshold": 0.05, "channel": "#alerts" },
"payload": { ... }
}| Field | Type | Description |
|---|---|---|
eventId | string | Unique UUID. Use for idempotency. |
eventType | string | One of the event types below |
timestamp | string | ISO 8601 when the event was generated |
appId | string | Your app ID |
crownId | string | Token registration identifier (e.g., doge.arb). Wire field keeps the historical crown prefix for compatibility. |
chainId | string | Chain key (e.g., arb, sol) |
crownConfig | object | Per-(token, app) user configuration. Set by the token owner via PUT /api/v2/registration/{id}/apps/{appId}/config. May be empty {} if not configured. Not present on test.ping delivery. |
payload | object | Event-specific data |
HTTP Headers
Each webhook request includes these headers:
| Header | Description |
|---|---|
Content-Type | application/json |
X-App-Event-ID | Same as eventId in the body |
X-App-Event-Type | Same as eventType in the body |
X-App-Timestamp | Same as timestamp in the body |
X-App-Signature | HMAC-SHA256 hex signature of the body |
Expected Response
Your runner must respond with:
json
{
"status": "ok"
}Or on error:
json
{
"status": "error",
"message": "Description of what went wrong"
}Timeout
Runners must respond within the configured timeout (default 30 seconds). Responses after the timeout are treated as failures.
Event Types
Implementation Status
Only token.app.enabled, token.app.disabled, token.app.configured, and test.ping are currently dispatched in production. The other event types below are part of the planned event catalog and are tagged Status: Planned. See Forward Compatibility for how to subscribe defensively.
Registration Lifecycle
token.claimed
Status: Planned
Not emitted yet.
A token registration was created.
json
{
"symbol": "DOGE",
"chainKey": "arb",
"ownerAddress": "0x1234...abcd",
"tokenAddress": "0xabcd...1234",
"tokenId": 42
}token.updated
Status: Planned
Not emitted yet.
Token registration metadata was changed.
json
{
"symbol": "DOGE",
"chainKey": "arb",
"changedFields": ["description", "tags", "socialLinks"]
}token.transferred
Status: Planned
Not emitted yet.
Token registration ownership transferred via the deal system.
json
{
"symbol": "DOGE",
"chainKey": "arb",
"previousOwner": "0x1234...abcd",
"newOwner": "0x5678...efgh",
"dealId": "deal-550e8400"
}Heartbeat
token.heartbeat.warning
Status: Planned
Not emitted yet.
Heartbeat score dropped below the threshold.
json
{
"symbol": "DOGE",
"chainKey": "arb",
"currentScore": 55,
"threshold": 60,
"daysBelowThreshold": 5
}token.heartbeat.inactive
Status: Planned
Not emitted yet.
Token registration became inactive due to low heartbeat score.
json
{
"symbol": "DOGE",
"chainKey": "arb",
"finalScore": 42,
"ownerAddress": "0x1234...abcd",
"claimable": true
}App Lifecycle
token.app.enabled
Status: Live
Dispatched from the developer handler when a token owner enables an app.
Your app was enabled on a token.
json
{
"symbol": "my-app",
"chainKey": "",
"enabledBy": "0x1234...abcd",
"config": {}
}Known caveats:
symbolis currently the app's name (not the token's ticker symbol). Derive the token symbol from the envelope'scrownIdor look it up via the public API.chainKeyis emitted as an empty string. Use the envelope'schainIdfor chain routing.configis currently the empty object; per-(token, app) config is delivered via the envelope'scrownConfigfield on subsequent events.
token.app.disabled
Status: Live
Dispatched from the developer handler when a token owner disables an app.
Your app was disabled on a token.
json
{
"symbol": "my-app",
"chainKey": "",
"disabledBy": "0x1234...abcd"
}Same symbol/chainKey caveats as token.app.enabled.
token.app.configured
Status: Live
Dispatched on every per-(token, app) config write (PUT /api/v2/registration/{id}/apps/{appId}/config).
App settings changed by the token owner.
json
{
"crownId": "42",
"chainKey": "arb",
"newConfig": { "alertPrice": 0.15 }
}| Field | Type | Description |
|---|---|---|
crownId | string | Token registration ID the config belongs to |
chainKey | string | Chain identifier |
newConfig | object | The freshly-written config, echoed so runners can act on the change without a separate GET round-trip |
Known caveats:
- The payload carries only the new config —
previousConfigandconfiguredByare not included. Keep your own last-seen copy if you need to diff. - Subsequent events for the token also deliver the current config via the envelope's
crownConfigfield.
Market
market.price.threshold
Status: Planned
Not emitted yet.
Token price crossed a configured threshold.
json
{
"symbol": "DOGE",
"chainKey": "arb",
"currentPrice": 0.105,
"thresholdPrice": 0.10,
"direction": "above",
"previousPrice": 0.098
}market.volume.spike
Status: Planned
Not emitted yet.
Unusual trading volume detected.
json
{
"symbol": "DOGE",
"chainKey": "arb",
"currentVolume": 5000000,
"averageVolume": 1200000,
"spikeMultiplier": 4.17
}Schedule
schedule.tick
Status: Planned
Not emitted yet.
Scheduled cron execution.
json
{
"schedule": "0 */6 * * *",
"scheduledAt": "2025-01-15T12:00:00Z",
"tickNumber": 42
}Cron Format
Use standard 5-field cron syntax: minute hour day-of-month month day-of-week. Example: 0 */6 * * * runs every 6 hours.
Test
test.ping
Status: Live
Dispatched during runner verification. Note: the test.ping envelope does NOT include crownConfig, only real events do.
Test event sent during runner verification.
json
{
"message": "Runner connectivity verification"
}Retry Policy
If your runner returns an error or doesn't respond in time, the platform retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
After all retries fail, the delivery is marked as failed.
Circuit Breaker
After 10 consecutive delivery failures, the platform opens a circuit breaker and stops delivering events. Use the verify endpoint to reset it.
Forward Compatibility
Your runner should handle unknown event types gracefully. When you receive an event type you don't recognize, log it and return {"status":"ok"}. This ensures your runner continues working as new event types are added.