Get started

Errors, limits and paging

Ver em Markdown
Nesta página

What every response of the REST API has in common: one error shape, a rate limit with its headers, the same paging on every list, and a request ID.

Errors

A failed request answers an HTTP error status and this body:

json
{
  "error": {
    "type": "not_found",
    "code": "trend_not_found",
    "message": "Trend not found."
  }
}
  • type is the stable family. Branch on it.
  • code is the precise reason. New codes may appear; treat an unknown one by its type.
  • message is for people and logs. Its wording may change.
  • details is present on some errors, such as invalid parameters.
typeStatusWhen
invalid_request400A parameter is missing, malformed or out of range.
authentication401No key, or an unknown or revoked key.
permission403The key lacks the scope, or the account lacks API access.
not_found404No such trend, or the feed, article, folder or monitor is not the account's. Also an unknown path.
rate_limit429Over the per-minute limit, or the month's quota is spent.
server500Something failed on EarlyWave's side.

Codes you will meet

codetype
invalid_parametersinvalid_request
invalid_category, invalid_stage, invalid_reachinvalid_request
invalid_country, invalid_publisher_countryinvalid_request
missing_api_key, invalid_api_keyauthentication
missing_scope, feature_not_available, account_inactivepermission
trend_not_found, feed_not_found, article_not_found, category_not_found, monitor_not_foundnot_found
route_not_foundnot_found
rate_limit_exceededrate_limit
quota_exceededrate_limit
internal_error, auth_unavailableserver

Invalid parameters

Parameters are checked before anything runs. details lists every problem, one per parameter:

bash
curl "https://api.earlywave.ai/api/v1/trends?limit=500&sort=popular" \
  -H "Authorization: Bearer $EARLYWAVE_API_KEY"
json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_parameters",
    "message": "sort: Invalid option: expected one of \"signal\"|\"recent\"|\"sources\"; limit: Too big: expected number to be <=100",
    "details": [
      { "param": "sort", "message": "sort: Invalid option: expected one of \"signal\"|\"recent\"|\"sources\"" },
      { "param": "limit", "message": "limit: Too big: expected number to be <=100" }
    ]
  }
}

A few rules make parameters forgiving:

  • An empty value (?category=) counts as absent.
  • Unknown parameters are ignored.
  • Numbers may be sent as strings (limit=5); they are converted.
  • Comma-separated lists (category=politics,economy) are checked value by value: an unknown value answers invalid_category and lists the allowed ones.

Rate limit and monthly quota

Each plan sets two counters, shared by all the account's keys and by REST and MCP together: one REST call or one MCP tool call counts as one request.

PlanPer minutePer calendar month
Pro60 requests10,000 requests
Max300 requests50,000 requests

Minute windows are fixed: each one is a calendar minute, and the counter resets at the start of the next minute. The monthly quota resets on the 1st at 00:00 UTC. A refused request counts against neither. Every authenticated response carries:

HeaderMeaning
X-RateLimit-LimitRequests allowed per minute.
X-RateLimit-RemainingRequests left in the current minute.
X-RateLimit-ResetUnix time, in seconds, when the minute window resets.
X-Quota-LimitRequests allowed this calendar month (-1 on a contract without a monthly limit).
X-Quota-RemainingRequests left this month.
X-Quota-ResetUnix time, in seconds, of the 1st of next month.

Over either limit, the API answers 429 with error.type = "rate_limit" and a Retry-After header in seconds. The code says which counter refused: rate_limit_exceeded for the minute, quota_exceeded for the month.

http
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1792400460
X-Quota-Limit: 10000
X-Quota-Remaining: 8211
X-Quota-Reset: 1793577600

Wait Retry-After seconds, then retry; a spent month waits for the 1st, or a higher plan. On MCP, a tool call over a limit returns a tool error that names the counter; the assistant can retry after the minute ends.

Paging

Every list takes the same two parameters:

ParameterDefaultRange
limit201–100
offset00 and up

and answers limit, offset and has_more. Most lists also answer total, the number of matching results.

json
{ "trends": [ … ], "total": 37, "limit": 20, "offset": 0, "has_more": true }

To read everything, call again with offset + limit while has_more is true:

js
let offset = 0;
const all = [];
for (;;) {
  const res = await fetch(`https://api.earlywave.ai/api/v1/trends?country=FR&limit=100&offset=${offset}`, {
    headers: { Authorization: `Bearer ${process.env.EARLYWAVE_API_KEY}` },
  });
  const page = await res.json();
  all.push(...page.trends);
  if (!page.has_more) break;
  offset += page.limit;
}

A few operations differ:

  • GET /monitors and GET /categories return everything at once, with total.
  • GET /monitors/{monitor_id}/results takes limit but no offset. Narrow the period (days) or the text (query) instead.
  • GET /discover/keywords takes limit only.

Results can move between two calls: a trend gains articles and its rank changes. When you need one complete pass, narrow the filters so that a page of 100 holds everything, or page right away.

Request ID

Every response, success or error, carries an X-Request-Id header. Quote it when you report a problem: it points to that exact request in EarlyWave's logs.

Retrying

StatusRetry?
400, 401, 403, 404No. Fix the request, the key or the plan first.
429Yes, after Retry-After seconds.
500Yes, with a growing delay (1 s, 2 s, 4 s…), a few times at most.

Every operation is a read, so retrying a request never changes anything.