/vibes

Send haptic feedback to users' ARKH Rings.

Quick Start: Target Yourself

Use @me as the user_app_id to send vibes to yourself. Perfect for testing and personal automation.

  • "Send a vibe to my ring"user_app_id: "@me"
  • "Buzz me"user_app_id: "@me"
  • "Target myself"user_app_id: "@me"

Quick Links

GET

/v1/vibes/patterns

List available patterns

POST

/v1/vibes/trigger

Send a vibe to a user

GET

/v1/events/:event_id/response

Poll for a notification response

GET

/v1/vibes/patterns

List available patterns

Request

curl -X GET "https://developer.arkh.com/api/vibes/patterns" \
  -H "Authorization: Bearer arkh_your_api_key_here"

Response

{
  "patterns": ["tap", "pulse"],
  "max_sequence_length": 3,
  "timing": {
    "min_delay_ms": 150,
    "max_delay_ms": 2000,
    "default_delay_ms": 300
  }
}
POST

/v1/vibes/trigger

Send a vibe to a user

Parameters

Name

Type

Req

Description

user_app_id

string

yes

The user-app ID from webhooks. Use @me to target yourself.

app_id

string

yes

Your app ID

sequence

array

yes

Array of up to 3 pattern steps. Each step has type ("tap" or "pulse") and optional delay_ms (150-2000ms). Default: 300ms.

message

string

Optional message to display (max 80 characters). Required when show_ring_ui_notif is true.

show_ring_ui_notif

boolean

When true, displays a 5-second Ring UI notification showing your app name and message. The notification appears on the Dynamic Island, Lock Screen, and in-app toast. Requires message to be set.

response_config

object

preferred_notification apps only. Configures the response UI shown to the user. type: "yes_no_dismiss" | "emoji" | "none". For emoji type, pass options: [{emoji, label}] with 2–5 items. Labels must be ≤15 chars (shown in Ring UI). If you exceed these limits, the API returns 200 with a warnings array describing what was truncated — no data is lost silently.

response_mode

string

How to receive the user's response. "webhook" (default) — fires notification.responded to your webhook URL. "poll" — returns immediately; use GET /events/:event_id/response to poll. "await" — holds the HTTP connection open until the user responds or timeout_ms elapses.

timeout_ms

number

await mode only. Milliseconds to hold the connection open. Default: 30000. Min: 5000. Max: 60000.

Request

curl -X POST "https://developer.arkh.com/api/vibes/trigger" \
  -H "Authorization: Bearer arkh_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "user_app_id": "@me",
    "app_id": "app_01234567",
    "sequence": [
      { "type": "tap" },
      { "type": "tap" },
      { "type": "pulse" }
    ],
    "message": "Order shipped!",
    "show_ring_ui_notif": true
  }'

Response

// webhook / poll mode (returns immediately):
{
  "success": true,
  "event_id": "731c520e-82a7-457a-ae18-7b5a866ba95a",
  "response_mode": "webhook",
  "delivery": {
    "method": "realtime",
    "status": "delivered",
    "latency_ms": 142,
    "app_state": "active"
  }
}

// await mode — user responded:
{
  "success": true,
  "event_id": "731c520e-82a7-457a-ae18-7b5a866ba95a",
  "response_mode": "await",
  "response": { "status": "responded", "value": "yes", "responded_at": "2026-02-25T14:30:05Z" }
}

// await mode — timed out:
{
  "success": true,
  "event_id": "731c520e-82a7-457a-ae18-7b5a866ba95a",
  "response_mode": "await",
  "response": { "status": "timeout", "value": null }
}

// await mode — user doesn't have notifications enabled (no slot, muted, ring off, app closed):
{
  "success": false,
  "event_id": null,
  "response_mode": "await",
  "response": { "status": "not_enabled", "value": null }
}

// webhook / poll mode — not_enabled (same user-side barriers):
{
  "success": false,
  "event_id": null,
  "response_mode": "webhook",
  "delivery_status": "not_enabled"
}

// With response_config warnings (200 OK, vibe was still sent — check warnings to fix your payload):
{
  "success": true,
  "event_id": "731c520e-82a7-457a-ae18-7b5a866ba95a",
  "response_mode": "webhook",
  "warnings": [
    "response_config.options had 6 items; max is 5. Truncated to first 5. Dropped: 🎉 (\"Party\"). Keep options to 5 or fewer.",
    "response_config label(s) exceeded 15-char limit and were truncated: 👍: \"Looks Good To Me\" → \"Looks Good To M\". Labels must be ≤15 chars to fit the Ring UI display."
  ]
}

Sequence Step Schema

Each step in the sequence array:
  • type (required, string): "tap" or "pulse"
  • delay_ms (optional, integer): Pause before this step (150-2000ms, default: 300ms)

Timing Constraints

  • Min delay: 150ms (accounts for motor spin-down + perception gap)
  • Max delay: 2000ms
  • Default: 300ms between steps if delay_ms not specified
  • Max sequence: 3 steps per vibe

Ring UI Notifications

Set show_ring_ui_notif: true to display a visual notification alongside the haptic:
  • Dynamic Island: Shows your app name and message in the expanded view
  • Lock Screen: Appears as a Live Activity notification
  • In-app: Shows as a toast overlay when the companion app is open
  • Auto-dismiss: Notification clears after 5 seconds
  • Message limit: 80 characters max

Requires message to be set. Perfect for confirmations like "Order shipped!" or "Payment received".

Double Delivery

The notification.responded webhook fires for every response regardless of response_mode. If your app has a webhook_url configured and you use await or poll, your server will receive both the inline/polled response and the webhook. Deduplicate using event_id, or leavewebhook_url blank if you only want inline delivery.

GET

/v1/events/:event_id/response

Poll for a notification response

Parameters

Name

Type

Req

Description

event_id

string

yes

The event_id returned from POST /vibes/trigger.

Request

curl -X GET "https://developer.arkh.com/api/events/731c520e-82a7-457a-ae18-7b5a866ba95a/response" \
  -H "Authorization: Bearer arkh_your_api_key_here"

Response

// Not yet responded:
{ "event_id": "731c520e-...", "status": "pending", "response": null, "responded_at": null }

// Responded:
{ "event_id": "731c520e-...", "status": "responded", "response": "yes", "responded_at": "2026-02-25T14:30:05Z" }

Error Responses

400

Invalid request (missing fields, invalid types, delay out of range). Also returned when @me is used but your API key is not linked to an ARKH user account.

403

User hasn't installed app or disabled vibes. When using @me, you must install the app on your own ring first.

404

App not found or not owned by you

429

Rate limit exceeded (max 30 vibes/user/minute, or 100 requests/60s per API key)