Documentation menu

REST API

Telegram Forwarding REST API Reference

All 102 routes the AutoTelegramForward control plane registers, grouped by subsystem, each with its verb, auth rule and a cURL example.

Verified against the checkout built for v2.2.4 · updated 20 Oct 2026

On this page

The control plane is a Go service that fronts the Python core. It owns authentication, tenancy, task CRUD, log history, dead-letter control and administration. Every route below is parsed out of api/main.go at build time, so this page cannot drift from the shipped binary.

102 endpoints68 require a token4 route groupsJSON in, JSON out

Where to go deeper

This page is the map. The four pages below are the territory: the full endpoint table with accepted fields, the response contract, the quota model and the durable-job lifecycle — each one grounded in the code that implements it rather than in a description of intent.

Authentication

Two schemes exist and they do different jobs. Clients (the web dashboard and the mobile app) obtain a session token from the public authentication routes and send it as a bearer token. Machines that call the API server-to-server can present a shared key instead.

Authentication schemes accepted by the control plane
SchemeHeaderUsed byBehaviour
Bearer tokenAuthorization: Bearer <token>Web dashboard, mobile app, atf auth token --saveResolves to an identity; every query is scoped to that numeric user id.
ATF_API_KEYX-API-Key: <key>Service-to-service automationOnly enforced when the key is configured on the server.
Init dataPOST /api/auth/tmaTelegram Mini AppThe signed WebApp init data is verified before a token is issued.
Log in and call an endpoint
# 1. Exchange credentials for a token
TOKEN=$(curl -s -X POST https://your-host/api/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"you@example.com","password":"…"}' \
  | grep -o '"token":"[^"]*"' | cut -d'"' -f4)

# 2. Read your own tasks
curl -s https://your-host/api/rules \
  -H "Authorization: Bearer $TOKEN"

# 3. Or use the CLI, which stores the token for you
atf auth token --save
atf auth whoami
Public readiness route (no token)
curl -s https://your-host/api/system/setup | jq

# {
#   "ready": true,
#   "version": "2.0.0",
#   "env": { "ATF_BOT_TOKEN": { "set": true } },
#   "services": { "core": true, "logger": true, "api": true, "web": true }
# }

# Ready verdict without probing the services:
curl -s 'https://your-host/api/system/setup?probe=0'

Conventions

  • Versioned aliases. Health and system routes answer on both /api/… and /api/v1/…; the dashboard uses the mirrored forms.
  • Partial updates are explicit. PATCH carries only what changes plus update_mask, which is the only way to set a field to false, zero or empty.
  • Optimistic concurrency. Updating a task bumps its version, so a stale writer is rejected instead of silently overwriting.
  • Correlation ids. Every response carries a correlation id that also appears in the log history, so an API call and its delivery can be joined.
  • Bounded reads. Log and queue queries page with limit / since rather than returning unbounded history.
  • Generated schema. The per-task settings surface publishes its own JSON schema at /api/rules/settings/schema, so editors can be built before any task exists.

Worked examples

Create a task with many sources and many targets
curl -s -X POST https://your-host/api/rules \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Market news → three channels",
    "source_chats": ["-1001111111111", "-1002222222222"],
    "target_chats": ["-1003333333333", "-1004444444444"],
    "settings": {
      "clean_links": true,
      "clean_mentions": true,
      "header_template": "📰 [[ORIGIN_NAME]]",
      "footer_template": "🔗 [[ORIGIN_LINK]]"
    }
  }'
Dry-run a rule before it goes live
curl -s -X POST https://your-host/api/simulate \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"rule_id":"<id>","text":"BUY NOW t.me/spam @channel #deal"}' | jq
Inspect history, then replay a dead-lettered job
curl -s "https://your-host/api/logs?level=ERROR&limit=50" \
  -H "Authorization: Bearer $TOKEN" | jq '.items[0]'

