API/Limits and errors

Limits and errors

The API's request limits and rate-limit headers, what every error code means, and the rules for periods, currencies, rounding and pages.

Request limits

LimitValue
Per minute60 requests
Per day10,000 requests

Both count for the whole account: all your keys and connected AI assistants together.

  • The minute limit refills continuously: one request comes back every second, up to 60.
  • The daily limit is a 24-hour window, not a calendar day. The X-RateLimit-Reset-Day header says when it ends.

Rate-limit headers

Every answer to a request with a valid key carries:

HeaderMeaning
X-RateLimit-LimitRequests allowed per minute (60)
X-RateLimit-RemainingRequests left right now
X-RateLimit-ResetSeconds until the minute limit is full again
X-RateLimit-Limit-DayRequests allowed per day (10,000)
X-RateLimit-Remaining-DayRequests left today
X-RateLimit-Reset-DaySeconds until the daily window ends

When a limit is reached, the answer is 429 rate_limited with a Retry-After header: wait that many seconds, then send the request again.

Every answer, error or not, also carries X-Request-Id.

The shape of an error

Errors follow the standard "problem details" format (application/problem+json):

{
  "type": "https://trueroyalties.com/docs/api/errors#invalid_request",
  "title": "Invalid request",
  "status": 400,
  "code": "invalid_request",
  "detail": "end_date must be on or after start_date.",
  "issues": [
    {
      "path": "end_date",
      "code": "invalid_value",
      "message": "end_date must be on or after start_date."
    }
  ],
  "request_id": "req_8fK2mQ7xLp3nR9sT1vWy"
}
  • Test code in your script. It never changes; detail is written for people and may be reworded.
  • issues lists each invalid parameter. It only appears on invalid_request.
  • Quote request_id when you contact support.

Error codes

invalid_request · 400 — A parameter is not valid: an unknown value, a date that does not exist, a period that is too long, a page cursor that is not ours. issues says which parameter and why.

api_key_in_query · 400 — The key was sent in the URL. Send it in the Authorization header, and revoke that key: it may already be in a log.

unauthorized · 401 — No key, or a key that is wrong or revoked. The answer does not say which, on purpose.

subscription_inactive · 403 — The account's subscription has ended. The API works again as soon as the subscription is active.

insufficient_scope · 403 — The key is not allowed to read. Every key created today can read, so you should never see this code.

not_found · 404 — There is no endpoint at this path, or the thing you asked for does not exist in your account. A series that belongs to another account gets the same answer.

wrong_host · 404 — The request went to trueroyalties.com. Use https://author.trueroyalties.com/api/v1.

method_not_allowed · 405 — The API only answers GET, because it is read-only. The Allow header lists what it accepts.

rate_limited · 429 — A limit is reached. Wait the number of seconds in Retry-After.

internal_error · 500 — Something failed on our side. Try again later; if it keeps happening, send us the request_id.

timeout · 504 — The answer took longer than 30 seconds. Ask for a shorter period.

Periods

The reports take either a relative range or two dates — never both.

  • range: today, yesterday, last_7_days, last_14_days, last_30_days, last_60_days, last_90_days, this_month, last_month, this_year, last_year, all_time. Without any period, you get last_30_days, like the dashboard.
  • start_date and end_date (YYYY-MM-DD, both days included) go together. A period can be up to 366 days long. An end date after today counts as today.
  • all_time only works on /reports/books.
  • timezone (for example Europe/Paris) decides which day is "today" for a range. Without it, the API uses UTC.

Every report returns the period it actually used. /account, /books and /series take no period.

Currencies and rounding

  • currency can be USD, GBP, EUR, JPY, CAD, INR, PLN, SEK, BRL, MXN or AUD. By default, your reporting currency (or USD if it is not one of these).
  • Amounts are numbers rounded to the currency's smallest unit: cents, or whole yen. Net profit is calculated before rounding, so the rounded lines of a report can differ from its rounded total by a cent.
  • Ratios are decimals: a margin of 0.25 means 25 %.
  • null means "does not exist", never zero. A margin without royalties is null, not 0.
  • Free downloads never count as royalties. They have their own endpoint, /free-units.

Filters and pages

  • Filters take comma-separated values: marketplaces=US,UK,DE. An unknown value is refused with 400 invalid_request, naming it. GB is accepted for the United Kingdom.
  • Long lists come in pages. limit sets the page size, from 1 to 100 (50 by default). When has_more is true, send next_cursor back as cursor to get the next page.