REST and ratelimits
Every REST call funnels through one RequestHandler. The helpers on Client and on structures (createMessage, editChannel, member.ban, ...) all use it.
Every REST call funnels through one RequestHandler. The helpers on Client and on structures (createMessage, editChannel, member.ban, ...) all use it.
Issuing requests
You normally call the typed helpers, not the handler directly. To reach an endpoint Athena has not wrapped:
import { Routes } from 'discord-api-types/v10';
const channel = await client.requestHandler.request('GET', Routes.channel(channelID), true);Signature: request(method, url, auth?, body?, file?, route?, short?). For GET/DELETE, body keys become the query string. auth: true adds the Authorization header.
File uploads
await client.createMessage(channelID, { content: 'Look' }, { file: buffer, name: 'a.png' });
await client.createMessage(channelID, { content: 'Look' }, [
{ file: b1, name: 'a.png' },
{ file: b2, name: 'b.png' }
]);MIME type is sniffed from the filename. Multiple files become files[0], files[1], etc.
Ratelimit model
Discord limits per route bucket. Athena tracks each route with its own sequential bucket, so same-route requests run strictly in order, and updates buckets from the X-RateLimit-* headers.
On a 429: it reads Retry-After (or X-RateLimit-Reset-After), engages a global block if the limit was global, and re-queues the request in a priority slot so it keeps its place.
Latency compensation
By default Athena tracks a rolling average of request latency and folds it into reset timing to absorb clock skew. Disable with rest.disableLatencyCompensation: true. rest.latencyThreshold (default 30000 ms) is where it warns about excessive latency.
Connection reuse
Athena defaults to a shared keep-alive HTTP(S) agent, so requests reuse connections instead of doing a fresh TLS handshake each time. This matters a lot at volume. Supplying your own rest.agent overrides it.
Force-queueing until ready
rest.forceQueueing: true holds authenticated requests until the first shardPreReady, avoiding a startup race against Discord's identify queue.
Retry behaviour
- 429: re-queued after the reset interval (with a clamp so a missing or malformed
Retry-Aftercannot cause a tight loop). - 502: up to 4 retries with random 100 to 2000 ms backoff.
- other 5xx: thrown as
DiscordHTTPError. - 4xx: thrown as
DiscordRESTErrorwith Discord's code and message. See Errors.
Tracing
client.on('rawREST', (e) => console.log(e.method, e.url, e.resp.statusCode, e.latency));Endpoints
Endpoints holds URL builders (for example Endpoints.CHANNEL_MESSAGES(channelID)) and CDN helpers. They return paths, not method-typed calls; response types come from discord-api-types.
Tips
- Always
awaitREST calls; forgetting it loses the ratelimit feedback path. - Prefer bulk endpoints (
bulkEditCommands) over loops. - Check the cache before REST:
channel.messages.get(id)is microseconds, the REST round trip is tens of milliseconds.