curl -s https://your-host/api/logs/stats -H "Authorization: Bearer $TOKEN" | jq

curl -s https://your-host/api/dlq -H "Authorization: Bearer $TOKEN" | jq '.items[].id'
curl -s -X POST https://your-host/api/dlq/<id>/retry \
  -H "Authorization: Bearer $TOKEN" | jq

Group highlights

System & readiness

  • GET /api/system/setupReady verdict, version, env contract and live service probes (booleans only)
  • GET /api/system/setup?probe=0The same verdict without probing the services
  • GET /api/system/envConfiguration contract: every key with set:true/false and a fix hint
  • GET /api/health/servicesPer-service reachability, latency and detail (core / logger / api / web)
  • GET /healthzLiveness probe used by the gateway and the upgrade gate

Tasks & rules

  • GET /api/rulesList the caller's tasks (tenant-scoped)
  • POST /api/rulesCreate a task with a source list, a target list and a content policy
  • GET /api/rules/{id}Read one task including its resolved settings
  • PUT /api/rules/{id}Update a task (optimistic concurrency, version bumped)
  • DELETE /api/rules/{id}Delete a task and its schedules
  • POST /api/rules/{id}/pausePause a task: queued jobs defer instead of failing
  • POST /api/rules/{id}/resumeResume a task and unblock retry-wait jobs
  • POST /api/rules/{id}/toggleEnable or disable a task
  • POST /api/simulateDry-run a message through a task and see the decision

Task lifecycle (async jobs)

  • GET /api/tasksList the caller's async jobs (state machine, tenant-scoped)
  • POST /api/tasksSubmit an async job (session backup, DLQ replay/purge, backup export); idempotent via idempotency_key
  • GET /api/tasks/{id}Poll one job: state, attempt, timestamps, structured error details
  • POST /api/tasks/{id}/cancelCancel a queued job before a worker claims it
  • POST /api/tasks/{id}/retryRe-queue a failed job (attempt budget reset)

Sessions

  • GET /api/sessionsList the caller's Telegram sessions
  • GET /api/sessions/{id}/chatsList the chats a session can see (sources and targets)
  • POST /api/sessions/{id}/backupExport an encrypted session backup
  • POST /api/backup/exportExport an encrypted backup of sessions and settings
  • POST /api/backup/importRestore from an encrypted backup
  • DELETE /api/sessions/{id}Terminate a session and purge its credentials

Filters & AI

  • GET /api/filtersList filter rules
  • POST /api/filtersCreate a filter rule
  • PUT /api/filters/{id}Update a filter rule
  • DELETE /api/filters/{id}Delete a filter rule
  • GET /api/ai-configsList AI rewrite configurations
  • POST /api/ai-configsCreate an AI configuration (provider, model, prompts)
  • PUT /api/ai-configs/{id}Update an AI configuration
  • POST /api/prompts/testSend sample text through a rewrite prompt

Observability

  • GET /api/logs?service=&level=&search=&limit=&since=Query attributable log history with bounded paging
  • GET /api/logs/statsAggregate counts by service and level
  • GET /api/logs/policyWhich levels and services the engine admits
  • POST /api/logs/purgePurge log history for one of the caller's own tasks (the installation-wide purge is administrator-only)
  • GET /api/statsDelivery throughput and outcome counters
  • GET /api/queueQueue depth and in-flight jobs
  • GET /api/dlqDead-lettered jobs
  • POST /api/dlq/{id}/retryReplay a dead-lettered job
  • DELETE /api/dlqPurge dead-lettered jobs for the caller scope (answers with the number removed)

Complete route table

All 102 registered routes, grouped by the mux that owns them and resolved through their mount prefixes. Host and scheme are yours; the paths are exact.

Service health & system · 12 routes

