Appearance
Security & Auth
The app system uses a bidirectional authentication model: the platform signs events sent to your runner, and your runner signs actions sent to the platform. The same key material is used in both directions.
Authentication Methods
HMAC-SHA256 (Recommended)
The platform generates a shared secret during runner registration. Both sides use it for signing.
Inbound (platform -> runner):
- Platform computes
HMAC-SHA256(secret, requestBody) - Hex signature is sent in
X-App-Signatureheader - Runner verifies by computing the same HMAC and comparing
Outbound (runner -> platform):
- Runner computes
HMAC-SHA256(secret, requestBody) - Hex signature is sent in
X-App-Signatureheader - Platform verifies the signature
Bearer Token
Developer provides a static token during registration. The platform sends it as Authorization: Bearer {token}.
Custom Header
Developer specifies a header name and value during registration. The platform includes it on every request.
Recommendation
Use hmac-sha256 for the strongest security. It provides integrity verification (the body hasn't been tampered with) and authentication (the request came from the platform).
Permission Scopes
Actions are organized into three tiers based on their impact:
Read Scopes
Read-only access. Never requires approval.
| Scope | Description |
|---|---|
crown:read | Read token page data (registration, market, social, etc.) |
market:read | Read market data |
apps:read | Read app configurations |
Write Scopes
Modify data. Some may require approval based on token owner settings.
| Scope | Description | Approval |
|---|---|---|
crown:metadata:write | Update token metadata | Configurable |
apps:config:write | Update app config | Configurable |
apps:storage:write | Read/write app storage | Never |
notifications:send | Send notifications | Never |
Dangerous Scopes
High-impact actions. Always require explicit token owner approval.
| Scope | Description |
|---|---|
crown:transfer:initiate | Initiate registration ownership transfer |
crown:apps:manage | Enable/disable apps on a token |
Approval Flow
When a runner requests a dangerous action:
- Runner sends the action request
- Platform creates a pending approval and returns
approval_id - Token owner sees the approval in their dashboard
- Token owner approves or denies within 24 hours
- If approved, the platform executes the action
- If denied or expired, the action is discarded
Expiry
Pending approvals expire after 24 hours. The runner must re-request expired actions.
Audit Logging
Every action attempt is logged:
- Scope: 100% of action API calls (successful and failed)
- Retention: 90 days
- Immutable: Logs cannot be modified or deleted
Token owners can view the audit log in their dashboard or via the API:
GET /api/v2/registration/{id}/app-actionsAuthentication required: this endpoint is gated by the platform's wallet session auth — send Authorization: Bearer <JWT> for the token owner's or a manager's signed-in session. (An unauthenticated or wrong-wallet request returns 401/403; the action log reveals pending approvals, which is why it is not public.)
Query parameters:
| Parameter | Description |
|---|---|
appId | Filter by app |
action | Filter by action type |
status | Filter by status (completed, pending, denied, failed) |
since | ISO 8601 start date |
limit | Max results (default 50) |
Rate Limiting
Actions are rate-limited per runner with sliding windows, by category (Read / Write / Storage / Notifications / Dangerous). The limits, the rate-limit response headers, and 429 handling are documented in the Actions API.
Abuse Detection
The platform tracks rate limit violations. After 10 violations within 5 minutes, the runner is automatically suspended. Contact support to re-enable a suspended runner.
Storage Isolation
App storage is strictly isolated:
- App A cannot read App B's storage
- Storage keys are scoped to
(app_id, crown_id, key)tuples,crown_idis the platform's internal id for a token registration - Each app gets its own quota per token — quota amounts and per-request size limits are listed in the Actions API
Request bodies to the Action API are capped at 1 MB.
Best Practices
- Always verify signatures before processing webhooks
- Use constant-time comparison for signature verification (prevent timing attacks)
- Implement idempotency: events may be delivered more than once
- Handle unknown events gracefully: log and return
ok - Namespace metadata keys with your app ID (e.g.,
myApp_score) - Store secrets securely: use environment variables or secrets managers, never commit them
- Respect rate limits: read
Retry-Afterheaders and back off accordingly