GraphQL
Entorno de pruebas GraphQL
La misma API que REST, una sola petición para lo que necesita. Use una clave de prueba: se queda en esta pestaña y solo va a nuestra API.
Dónde está
- Consultas:
POST https://developers.aton-network.org/api/graphql - Suscripciones:
wss://developers.aton-network.org/api/graphql/ws(graphql-transport-ws) - Esquema, versión 2026-10-15: schema.graphql
- Flujo de eventos y webhooks: Descripción AsyncAPI
Cada campo es también una llamada REST, con el mismo permiso y la misma cuota. Una petición descuenta su coste de su cuota api, así que pedir dos cosas a la vez cuesta dos.
Límites
| Operaciones por petición | 1 (sin agrupar) |
| Coste por petición | 25 (cada campo que lee nuestra base de datos cuesta 1, la introspección 5) |
| Profundidad | 5 niveles (15 dentro de la introspección) |
| Campos seleccionados | 300, alias y fragmentos contados donde aparecen |
| Tamaño de la petición | 16 KB, 2000 tokens, variables 4 KB |
| Suscripciones | 5 por socket; 10 flujos de eventos por aplicación y entorno con Server-Sent Events, y 10 con WebSockets |
Errores
Cada error lleva extensions.code, el mismo código que responde REST cuando lo hay.
| Código | Estado | Por qué | Qué hacer |
|---|---|---|---|
| invalid_key | 401 | No se envió ninguna clave de API, o no es nuestra, ha caducado o se revocó. | Envíe una clave vigente como Authorization: Bearer ath_test_... o ath_live_... (por WebSocket, en el payload de connection_init). |
| missing_right | junto a los datos | La clave no tiene el permiso que necesita un campo. Ese campo es null; el resto de la respuesta está ahí. | Cree una clave con el permiso (app:read, usage:read, events:read) en el portal, o pida solo lo que esta clave puede leer. |
| not_found | junto a los datos | La aplicación de la clave se ha eliminado, o el id after de los eventos no es de esta aplicación o tiene más de 30 días. | Use una clave de una aplicación que siga existiendo; retome desde un id que recibió en los últimos 30 días, o empiece sin after. |
| rate_limited | 429 | Ha superado su cuota api de este minuto o día. Una petición descuenta su coste de la cuota; demasiados flujos de eventos abiertos también dan esta respuesta. | Espere los segundos de Retry-After. Pida menos campos que lleguen a la base de datos, o menos alias. |
| invalid_request | 400 | La petición no se pudo ejecutar: no es JSON, es un lote (un array), un error de sintaxis, un campo o argumento que el esquema no tiene, más de una operación sin operationName, o una suscripción enviada por HTTP. | Revise el mensaje; el esquema está en /graphql/schema.graphql. Envíe una operación por petición; las suscripciones van por el WebSocket. |
| query_too_complex | 400 | Se superó un límite: profundidad, campos seleccionados (alias y fragmentos contados donde aparecen), profundidad de introspección o coste. | Divida la petición, o pida menos de una vez. Los límites están en esta página. |
| persisted_query_not_found | 200 | Aún no conocemos el hash de una consulta persistida (mensaje PersistedQueryNotFound). | Vuelva a enviar la misma petición con la consulta además del hash; entonces se guarda y luego basta con el hash. |
| server_error | junto a los datos | Algo falló por nuestra parte. No se muestra nada al respecto. | Vuelva a intentarlo en un momento. Si sigue pasando, díganoslo en la página de soporte con la hora. |
Esquema
"""
Atheron developer API, GraphQL, version 2026-10-15. A field is never removed or changed in a way that breaks a client without first being marked @deprecated, with the date and what replaces it, at least six months before.
"""
schema {
query: Query
subscription: Subscription
}
"""The developer API, version 2026-10-15. Every field is a REST call too."""
type Query {
"""
Your application as registered, for this key's environment. Needs app:read. Same as GET /api/v1/app.
"""
app: App
"""
Calls, errors and latency per day and bucket, for this key's environment. Needs usage:read. Same as GET /api/v1/usage.
"""
usage(
"""1 to 90; anything else is brought within."""
days: Int = 7
): Usage
}
"""
Your application as registered, for the environment the API key belongs to. The same fields as GET /api/v1/app.
"""
type App {
"""The name people see on the consent screen."""
name: String!
"""Where the app is: development, review or live."""
state: String!
"""confidential (a server that keeps a secret) or public (PKCE only)."""
kind: String!
"""The quota tier: free, growth, scale or partner."""
quota: String!
"""The environment of this key."""
env: Environment!
"""The OAuth client ID for this environment."""
clientId: String!
"""The redirect addresses registered for this environment."""
redirectUris: [String!]!
"""The scopes this environment's client may ask for."""
scopes: [String!]!
"""The scopes review approved for live."""
approvedScopes: [String!]!
"""Your privacy policy, shown on the consent screen."""
privacyUrl: String
"""Your homepage, shown on the consent screen."""
homepageUrl: String
"""Client secrets and certificates in force."""
credentials: Int!
"""Named testers on the test client."""
testers: Int!
"""Webhooks for this environment."""
webhooks: Int!
}
"""Which of the app's two clients a key belongs to."""
enum Environment {
"""The test client: you, your team and up to 25 named testers."""
TEST
"""The live client, after review."""
LIVE
}
"""
Calls, errors and latency per day and bucket. The same answer as GET /api/v1/usage.
"""
type Usage {
"""The environment of this key."""
env: Environment!
"""How many days the answer covers, 1 to 90."""
days: Int!
"""One row per day and bucket, oldest first."""
usage: [UsageDay!]!
}
"""One day and bucket of calls. Days are UTC."""
type UsageDay {
"""The day, YYYY-MM-DD, UTC."""
day: String!
"""token, userinfo, userinfo:sensitive, api, sandbox or sign-in."""
bucket: String!
"""Requests counted. A GraphQL request counts as its cost."""
calls: Int!
"""Of those, how many failed."""
errors: Int!
"""Mean time taken, in milliseconds."""
msAvg: Int
"""Longest time taken, in milliseconds."""
msMax: Int!
}
"""
Events as they happen, over WebSocket (graphql-transport-ws). The same events as GET /api/v1/events and your webhooks.
"""
type Subscription {
"""
Events for this key's app and environment. Needs events:read. Same as GET /api/v1/events.
"""
events(
"""Only these kinds. All kinds when left out."""
types: [EventType!]
"""Resume after this event id (kept 30 days)."""
after: ID
): Event!
}
"""
One event, with the same five fields a webhook delivery's body carries.
"""
type Event {
"""The event's id. Send it back as after to resume."""
id: ID!
"""The kind of event."""
type: EventType!
"""When it was raised, ISO 8601."""
created: String!
"""The client it concerns."""
clientId: String!
"""What happened."""
data: EventData!
}
"""The kinds of event, as webhooks name them."""
enum EventType {
USER_SIGNED_IN
CONSENT_REVOKED
MEMBERSHIP_CHANGED
PING
}
"""
What happened. Which fields are present depends on the type, exactly as in a webhook's data.
"""
type EventData {
"""The person, as the sub claim your app was given. Absent for ping."""
sub: ID
"""user.signed_in: the scopes of this sign-in."""
scopes: [String!]
"""When it happened, ISO 8601."""
at: String
}