EndpointHandlerAuth
GET /api/health/servicesh.ServicesHealthPublic
GET /api/openapi.yamlh.OpenAPIDocPublic
GET /api/system/envh.EnvContractHandlerPublic
GET /api/system/setuph.SetupReportPublic
GET /api/v1/health/servicesh.ServicesHealthPublic
GET /api/v1/system/envh.EnvContractHandlerPublic
GET /api/v1/system/setuph.SetupReportPublic
GET /api/versionh.VersionPublic
GET /healthh.HealthPublic
GET /healthzh.HealthPublic
GET /readyh.ReadyPublic
GET /readyzh.ReadyPublic

Authentication · 7 routes

EndpointHandlerAuth
GET /api/auth/bot-login-linkh.AuthBotLoginLinkPublic
PATCH /api/auth/change-passwordh.AuthChangePasswordPublic
POST /api/auth/exchange-bot-tokenh.AuthBotExchangePublic
POST /api/auth/loginh.AuthLoginPublic
GET /api/auth/meh.AuthMePublic
POST /api/auth/registerh.AuthRegisterPublic
POST /api/auth/tmah.AuthTMAPublic

Authenticated control plane · 71 routes

EndpointHandlerAuth
GET /api/ai-configsh.ListAIConfigsBearer
POST /api/ai-configsh.CreateAIConfigBearer
PUT /api/ai-configs/{id}h.UpdateAIConfigBearer
DELETE /api/ai-configs/{id}h.DeleteAIConfigBearer
POST /api/ai-configs/check-keyh.CheckProviderKeyBearer
GET /api/ai-configs/providersh.ListAIProvidersBearer
GET /api/audit/eventsh.QueryAuditEventsBearer
POST /api/backup/exporth.BackupExportBearer
POST /api/backup/importh.BackupImportBearer
GET /api/bot-tokensh.ListBotTokensBearer
POST /api/bot-tokensh.CreateBotTokenBearer
DELETE /api/bot-tokens/{id}h.DeleteBotTokenBearer
GET /api/bot-tokens/{id}/defaultsh.GetBotDefaultsBearer
PUT /api/bot-tokens/{id}/defaultsh.SetBotDefaultsBearer
POST /api/client/credentialsh.ClientSaveCredentialsBearer
GET /api/client/settingsh.ClientGetSettingsBearer
GET /api/diagnosticsh.DiagnosticsBearer
GET /api/dlqh.ListDeadLetterBearer
DELETE /api/dlqh.PurgeDeadLetterBearer
POST /api/dlq/{id}/retryh.ReplayDeadLetterBearer
GET /api/filtersh.ListFiltersBearer
POST /api/filtersh.CreateFilterBearer
PUT /api/filters/{id}h.UpdateFilterBearer
DELETE /api/filters/{id}h.DeleteFilterBearer
GET /api/logsh.QueryLogsBearer
POST /api/logs/diagnostics/starth.RequireAdmin(http.HandlerFunc(h.LogDiagnosticsStart))Public
POST /api/logs/diagnostics/stoph.RequireAdmin(http.HandlerFunc(h.LogDiagnosticsStop))Public
GET /api/logs/exporth.ExportLogsBearer
GET /api/logs/healthh.LoggingHealthBearer
GET /api/logs/policyh.LogPolicyBearer
PUT /api/logs/policyh.RequireAdmin(http.HandlerFunc(h.LogPolicyUpdate))Public
POST /api/logs/purgeh.PurgeLogsBearer
GET /api/logs/statsh.LogStatsBearer
GET /api/promptsh.ListPromptTemplatesBearer
POST /api/promptsh.CreatePromptTemplateBearer
PUT /api/prompts/{id}h.UpdatePromptTemplateBearer
DELETE /api/prompts/{id}h.DeletePromptTemplateBearer
POST /api/prompts/testh.TestPromptBearer
GET /api/pv-responderh.GetPVResponderBearer
POST /api/pv-responderh.SetPVResponderBearer
PUT /api/pv-responderh.SetPVResponderBearer
GET /api/queueh.DeliveryStatsBearer
GET /api/rulesh.ListRulesBearer
POST /api/rulesh.CreateRuleBearer
GET /api/rules/{id}h.GetRuleBearer
PUT /api/rules/{id}h.UpdateRuleBearer
PATCH /api/rules/{id}h.UpdateRuleBearer
DELETE /api/rules/{id}h.DeleteRuleBearer
POST /api/rules/{id}/duplicateh.DuplicateRuleBearer
GET /api/rules/{id}/logsh.RuleLogsBearer
POST /api/rules/{id}/pauseh.PauseRuleBearer
POST /api/rules/{id}/restarth.RestartRuleBearer
POST /api/rules/{id}/resumeh.ResumeRuleBearer
POST /api/rules/{id}/route-pathh.RoutePathQuickSetBearer
GET /api/rules/{id}/settingsh.GetRuleSettingsBearer
PUT /api/rules/{id}/settingsh.UpdateRuleSettingsBearer
PATCH /api/rules/{id}/settingsh.UpdateRuleSettingsBearer
POST /api/rules/{id}/stoph.StopRuleBearer
POST /api/rules/{id}/toggleh.ToggleRuleBearer
GET /api/rules/settings/schemah.GetRuleSettingsSchemaBearer
GET /api/sessionsh.ListSessionsBearer
DELETE /api/sessions/{id}h.TerminateSessionBearer
POST /api/sessions/{id}/backuph.BackupSessionBearer
GET /api/sessions/{sessionId}/chatsh.ListChatsBearer
POST /api/simulateh.TestRuleBearer
GET /api/statsh.GetStatsBearer
GET /api/tasksh.ListTasksBearer
POST /api/tasksh.CreateTaskBearer
GET /api/tasks/{id}h.GetTaskBearer
POST /api/tasks/{id}/cancelh.CancelTaskBearer
POST /api/tasks/{id}/retryh.RetryTaskBearer

