# HereGo API — Video Evidence API for AI Agents

HereGo is the REST API for asking humans to produce visual evidence on demand.

AI agents and applications can create video recording requests, generate browser-based recording links with a REST call, and retrieve the resulting videos programmatically.

**Flow**

1. An AI agent or application creates a visual-evidence request with `POST /v1/requests` and receives a `submission_url` plus a request-scoped `access_token`.
2. The `submission_url` (`https://herego.video/r/{id}`) is sent to a human.
3. The human opens the link in a browser and records a video without installing an app or creating a HereGo account.
4. The agent checks request status with `GET /v1/requests/{id}`.
5. Once `status` is `submitted`, the agent retrieves the video from `GET /v1/videos/{id}`.
6. If the request is no longer needed, the agent can delete it with `DELETE /v1/requests/{id}`.

**Public API surface**

- `POST /v1/requests`
- `GET /v1/requests/{id}`
- `DELETE /v1/requests/{id}`
- `GET /v1/videos/{id}`

**Authentication and rate limits**

No API key is currently required for free anonymous usage.

Anonymous usage is heavily rate limited.

The request-scoped `access_token` returned by `POST /v1/requests` authorizes access to that specific request and its submitted video, including request deletion.

Base URL: `https://herego.video/v1`

## Authentication

- `requestAccessToken` (http bearer)
  Request-scoped bearer token returned by `POST /v1/requests`. Authorizes access to a single request and its submitted video. Distinct from an API key (which identifies an account and is not currently required). Send as `Authorization: Bearer <access_token>`.

Send the token as `Authorization: Bearer <token>`.

## Requests

Create, inspect, and delete visual-evidence requests. A request is the primary resource; a submitted video is the human response.

### `POST /v1/requests`

Create a visual-evidence request

Creates a new video request in the `awaiting_submission` state and returns a browser-based `submission_url` to send to a human, along with a request-scoped `access_token`.

The `access_token` is returned only once, at creation time, to the creator of the request. Store it securely: it is required to check status, delete the request, and stream the submitted video.

No API key is currently required. Anonymous creation is intentionally supported for the MVP and is aggressively rate limited (`429 Too Many Requests`).

**Request body** (required, `application/json`)

- `prompt` (string, required): Human-readable instruction shown to the person who will record the video.
- `expires_in_hours` (integer, required): Number of hours until the request and any submitted video expire. Must be between 1 and 48 hours.

**Responses**

- `201 Created`: Request created.
- `400 Bad Request`: The request was malformed or failed validation.
- `429 Too Many Requests`: Rate limit exceeded. Anonymous access is aggressively rate limited in the MVP.
- `500 Internal Server Error`: An unexpected error occurred.

```bash
curl -X POST https://herego.video/v1/requests \
  -H "Content-Type: application/json" \
  -d '{
      "prompt": "Please show me what happens when you try to check out."
    }'
```

Example body:

```json
{
  "prompt": "Please show me what happens when you try to check out."
}
```

Example `201` response:

```json
{
  "id": "req_abc123",
  "status": "awaiting_submission",
  "submission_url": "https://herego.video/r/abc123",
  "access_token": "rat_9f8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d",
  "expires_at": "2026-09-08T14:30:00Z"
}
```

Example `400` response:

```json
{
  "error": {
    "code": "bad_request",
    "message": "Field 'prompt' is required."
  }
}
```

Example `429` response:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please retry later."
  }
}
```

Example `500` response:

```json
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred."
  }
}
```

### `DELETE /v1/requests`

Delete a visual-evidence request

Deletes a video request and cleans up any associated submitted video. Access is scoped to the specific request via the request access token.

This operation is useful when an AI agent or application no longer needs the request or its submitted evidence. From the caller's perspective it is idempotent: once deleted, subsequent reads return `404 Not Found`.

Requires bearer auth (`Authorization: Bearer <token>`).

**Responses**

- `204 No Content`: Request deleted. No content.
- `401 Unauthorized`: Missing or invalid request access token.
- `403 Forbidden`: The provided access token does not grant access to this request.
- `404 Not Found`: The request or video does not exist.
- `429 Too Many Requests`: Rate limit exceeded. Anonymous access is aggressively rate limited in the MVP.
- `500 Internal Server Error`: An unexpected error occurred.

```bash
curl -X DELETE https://herego.video/v1/requests \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Example `401` response:

