## Building on your own account

For a RapidEye Premium customer building on their own workspace: issue
recording links from your own system, read the results, and receive webhooks.
Partners integrating many customers use the rest of this guide instead.

- **One workspace per key.** A workspace key acts for the workspace that made it, and nothing else. No request here takes a `workspace_id`.
- **Our ids.** `property_id` and `inspection_id` are RapidEye's on every call. `task_id` is yours.
- **Shared rules.** Base URL, JSON, pagination, the error envelope and the rate limit are as in *Conventions* and *Authentication*.

### Getting a key

- **Where:** Settings › Workspace › API, by an owner or admin of the workspace. A workspace holds up to 5 active keys.
- **Shown once.** Copy the key when you create it. We cannot show it again.
- **Send it** on every request as `Authorization: Bearer rapideye_wk_...`. Keep it on your server, never in an app or a web page.
- **Check it** with `GET /v1/me`.

### What a workspace key can call

| Route | Scope |
|---|---|
| `GET /v1/me` | None |
| `GET /v1/properties` | `read:properties` |
| `GET /v1/recording-link` | `write:recording_links` |
| `GET /v1/inspections` | `read:inspections` |
| `GET /v1/inspections/{inspection_id}/findings` | `read:inspections` |
| `GET /v1/inspections/{inspection_id}/video` | `read:inspections` |

- Every workspace key carries these three scopes.
- Every other route answers `403 not_available_to_workspace_keys`. Set up homes and checklists in the RapidEye app.

### `GET /v1/me`

Says which workspace a key belongs to, and whether it can call the API. No scope needed.

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `Authorization` | header | string | yes | `Bearer rapideye_wk_...` |

```http
GET /v1/me HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_wk_...
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "kind": "workspace",
  "workspace": { "id": "b57d44f0-1c2e-4f3a-9d61-0c8f1b7e2a55", "name": "Harbor Homes" },
  "key": { "name": "Chores app", "last4": "fA9x" },
  "scopes": ["read:inspections", "read:properties", "write:recording_links"],
  "api_access": true
}
```

| Field | Meaning |
|---|---|
| `workspace` | Your workspace's `id` and `name`. Webhooks carry the `id` as `company_id`. |
| `key` | The key's name in Settings and its last four characters. |
| `api_access` | `true` while the workspace's plan includes the API. A key on a plan without it gets `403 plan_required` here too. |

A partner key may call it as well and gets `"kind": "partner"` with its own fields.

### `GET /v1/properties`

Lists your workspace's homes, with the `property_id` every other call takes. Scope: `read:properties`.

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `Authorization` | header | string | yes | `Bearer rapideye_wk_...` |
| `limit` | query | integer | no | 1 to 500, default 100. |
| `cursor` | query | string | no | The previous page's `next_cursor`. |

```http
GET /v1/properties HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_wk_...
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "properties": [
    {
      "property_id": "8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44",
      "name": "Harbor House",
      "status": "active",
      "address": {
        "line1": "18 Ocean Drive",
        "city": "Panama City Beach",
        "region": "FL",
        "postal_code": "32413",
        "country_code": "US"
      },
      "has_checklist": true,
      "timezone": "America/Chicago",
      "updated_at": "2026-10-15T07:04:12+00:00"
    }
  ]
}
```

| Field | Meaning |
|---|---|
| `property_id` | Ours and stable. `GET /v1/recording-link` takes it. |
| `status` | `active` or `inactive` (switched off in RapidEye). An `inactive` home carries no `address`. A home deleted in RapidEye is not listed. |
| `has_checklist` | Whether the home has a checklist. Only a home with one gets per-item results. |
| `next_cursor` | Absent on the last page. |

| Error | When |
|---|---|
| `400 invalid_request` | `limit` or `cursor` is malformed. `detail.parameter` names it. |

### `GET /v1/recording-link`

Returns the link a person opens to record a walkthrough of one of your homes for one of your tasks. Scope: `write:recording_links`.

Idempotent: the same `task_id` returns the same URL, so it is safe to call on every render. A task is bound to its first home for its whole life.

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `Authorization` | header | string | yes | `Bearer rapideye_wk_...` |
| `task_id` | query | string | yes | Yours, up to 200 characters. The idempotency key. |
| `property_id` | query | string | yes | Ours, from `GET /v1/properties`. |
| `task_name` | query | string | no | Free text, shown on the walkthrough. Cut to 200 characters. |

```http
GET /v1/recording-link?task_id=chore_2026w42_r17&property_id=8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44&task_name=Weekly%20chores HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_wk_...
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "recording_url": "https://app.rapideyeinspections.com/record/8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44?api_task=chore_2026w42_r17",
  "task_id": "chore_2026w42_r17",
  "property_id": "8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44"
}
```

- Treat `recording_url` as opaque. The person who opens it needs no RapidEye login.
- A walkthrough from a link is an inspection like any other in your workspace, with the same report.

| Error | When |
|---|---|
| `400 missing_parameter` | `task_id` or `property_id` is absent or blank. `detail.parameter` names it. |
| `400 invalid_request` | `task_id` is longer than 200 characters, or `return_url` has a value: workspace links do not take one. `detail.parameter` names it. |
| `404 property_not_found` | That `property_id` is not one of your homes, or the home was deleted. |
| `409 property_inactive` | The home is switched off. Switch it on in RapidEye. |
| `409 property_managed_by_partner` | A partner records this home through its own links. Use those. |
| `409 task_property_conflict` | That `task_id` is already bound to another home. Use a new `task_id`. |

