Skip to content

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": { ... }
}
FieldTypeDescription
eventIdstringUnique UUID. Use for idempotency.
eventTypestringOne of the event types below
timestampstringISO 8601 when the event was generated
appIdstringYour app ID
crownIdstringToken registration identifier (e.g., doge.arb). Wire field keeps the historical crown prefix for compatibility.
chainIdstringChain key (e.g., arb, sol)
crownConfigobjectPer-(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.
payloadobjectEvent-specific data

HTTP Headers

Each webhook request includes these headers:

HeaderDescription
Content-Typeapplication/json
X-App-Event-IDSame as eventId in the body
X-App-Event-TypeSame as eventType in the body
X-App-TimestampSame as timestamp in the body
X-App-SignatureHMAC-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:

  • symbol is currently the app's name (not the token's ticker symbol). Derive the token symbol from the envelope's crownId or look it up via the public API.
  • chainKey is emitted as an empty string. Use the envelope's chainId for chain routing.
  • config is currently the empty object; per-(token, app) config is delivered via the envelope's crownConfig field 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 }
}
FieldTypeDescription
crownIdstringToken registration ID the config belongs to
chainKeystringChain identifier
newConfigobjectThe 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 — previousConfig and configuredBy are 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 crownConfig field.

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:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 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.