Agent API
The same search the site runs, addressed by a program. There is no account, no key and no invoice: the request pays for itself, so an agent that has never contacted us before can call it on its first try.
Endpoint
POST /api/agent/search?q=<query>&limit=<n>&lang=<code>&kind=<type>&min_users=<n>&max_users=<n> Parameters go in the query string, not in a body. The price is quoted by the payment layer, which sees the URL and nothing else, so a body would be priced for one request and answer another.
| Parameter | Required | Default | Meaning |
|---|---|---|---|
q | yes | — | The query. Matched by meaning as well as by name; @username returns that entity and similar ones. |
limit | no | 100 | Results wanted, 1 to 1000. Above 1000 is clamped, and priced at the clamped figure. |
lang | no | — | ISO 639-1 code, e.g. en, ru. |
kind | no | — | channel, group or bot. |
min_users | no | — | Lowest subscriber or member count. |
max_users | no | — | Highest subscriber or member count. |
Paying per request
Payment is the x402 protocol — HTTP 402, no keys and no subscription.
- Send the request with no payment header.
-
The reply is
402 Payment Requiredwith aPayment-Requiredheader: base64 of a JSON document naming the recipient, the token, the amount and the networks accepted. -
Authorise a payment matching one of them and repeat the request with a
Payment-Signatureheader. The authorisation is good for five minutes. -
On
200the payment settles on chain. On any error nothing is charged.
An x402 client library does all four steps for you: x402-fetch for JavaScript, x402-reqwest for Rust.
The price is a tier per hundred results asked for, rounded up, never fewer than one: ceil(limit / 100) × base, in USDC, on Base and on Solana. The base amount is
quoted in the 402 itself rather than printed here, so what an agent reads is
always what it will be charged. It is also in /.well-known/x402 and openapi.json,
both of which are free to read.
Response
200, application/json, an array in ranked order — the same shape /api/search returns. Empty is [], never null. Fields
with nothing in them are omitted rather than sent as null.
[
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"kind": "channel",
"username": "example_channel",
"name": "Example Channel",
"description": "An example Telegram channel",
"avatar_url": "https://semagram.io/avatar/example_channel.jpg",
"user_count": 15000
}
] | Field | Type | Meaning |
|---|---|---|
uuid | string | Stable identifier. Survives a rename; username does not. |
kind | string? | channel, group or bot. |
username | string | Telegram username, without the @. |
name | string? | Display name. |
bio | string? | Short bio. |
description | string? | Full description. |
avatar_url | string? | Avatar, served by us rather than by Telegram. |
user_count | number? | Subscribers or members, as of the last crawl. |
Errors
| Status | Meaning |
|---|---|
400 | q is missing or empty, or kind is not one of the three. |
402 | No payment, or one that did not settle. Read the Payment-Required header. |
502 | The search could not be answered. Retriable; nothing is charged. |
Example
import { wrapFetch } from "x402-fetch";
const fetch402 = wrapFetch(fetch, wallet);
const res = await fetch402(
"https://semagram.io/api/agent/search?q=crypto+news&limit=200",
{ method: "POST" },
);
const results = await res.json(); Model Context Protocol
/mcp serves the same catalogue as one tool, search, over streamable
HTTP. It takes the arguments above as a structured object rather than a query string, and
returns the same rows.
It is behind OAuth 2.0, so the first connection sends you through a browser once and the client keeps the token afterwards. Our authorization server registers clients by hand rather than on demand, so the client id has to be given along with the address — without it a client that expects to register itself will report that the server is incompatible:
claude mcp add --transport http --client-id semagram-mcp semagram https://mcp.semagram.io/mcp Any MCP client works the same way; only the flag's spelling changes. If yours offers no way to set a client id, it cannot connect yet — tell us which one it is.
Access is granted on request, and unlike the paid endpoint there is no self-service sign-up. Write to [email protected] with the client you will connect with and its client id, and you will be sent credentials.
Also
- agent-api.md — this page as one Markdown file, for a model to read.
- openapi.json — the OpenAPI description.
- /.well-known/x402 — the payment discovery document.
- x402 documentation — the protocol itself.