### `GET /v1/inspections`

Returns one inspection's status, report and checklist results. Scope: `read:inspections`. Send exactly one of `task_id` or `inspection_id`.

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `Authorization` | header | string | yes | `Bearer rapideye_wk_...` |
| `task_id` | query | string | one of | Yours, from a recording link. |
| `inspection_id` | query | string | one of | Ours, from a webhook. Reads any inspection in your workspace, including one recorded in the app. |

```http
GET /v1/inspections?task_id=chore_2026w42_r17 HTTP/1.1
Host: api.rapideyeinspections.com
Authorization: Bearer rapideye_wk_...
```

The response is the one partners get from the status poll on *Recording links and inspections*: `status`, `inspection_id`, the `report` block and the `checklist` block. Each item's result is described in *Per-item checklist results*. A task whose link nobody has opened yet reads `{"status": "pending"}`.

| Error | When |
|---|---|
| `400 missing_parameter` | Neither `task_id` nor `inspection_id` was sent. |
| `400 invalid_request` | Both have a value. `detail.parameters` names the two. |
| `404 task_not_found` | No recording link was issued for that `task_id`. |
| `404 not_found` | No inspection with that `inspection_id` in your workspace. |

### Findings and video

`GET /v1/inspections/{inspection_id}/findings` and `GET /v1/inspections/{inspection_id}/video` answer a workspace key exactly as they answer a partner, without `workspace_id`. Both take our `inspection_id` and need `read:inspections`. An inspection in another workspace answers `404 not_found`, the same as one that does not exist.

### Webhooks for your account

- **Register** in Settings › Workspace › API: one HTTPS receiver per workspace, reachable from the internet, and the events you want. Any port; no query string or `#` fragment; a host name or IPv4 address, not an IPv6 address. The signing secret is shown once when you save.
- **Every inspection** in your workspace, whether or not it started from your link. A receiver you save also gets Walkthrough saved for walkthroughs saved in the 6 hours before.
- **Send test event** in Settings sends `webhook.test`, carrying only `version`, `event_id`, `event_type`, `company_id` and `sent_at`. It works while the webhook is paused.

| In Settings | Event | Fires when |
|---|---|---|
| Walkthrough saved | `inspection.recording_completed` | The walkthrough is saved, with each checklist item's result. Within a few minutes of the person tapping Done. |
| Report ready | `inspection.completed` | The report is ready, hours after the walkthrough. |
| Report failed | `inspection.failed` | We could not produce the report, instead of Report ready. |

The payloads are the ones in *What we send back to you*, with three differences:

- `company_id` in place of `workspace_id`. It is your workspace's id.
- `property_id` is ours.
- `task_id` is yours, or `null` for a walkthrough not started from your link.

```json
{
  "version": 1,
  "event_id": "5d0b8f2e-6c1a-4f3e-9a77-1e2d3c4b5a69",
  "event_type": "inspection.recording_completed",
  "company_id": "b57d44f0-1c2e-4f3a-9d61-0c8f1b7e2a55",
  "task_id": "chore_2026w42_r17",
  "property_id": "8c1e4b7a-90d2-4f55-a3f1-1d2e9b0c6a44",
  "inspection_id": "3b7f1a90-2c44-4b6d-9e01-7a5c2f8e1d33",
  "recorded_at": "2026-10-20T18:02:11Z",
  "checklist": {
    "status": "complete",
    "counts": { "verified": 2, "missed": 1, "explained": 0, "not_checked": 0, "pending": 0 },
    "items": [
      { "id": "c1f0a2e4-...", "name": "Kitchen: counters wiped", "state": "verified",
        "timestamp": 41.7, "image_url": "https://...signed..." }
    ]
  }
}
```

- **Verify** every delivery as in *Verifying our signature*. Retries, timeouts and duplicates follow *Delivery semantics*.
- **A receiver that keeps failing pauses.** If deliveries keep failing for 3 days, we pause the webhook and email the workspace's owners once. Events while it is paused are not sent, and **Resume** in Settings does not resend them. For walkthroughs started from your links, `GET /v1/inspections?task_id=...` has the result of anything you missed.
- **Off Premium,** events are not sent, and are not sent later when the workspace is back on Premium.

### Errors and limits

Besides each route's own codes, any route here can return:

| Error | When |
|---|---|
| `401 invalid_key` | The key is missing, malformed or not one we recognize. |
| `403 key_revoked` | The key was revoked in Settings. Make a new one. |
| `403 plan_required` | The workspace's plan does not include the API. Keys and the webhook are kept and work again once the workspace is on Premium. |
| `403 not_available_to_workspace_keys` | The route is for partners. See *What a workspace key can call*. |
| `429 too_many_requests` | More than 600 requests from your key in one 5-minute window of the clock. Retry once the next window starts. |

### Keys over time

- **Replace a key** by creating a new one, deploying it, then revoking the old one in Settings. Revoking is immediate and permanent: the old key answers `403 key_revoked`.
- **A leaked key:** revoke it in Settings at once.
- **Rotate the webhook secret** with Rotate in Settings. The new secret is shown once, and the old one keeps signing alongside it for 7 days, so each signature header carries two entries and either secret verifies. Deploy the new one within those 7 days. Rotating again inside them ends the earlier secret's overlap at once, so Settings asks you to confirm.
