# API Reference

Manage projects, dynamic links, and app registrations programmatically via the LinkSense REST API. Available on the Pro plan.

Machine-readable OpenAPI 3.1 spec: https://linksense.net/openapi.json

## Base URL

```
https://linksense.net/api/v1
```

## Authentication

Every request requires an API key sent as a Bearer token:

```
Authorization: Bearer ls_live_your_api_key_here
```

Generate and manage API keys at **Dashboard → Settings → API Keys**. Treat them like passwords — never commit them or expose them in client-side code.

## Rate limits

- 60 requests per minute per API key.
- Exceeding the limit returns `429 Too Many Requests`.

Every response includes:

| Header | Description |
|---|---|
| `X-RateLimit-Limit` | Maximum requests per window. |
| `X-RateLimit-Remaining` | Requests remaining in the current window. |
| `X-RateLimit-Reset` | Unix timestamp (seconds) when the window resets. |

## Response format

Success — results are wrapped in a `data` envelope:

```json
{
  "data": {
    "id": "abc123",
    "name": "My Project",
    "subdomain": "my-project",
    "created_at": "2026-01-01T00:00:00Z"
  }
}
```

Errors use an `error` envelope with `code` (machine-readable) and `message` (human-readable):

```json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "The requested resource does not exist."
  }
}
```

## Error codes

| Code | HTTP | Description |
|---|---|---|
| `INVALID_INPUT` | 400 | Request body or query parameter validation failed. |
| `FORBIDDEN_FIELD` | 400 | The request included a field that isn't allowed. |
| `UNAUTHORIZED` | 401 | API key missing, invalid, or revoked. |
| `AUTH_REQUIRED` | 401 | Authentication is required for this request. |
| `ACCESS_DENIED` | 403 | The resource belongs to another account, or access was denied. |
| `FORBIDDEN_PLAN` | 403 | Your plan doesn't include this feature. Upgrade to Pro for API access. |
| `FORBIDDEN_CROSS_SCOPE` | 403 | The referenced resource belongs to a different project or account. |
| `NOT_FOUND` | 404 | Resource does not exist. |
| `IOS_APP_NOT_FOUND` | 404 | `ios_app_id` does not exist in the project. |
| `ANDROID_APP_NOT_FOUND` | 404 | `android_app_id` does not exist in the project. |
| `SUBDOMAIN_TAKEN` | 409 | Subdomain already in use by another project. |
| `CUSTOM_PATH_EXISTS` | 409 | A link with this custom path already exists in the project. |
| `SLUG_EXISTS` | 409 | A resource with this slug already exists. |
| `BUNDLE_ID_EXISTS` | 409 | An iOS app with this bundle ID already exists in the project. |
| `PACKAGE_NAME_EXISTS` | 409 | An Android app with this package name already exists in the project. |
| `LINKED_REFERENCES` | 409 | App can't be deleted because dynamic links still reference it. |
| `RATE_LIMITED` | 429 | Rate limit exceeded. Wait until the window resets. |

## Endpoints

All endpoints are scoped to the authenticated account.

### Projects

- `GET /projects` — list projects.
- `POST /projects` — create a project.
- `GET /projects/{projectId}` — fetch a project.
- `PUT /projects/{projectId}` — update a project.
- `DELETE /projects/{projectId}` — delete a project.

### Dynamic links

- `GET /projects/{projectId}/links` — list links in a project.
- `POST /projects/{projectId}/links` — create a link.
- `GET /projects/{projectId}/links/{linkId}` — fetch a link.
- `PUT /projects/{projectId}/links/{linkId}` — update a link.
- `DELETE /projects/{projectId}/links/{linkId}` — delete a link.

### iOS apps

- `GET /projects/{projectId}/ios-apps` — list iOS apps registered to the project.
- `POST /projects/{projectId}/ios-apps` — register an iOS app.
- `GET /projects/{projectId}/ios-apps/{appId}` — fetch an iOS app.
- `PUT /projects/{projectId}/ios-apps/{appId}` — update an iOS app.
- `DELETE /projects/{projectId}/ios-apps/{appId}` — delete an iOS app.

### Android apps

- `GET /projects/{projectId}/android-apps` — list Android apps registered to the project.
- `POST /projects/{projectId}/android-apps` — register an Android app.
- `GET /projects/{projectId}/android-apps/{appId}` — fetch an Android app.
- `PUT /projects/{projectId}/android-apps/{appId}` — update an Android app.
- `DELETE /projects/{projectId}/android-apps/{appId}` — delete an Android app.

## Quick example

```bash
curl -H "Authorization: Bearer ls_live_abc123..." \
  https://linksense.net/api/v1/projects
```

See https://linksense.net/docs/api/endpoints for full request/response payloads for each endpoint.
