API reference
every endpoint, explained
Parameters, request examples and responses for every v3 resource, made from the OpenAPI spec.
Base URLhttps://gorest.co.in/public/v3This is v3, the current version. The v2 reference or the Swagger UI.
Change stream
Your own changes as they happen, as Server-Sent Events. Read it with fetch or curl -N and your token, or with a browser EventSource and a single use ticket from POST /stream/tickets.
Stream your changes
GET/public/v3/stream/changesEvery create, update and delete in your own v3 data, as Server-Sent Events (text/event-stream), within about a second of the commit. Sample rows never change, so they send nothing. Each event has an id, an event name and one data line of JSON:
• ready: the stream is open. Read the data you show now; every change from here on comes as an event.
• change: one row was created, updated or deleted. data is a ChangeEvent; read the row at href for its new state.
• reset: your data changed as a whole (a reset of your data) or the stream lost its place. Read the data you show again.
A comment line : heartbeat comes every 25 seconds. The stream ends after 30 minutes, at the token's end, when the token is revoked, or when the server restarts; connect again after retry milliseconds and send the last id you got as Last-Event-ID. Within 5 minutes you get the events you missed, else reset. An event may come twice after a reconnect; drop one you have seen by its id. At most 3 streams per token and 10 per account on each server.
A browser EventSource cannot send a header: get a ticket from POST /stream/tickets and open ?ticket=<ticket>, with &last-event-id=<id> to resume. A ticket works once, also when the connect is refused (a 429, for one), so get a new one before every connect. Needs a token with stream:read.
Parameters
- Last-Event-IDheader, stringoptional
- The
idof the last event you got, to resume. - last-event-idquery, stringoptional
- The same as the
Last-Event-IDheader, forEventSourcewith a ticket; the header wins when both come.
curl "https://gorest.co.in/public/v3/stream/changes" \ -H "Authorization: Bearer YOUR_TOKEN"
id: 019a3c4e-7b10-7d2a-9c4e-2f1b6a8d0e55
event: change
data: {"resource":"posts","action":"updated","id":"019a3c4e-1111-7d2a-9c4e-2f1b6a8d0e55","version":2,"href":"/public/v3/posts/019a3c4e-1111-7d2a-9c4e-2f1b6a8d0e55"}
Get a stream ticket
POST/public/v3/stream/ticketsA ticket for one GET /stream/changes?ticket=<ticket>, for a browser EventSource, which cannot send the token in a header. It works once, within 60 seconds, and only on the stream; the stream then checks the token that made it, as for a Bearer call. Never put your API token in a URL; a ticket is made to go there. Needs a token with stream:read.
curl -X POST "https://gorest.co.in/public/v3/stream/tickets" \ -H "Authorization: Bearer YOUR_TOKEN"
{
"ticket": "string",
"expires_at": "2026-10-31T09:30:00Z"
}Authentication
Most reads need no token: you see the read only sample data. With a token you also see your own rows. Writes, and the access tokens, my data and change stream calls, need a token with the scope the call names, such as users:write. Make a token on the tokens page after you log in.
- Authorization: Bearer YOUR_TOKEN
- The only way to send a token in v3. A token never goes in the URL.
No token or a wrong one gives 401 with WWW-Authenticate. A token without the scope gives 403 with error="insufficient_scope". Sample rows (read_only: true) cannot be changed.
Pagination
A list answers {"data": [...], "meta": {...}}, 25 items by default. Set page[size] from 1 to 100. For the next page send page[after] with meta.next_cursor; the same link is in the Link header.
- meta.has_more
- true when there is a next page.
- meta.next_cursor
- Send it as page[after] for the next page; null on the last one.
- meta.total
- Only with page[count]=true, or with page[number].
- page[number]
- Offset paging from 1 to 10,000, in place of page[after].
- Link
- rel="next", "prev", "first" and, for offset paging, "last" (RFC 8288).
Rate limits
Every answer carries the IETF rate limit fields. A token has its own limit, 300 calls a minute by default (1 to 600, set on the tokens page). With no token, an IP gets 120 calls a minute. Past the limit you get 429 with Retry-After.
- RateLimit-Policy
- The limit and its window, for example "token";q=300;w=60.
- RateLimit
- Calls left and the seconds until the window resets.
- Retry-After
- On a 429: the seconds to wait.
Errors and status codes
- 200 OK
- The item or the list is in the body.
- 201 Created
- The new item is in the body, and Location has its URL.
- 204 No Content
- A delete worked. The body is empty.
- 304 Not Modified
- Your copy (If-None-Match with the ETag) is still good.
- 400 Bad Request
- A parameter is wrong, unknown or out of range.
- 401 Unauthorized
- No token, or it is wrong, expired or revoked.
- 403 Forbidden
- The token lacks the scope, or the row is sample data.
- 404 Not Found
- No such item, or you cannot see it.
- 409 Conflict
- A duplicate, or the same Idempotency-Key is busy.
- 412 Precondition Failed
- If-Match did not match: someone changed the item.
- 422 Unprocessable
- A field failed a check. errors has a pointer and a code for each.
- 429 Too Many Requests
- The rate limit is used up; wait Retry-After seconds.
- 500 Server Error
- A fault on our side. Send the request_id when you report it.
{
"type": "https://www.gorest.co.in/docs/api/errors#validation_failed",
"title": "Unprocessable Content",
"status": 422,
"code": "validation_failed",
"detail": "Some fields are not valid.",
"instance": "/public/v3/users",
"request_id": "0190a8e4-0000-7000-8000-0000000000aa",
"errors": [
{ "pointer": "/email", "code": "taken", "detail": "has already been taken" }
]
}Format and testing
- /http/status/503
- Answers with that status, with the headers a real one carries. Any code from 200 to 599.
- /http/delay/1500
- Waits that many milliseconds, up to 10,000, then answers.
- ETag and If-Match
- Send If-Match on PATCH or DELETE so you never overwrite a newer change (412 if it changed).
- Idempotency-Key
- A header on POST that makes a retry safe: the same answer for 24 hours.
- fields, include, sort
- fields[users]=id,name returns fewer fields; include=user embeds the related item; sort=-created_at orders a list.
Want to try a call now? Open the REST console.