# Helicone request logged notifications on your phone

> Get a push notification for LLM requests logged by Helicone, with model, cost, tokens and latency, and a High-priority push when the provider returns an error.

- Company: Helicone (https://www.justpush.io/recipes/helicone)
- Event: `request` (Request)
- Tags: AI, Monitoring
- Install: https://studio.justpush.io/recipes/helicone/request
- Web page: https://www.justpush.io/recipes/helicone/request

## Setup

1. Click Install in Studio and sign in. The recipe is added to your account and you get a personal webhook URL.
2. In Helicone, open Webhooks and add a webhook with your webhook URL (shown in Studio after install) as the destination URL.
3. Set a Sample Rate and Property Filters so you only get the requests you care about (see the setup notes).
4. Save and send a test event.
5. Helicone sends this webhook for **every** logged request that passes its filters, so narrow it down:
6. **Property filters:** only send requests with a specific `Helicone-Property-*` header, e.g. tag the calls you care about with `Helicone-Property-Notify: true` and filter on it.
7. **Sample rate:** send only a percentage of requests.
8. Helicone's alerts (cost, error rate, latency) can only go to email or Slack, not to a webhook, so this recipe works per request.
9. Helicone signs requests with a `Helicone-Signature` header, but JustPush doesn't check it yet, so keep your endpoint URL private.

## Code

Studio calls `handleRequest(request)` with the incoming webhook (`{ method, headers, body, query, raw }`) and sends the message object it returns. Returning `null` sends nothing.

```js
// Helicone → request logged
// Fires after Helicone logs an LLM request that passes your webhook's sample rate and
// property filters. Every matching request pushes, so filter hard (see INSTALL.md).
// Docs: https://docs.helicone.ai/features/webhooks

// LLM calls often cost fractions of a cent: $0.0015, $0.12, $3.40.
function usd(value) {
    const n = Number(value)
    if (value == null || !Number.isFinite(n)) return null
    return "$" + (n > 0 && n < 0.01 ? n.toPrecision(2) : n.toFixed(2))
}

// request_body / response_body arrive as JSON strings (or a "too large" notice).
function parse(value) {
    if (typeof value !== "string") return value && typeof value === "object" ? value : null
    try {
        return JSON.parse(value)
    } catch {
        return null
    }
}

function handleRequest(request) {
    const body = request.body || {}

    // Guard: only Helicone request webhooks.
    if (!body.request_id) {
        console.log("Not a Helicone webhook — skipping")
        return null
    }

    const meta = body.metadata ?? {}
    const response = parse(body.response_body)
    // Providers report failures as an "error" object in the response body.
    const error = response?.error
    const reason = typeof error === "string" ? error : error?.message

    const model = body.model ?? "LLM"
    const provider = body.provider ? ` (${String(body.provider).toLowerCase()})` : ""
    const cost = usd(meta.cost)
    const tokens = Number.isFinite(Number(meta.totalTokens)) ? `${meta.totalTokens} tokens` : null
    const latency = Number.isFinite(Number(meta.latencyMs)) ? `${(Number(meta.latencyMs) / 1000).toFixed(1)}s` : null
    const stats = [cost, tokens, latency, body.user_id ? `user ${body.user_id}` : null].filter(Boolean)

    return {
        title: error ? `❌ ${model} request failed` : `🤖 ${model} request`,
        message: (reason ? `${reason} · ` : "") + (stats.join(" · ") || `Request ${body.request_id}`) + provider,
        topic: "Helicone",
        priority: error ? 1 : -1, // High for failures, Low for routine requests
    }
}
```

## Helicone request webhook payload (sample)

```json
{
  "model": "gpt-4o-mini",
  "user_id": "user-123",
  "metadata": {
    "cost": 0.0015,
    "latencyMs": 1200,
    "totalTokens": 25,
    "promptTokens": 10,
    "completionTokens": 15
  },
  "provider": "openai",
  "request_id": "550e8400-e29b-41d4-a716-446655440000",
  "request_body": "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"user\",\"content\":\"Hi\"}]}",
  "response_body": "{\"id\":\"chatcmpl-1\",\"object\":\"chat.completion\",\"choices\":[{\"message\":{\"role\":\"assistant\",\"content\":\"Hello!\"}}]}",
  "request_response_url": "https://s3.example.com/helicone/550e8400?signature=abc"
}
```

## FAQ

### Does this work on iPhone and Android?

Yes. Install the JustPush app from the App Store or Google Play and sign in. Every phone signed in to your account gets the notification.

### Do I need to write code?

No. Install the recipe in Studio, paste your webhook URL into Helicone and you are done. The code is there if you want to change the text, the sound or the buttons.

### Can I change what the notification says?

Yes. After install the recipe's code is yours. Edit it in Studio and test it against the sample payload before you save.

### What does it cost?

JustPush is free for 30 days. After that it's $19.99 a year, or $39.99 once. There is no extra charge for recipes.
