Documentation

Send messages to your phone with a single curl command. No SDK required.

Quickstart

Get your first notification in under 60 seconds:

1. Sign up

Create an account at airlog.to. You'll get a channel with a unique slug.

2. Send a message

# Plain text
curl -d "Deploy completed successfully" https://airlog.to/your-slug

# JSON with level
curl -H "Content-Type: application/json" \
  -d '{"text":"CPU at 95%","level":"error","title":"Server Alert"}' \
  https://airlog.to/your-slug
[ Try it ]
curl -d "hello from docs" https://airlog.to/your-slug

3. Get notified

Messages appear instantly in the Airlog dashboard. Warnings and errors trigger push notifications.

Concepts

Channels — Each channel has a unique slug URL. Think of them as separate inboxes for different apps or services.

Messages — Text or JSON payloads sent to a channel. Each has a level (info, warn, error, critical).

Levels — Control notification behavior. Info is silent, warn triggers push, error adds badge, critical adds sound.

Authentication

Ingest (sending messages)

No authentication needed. Just POST to your channel's slug URL. The slug itself acts as an API key.

Tip: If your slug is compromised, use the rotate endpoint to generate a new one.

REST API (managing channels)

Requires a Bearer token from OAuth login.

curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  https://airlog.to/api/channels

Sign in flow:

  1. Redirect user to /auth/github or /auth/google
  2. After OAuth, user is redirected to /auth/callback?code=AUTH_CODE
  3. Exchange the code for a JWT:
POST/auth/token
curl -X POST -H "Content-Type: application/json" \
  -d '{"code":"AUTH_CODE"}' \
  https://airlog.to/auth/token

# Response
{ "token": "eyJhbGciOi..." }
Note: Auth codes are single-use and expire in 30 seconds.
GET/api/me

Get the authenticated user's profile.

curl -H "Authorization: Bearer TOKEN" https://airlog.to/api/me

# Response
{
  "id": "6e46bcc8-...",
  "email": "user@example.com",
  "name": "User Name",
  "plan": "free"
}

Send Message

POST/{slug}

Send a message to a channel. Auto-detects content type.

Plain text

curl -d "Server restarted" https://airlog.to/my-app

JSON

curl -H "Content-Type: application/json" \
  -d '{"text":"Disk usage 92%","level":"warn","title":"Storage"}' \
  https://airlog.to/my-app

Response

{
  "id": "9f05f0c6-...",
  "channel": "a1b2c3d4e5f6",
  "timestamp": "2026-03-15T12:00:00Z"
}

JSON Format

FieldTypeDescription
text requiredstringMessage body
level optionalstringinfo, warn, error, critical (default: info)
title optionalstringShort title for the message
tags optionalstring[]Tags for filtering
data optionalobjectArbitrary JSON metadata

Message Levels

LevelPushBadgeSoundUse case
infoNoNoNoDeploy logs, status updates
warnYesNoNoHigh memory, slow queries
errorYesYesNoFailed requests, exceptions
criticalYesYesYesServer down, data loss

Channels API

GET/api/channels

List all your channels. Requires auth.

# Response
[{
  "id": "5c50146a-...",
  "slug": "a1b2c3d4e5f6",
  "name": "my-app",
  "created_at": "2026-03-15T10:00:00Z"
}]
POST/api/channels

Create a new channel.

curl -X POST -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"my-app"}' \
  https://airlog.to/api/channels
POST/api/channels/{id}/rotate

Generate a new slug. Old slug stops working immediately.

DELETE/api/channels/{id}

Delete a channel and all its messages.

Members API

Invite team members to your channels with role-based access.

GET/api/channels/{id}/members

List all members of a channel.

POST/api/channels/{id}/members

Add a member to a channel.

curl -X POST -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"USER_ID","role":"viewer"}' \
  https://airlog.to/api/channels/{id}/members
RoleDescription
ownerFull control (creator)
editorCan manage channel settings
viewerRead-only access to messages
DELETE/api/channels/{id}/members/{userId}

Remove a member from a channel.

PATCH/api/channels/{id}/members/{userId}

Update a member's role.

Messages API

GET/api/channels/{id}/messages?limit=50&cursor=MSG_ID

List messages. Cursor-based pagination, newest first.

ParamTypeDescription
limit optionalintMax messages (default: 50, max: 100)
cursor optionalstringMessage ID for pagination
GET/api/messages/{id}

Get a single message by ID.

WebSocket

Connect to receive real-time messages:

const ws = new WebSocket(
  `wss://airlog.to/ws/channels/${channelId}?token=${token}`
);

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  console.log(msg.level, msg.text);
};

MCP (AI Tools)

Airlog ships an MCP server for Claude Code, Cursor, and other AI tools.

Install

# Install
go install github.com/airlog/airlog/cmd/mcp@latest

# Claude Code
claude mcp add airlog -e AIRLOG_USER_ID=YOUR_USER_ID -- airlog-mcp

# Cursor (.cursor/mcp.json)
{
  "mcpServers": {
    "airlog": {
      "command": "airlog-mcp",
      "env": { "AIRLOG_USER_ID": "YOUR_USER_ID" }
    }
  }
}

Available Tools

ToolDescription
airlog_sendSend a message to a channel
airlog_channelsList your channels
airlog_historyView recent messages
airlog_create_channelCreate a new channel

Examples

Shell script

#!/bin/bash
if pg_dump mydb > backup.sql; then
  curl -d "Backup completed ($(du -h backup.sql | cut -f1))" \
    https://airlog.to/ops
else
  curl -H "Content-Type: application/json" \
    -d '{"text":"Backup FAILED","level":"critical"}' \
    https://airlog.to/ops
fi

Python

import requests
requests.post("https://airlog.to/my-app", json={
    "text": "Payment failed",
    "level": "error",
    "title": "Stripe",
    "data": {"customer_id": "cus_123"}
})

Node.js

fetch("https://airlog.to/my-app", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    text: "Memory at 95%",
    level: "warn",
    tags: ["server-1"]
  })
});

GitHub Actions

# .github/workflows/deploy.yml
- name: Notify Airlog
  if: always()
  run: |
    if [ "${{ job.status }}" = "success" ]; then
      curl -d "Deploy ${{ github.sha }} succeeded" https://airlog.to/ops
    else
      curl -H "Content-Type: application/json" \
        -d '{"text":"Deploy failed","level":"critical","tags":["ci"]}' \
        https://airlog.to/ops
    fi

Rate Limits

PlanMessages/dayChannelsRetention
Free10037 days
Pro ($9/mo)10,000Unlimited90 days
Team ($29/mo)50,000Unlimited1 year

Rate limited responses return 429 Too Many Requests.

Errors

CodeMeaning
400Bad request — empty body or invalid JSON
401Unauthorized — missing or invalid Bearer token
404Channel not found — invalid slug
413Payload too large — body exceeds 64KB
429Rate limited — daily quota exceeded
500Internal server error

All errors return JSON: {"error": "description"}