Administration · 12 routes

EndpointHandlerAuth
GET /api/admin/adminsh.AdminListAdminsPublic
POST /api/admin/adminsh.AdminAddAdminPublic
DELETE /api/admin/admins/{id}h.AdminRemoveAdminPublic
POST /api/admin/broadcasth.AdminBroadcastPublic
GET /api/admin/extensionsh.AdminListExtensionsPublic
POST /api/admin/extensions/{id}/toggleh.AdminToggleExtensionPublic
GET /api/admin/overviewh.AdminOverviewPublic
GET /api/admin/ratelimith.RateLimitStatusPublic
GET /api/admin/settingsh.AdminGetSettingsPublic
POST /api/admin/settingsh.AdminSaveSettingsPublic
GET /api/admin/usersh.AdminListUsersPublic
POST /api/admin/users/{id}/statush.AdminSetUserStatusPublic

Delivery lifecycle

Every delivery moves through these states, and the same vocabulary is used by the queue API, the log history and the dashboard. Jobs in RETRY_WAIT are the ones a pause defers rather than fails.

  • RECEIVED
  • VALIDATING
  • AUTHORIZED
  • ACCEPTED
  • IN_PROGRESS
  • RETRY_WAIT
  • SUCCEEDED
  • FAILED
  • CANCELLED
  • OUTCOME_UNCONFIRMED

Errors & status codes

Status codes returned by the control plane
CodeWhenWhat to do
200Success.Read the JSON body.
400The body or query is malformed.Check the settings schema and the environment contract.
401Missing, expired or unverifiable token.Log in again, or run atf auth whoami.
403Administration route called without admin rights.Use an administrator account.
404The resource does not exist — or does not belong to you.Ownership failures deliberately look identical to missing rows.
409A concurrent update moved the version first.Re-read the task, re-apply your change.
422A setting was rejected by validation.Read the field error in the response body.
502The logger or core service is unreachable.Check /api/health/services and atf doctor.