```json
{
  "error": {
    "code": "unauthorized",
    "message": "A valid request access token is required."
  }
}
```

Example `403` response:

```json
{
  "error": {
    "code": "forbidden",
    "message": "This access token is not scoped to the requested resource."
  }
}
```

Example `404` response:

```json
{
  "error": {
    "code": "not_found",
    "message": "The requested resource was not found."
  }
}
```

Example `429` response:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please retry later."
  }
}
```

Example `500` response:

```json
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred."
  }
}
```

### `GET /v1/requests/{id}`

Get the status of a visual-evidence request

Returns the current status of a video request. Access is scoped to the specific request: the caller must present the request access token returned when the request was created.

When `status` is `submitted`, the response includes a `video` object whose `url` is a HereGo API endpoint (`GET /v1/videos/{id}`), **not** a direct storage URL. Stream the video from that URL using the same request access token.

**Status values**

- `awaiting_submission` — the request exists but no video has been submitted yet.
- `submitted` — a human has submitted a video; `video` is present.
- `expired` — the request (and any video) has passed its `expires_at`; the video is no longer retrievable.

**Lifecycle transitions**

- `awaiting_submission → submitted`
- `awaiting_submission → expired`
- `submitted → expired`

Requires bearer auth (`Authorization: Bearer <token>`).

**Parameters**

- `id` (path, required, string): Identifier of the video request, e.g. `req_abc123`.

**Responses**

- `200 OK`: Current request status.
- `401 Unauthorized`: Missing or invalid request access token.
- `403 Forbidden`: The provided access token does not grant access to this request.
- `404 Not Found`: The request or video does not exist.
- `429 Too Many Requests`: Rate limit exceeded. Anonymous access is aggressively rate limited in the MVP.
- `500 Internal Server Error`: An unexpected error occurred.

```bash
curl -X GET https://herego.video/v1/requests/req_abc123 \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Example `200` response:

```json
{
  "id": "req_abc123",
  "status": "awaiting_submission"
}
```

Example `401` response:

```json
{
  "error": {
    "code": "unauthorized",
    "message": "A valid request access token is required."
  }
}
```

Example `403` response:

```json
{
  "error": {
    "code": "forbidden",
    "message": "This access token is not scoped to the requested resource."
  }
}
```

Example `404` response:

```json
{
  "error": {
    "code": "not_found",
    "message": "The requested resource was not found."
  }
}
```

Example `429` response:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please retry later."
  }
}
```

Example `500` response:

```json
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred."
  }
}
```

## Videos

Retrieve submitted videos through the HereGo API. Videos are never exposed as direct storage URLs.

### `GET /v1/videos/{id}`

Stream a submitted video

Streams the submitted video for a request. The response body is a binary video stream served through HereGo; the underlying private storage object is never exposed.

**Authorization**

Requires the request access token for the request that owns this video. HereGo validates the request-scoped token and rejects mismatched or missing tokens.

**Expiry**

HereGo checks the video's `expires_at` on every request. After expiry, the video is no longer served and the endpoint returns `410 Gone`. Note: HereGo cannot prevent a client from retaining bytes it already downloaded before expiry; expiry only prevents new access.

**HTTP Range / streaming**

The endpoint supports HTTP partial-content semantics. Clients and agents may send a `Range: bytes=start-end` header for partial retrieval, seeking, or streaming. A valid range request returns `206 Partial Content` with `Content-Range` and `Accept-Ranges: bytes`. A request without a `Range` header may return the complete `200 OK` response with the appropriate `Content-Type` and `Content-Length`.

This is the sole video retrieval/streaming endpoint. There is no public `/v/{id}` viewer route and no permanent media URL.

Requires bearer auth (`Authorization: Bearer <token>`).

**Parameters**

- `id` (path, required, string): Identifier of the submitted video, e.g. `vid_xyz789`.
- `Range` (header, optional, string): Optional HTTP byte range for partial retrieval, e.g. `bytes=0-1048575`. When present and satisfiable, the response is `206 Partial Content`.

**Responses**

- `200 OK`: Full video stream. Returned when no `Range` header is provided (or the server chooses to return the complete representation).
- `206 Partial Content`: Partial video stream. Returned in response to a satisfiable `Range` request.
- `401 Unauthorized`: Missing or invalid request access token.
- `403 Forbidden`: The provided access token does not grant access to this request.
- `404 Not Found`: The request or video does not exist.
- `410 Gone`: The request or video has expired and is no longer available. HereGo stops serving the video after `expires_at`.
- `416 Range Not Satisfiable`: The requested range is not satisfiable.
- `429 Too Many Requests`: Rate limit exceeded. Anonymous access is aggressively rate limited in the MVP.
- `500 Internal Server Error`: An unexpected error occurred.

```bash
curl -X GET https://herego.video/v1/videos/vid_xyz789 \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Range: bytes=0-1048575"
```

Example `401` response:

```json
{
  "error": {
    "code": "unauthorized",
    "message": "A valid request access token is required."
  }
}
```

Example `403` response:

```json
{
  "error": {
    "code": "forbidden",
    "message": "This access token is not scoped to the requested resource."
  }
}
```

Example `404` response:

```json
{
  "error": {
    "code": "not_found",
    "message": "The requested resource was not found."
  }
}
```

Example `410` response:

```json
{
  "error": {
    "code": "gone",
    "message": "This video has expired and is no longer available."
  }
}
```

Example `429` response:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please retry later."
  }
}
```

Example `500` response:

```json
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected error occurred."
  }
}
```

## Schemas

### `CreateRequestBody`

- `prompt` (string, required): Human-readable instruction shown to the person who will record the video.
- `expires_in_hours` (integer, required): Number of hours until the request and any submitted video expire. Must be between 1 and 48 hours.

### `RequestStatusValue`

Lifecycle state of a video request.

- Type: string
  Allowed: awaiting_submission | submitted | expired
  Lifecycle state of a video request.

### `CreatedRequest`

- `id` (string, required): Identifier of the created request.
- `status` (string, required): Lifecycle state of a video request.
- `submission_url` (string (uri), required): Public website URL (`/r/{id}`) to send to a human so they can record and submit the video.
- `access_token` (string, required): Request-scoped bearer token. Returned only once, to the creator. Required to check status, delete the request, and stream the submitted video.
- `expires_at` (string (date-time), required): When the request (and any submitted video) expires.

### `SubmittedVideo`

- `id` (string, required): Identifier of the submitted video.
- `url` (string (uri), required): HereGo API endpoint that streams the video (`GET /v1/videos/{id}`). This is NOT a direct storage URL. Stream it using the request access token.
- `expires_at` (string (date-time), required): When the video stops being served. After this time, streaming returns `410 Gone`.

### `RequestStatus`

- `id` (string, required)
- `status` (string, required): Lifecycle state of a video request.
- `expires_at` (string (date-time), required): When the request and any submitted video expire.
- `video` (object, optional)
  - `id` (string, required): Identifier of the submitted video.
  - `url` (string (uri), required): HereGo API endpoint that streams the video (`GET /v1/videos/{id}`). This is NOT a direct storage URL. Stream it using the request access token.
  - `expires_at` (string (date-time), required): When the video stops being served. After this time, streaming returns `410 Gone`.

### `VideoBinary`

Raw binary video stream. Supports full (`200 OK`) and partial (`206 Partial Content`) responses.

- Type: string (binary)
  Raw binary video stream. Supports full (`200 OK`) and partial (`206 Partial Content`) responses.

### `Error`

- `error` (object, required)
  - `code` (string, required): Stable, machine-readable error code.
  - `message` (string, required): Human-readable explanation of the error.

## Errors

- `BadRequest`: The request was malformed or failed validation.
- `Unauthorized`: Missing or invalid request access token.
- `Forbidden`: The provided access token does not grant access to this request.
- `NotFound`: The request or video does not exist.
- `Gone`: The request or video has expired and is no longer available. HereGo stops serving the video after `expires_at`.
- `TooManyRequests`: Rate limit exceeded. Anonymous access is aggressively rate limited in the MVP.
- `InternalServerError`: An unexpected error occurred.

## Further reading

- REST reference: https://herego.video/docs/api
- MCP server documentation: https://herego.video/docs/mcp
- OpenAPI specification: https://herego.video/api/openapi.json
