988 lines
20 KiB
Markdown
988 lines
20 KiB
Markdown
# FlockPal API Reference
|
|
|
|
This document describes the HTTP API currently implemented in `backend/src/app.ts`.
|
|
|
|
## Base URLs
|
|
|
|
- Development frontend: `http://localhost:3000`
|
|
- Development API: `http://localhost:5000`
|
|
- Production API: use your configured `BACKEND_URL`
|
|
|
|
## Authentication
|
|
|
|
Most protected endpoints use a bearer token:
|
|
|
|
```http
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
The current backend supports two token systems.
|
|
|
|
### 1. Browser session tokens
|
|
|
|
Browser session tokens are created after:
|
|
|
|
- a successful magic-link sign-in
|
|
- a successful OAuth sign-in with Google, Microsoft, or Apple
|
|
|
|
After sign-in, the backend redirects the browser back to the frontend with an `auth_token` query parameter. That `auth_token` is the browser session token.
|
|
|
|
Example redirect:
|
|
|
|
```text
|
|
http://localhost:3000/?auth_token=YOUR_SESSION_TOKEN
|
|
```
|
|
|
|
The backend stores only a hash of the session token in the database. The raw token is returned to the client once when the session is created.
|
|
|
|
### 2. Integration tokens
|
|
|
|
Integration tokens are created by an authenticated browser-session user through:
|
|
|
|
- `GET /api/integration-tokens`
|
|
- `POST /api/integration-tokens`
|
|
- `DELETE /api/integration-tokens/:tokenId`
|
|
|
|
These tokens are intended for automation tools such as n8n, scripts, and server-to-server use.
|
|
|
|
Integration tokens are:
|
|
|
|
- workspace-scoped
|
|
- tied to the creating user
|
|
- returned in raw form only once at creation time
|
|
- either `read_only` or `read_write`
|
|
|
|
Use them exactly like session tokens:
|
|
|
|
```http
|
|
Authorization: Bearer flpt_...
|
|
```
|
|
|
|
### Token behavior by endpoint type
|
|
|
|
Browser-session-only endpoints:
|
|
|
|
- `/api/auth/logout`
|
|
- `/api/auth/session`
|
|
- `/api/auth/switch-workspace`
|
|
- `/api/workspaces`
|
|
- `/api/integration-tokens`
|
|
|
|
Endpoints that accept either browser session tokens or integration tokens:
|
|
|
|
- `/api/workspace`
|
|
- `/api/workspace/members`
|
|
- `/api/birds`
|
|
- `/api/birds/:birdId/weights`
|
|
- `/api/birds/:birdId/vet-visits`
|
|
- `/api/transfers/draft`
|
|
|
|
Read-only integration tokens can call read endpoints, but cannot call write endpoints.
|
|
|
|
If authentication is missing or invalid, the API returns:
|
|
|
|
```json
|
|
{ "error": "Authentication required." }
|
|
```
|
|
|
|
Browser-session-only endpoints reject integration tokens with:
|
|
|
|
```json
|
|
{
|
|
"error": "This endpoint requires a browser session instead of an integration token."
|
|
}
|
|
```
|
|
|
|
Write endpoints reject read-only integration tokens with:
|
|
|
|
```json
|
|
{
|
|
"error": "That integration token is read-only."
|
|
}
|
|
```
|
|
|
|
## How Browser `auth_token` Is Issued
|
|
|
|
FlockPal issues the browser bearer token on the backend after a successful passwordless sign-in. The client does not generate it.
|
|
|
|
### Magic-link flow
|
|
|
|
1. The client calls `POST /api/auth/magic-link/request`.
|
|
2. The backend creates a short-lived magic-link token and emails it, or returns a preview URL in local development.
|
|
3. The user opens the magic link.
|
|
4. `GET /api/auth/magic-link/verify` validates the magic-link token, creates an auth session, and generates a new `auth_token`.
|
|
5. The backend redirects to the frontend with `auth_token` in the query string.
|
|
|
|
Example redirect:
|
|
|
|
```text
|
|
http://localhost:3000/?auth_token=YOUR_SESSION_TOKEN
|
|
```
|
|
|
|
### OAuth flow
|
|
|
|
1. The client sends the user to `GET /api/auth/oauth/{provider}/start`.
|
|
2. The provider authenticates the user and redirects back to the backend callback.
|
|
3. The backend callback creates an auth session and generates a new `auth_token`.
|
|
4. The backend redirects to the frontend with `auth_token` in the query string.
|
|
|
|
Example redirect:
|
|
|
|
```text
|
|
http://localhost:3000/?auth_token=YOUR_SESSION_TOKEN
|
|
```
|
|
|
|
### How the browser token is used
|
|
|
|
After the frontend receives `auth_token`, it should store it and send it on authenticated requests:
|
|
|
|
```http
|
|
Authorization: Bearer YOUR_SESSION_TOKEN
|
|
```
|
|
|
|
Integration tokens use the same bearer-token header format, but they are created separately and are not used for browser login.
|
|
|
|
## Roles
|
|
|
|
Workspace roles used by protected endpoints:
|
|
|
|
- `owner`
|
|
- `manager`
|
|
- `staff`
|
|
- `viewer`
|
|
|
|
Role requirements are called out per endpoint below. If the signed-in member lacks permission, the API returns:
|
|
|
|
```json
|
|
{ "error": "You do not have permission for that action." }
|
|
```
|
|
|
|
## Data Shapes
|
|
|
|
### User
|
|
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"email": "person@example.com",
|
|
"name": "Taylor",
|
|
"createdAt": "2026-04-14T12:34:56.000Z"
|
|
}
|
|
```
|
|
|
|
### Workspace
|
|
|
|
```json
|
|
{
|
|
"id": 1001,
|
|
"name": "Home Flock",
|
|
"workspaceType": "standard",
|
|
"billingEmail": "billing@example.com",
|
|
"billingPlan": "household_basic",
|
|
"createdAt": "2026-04-14T12:34:56.000Z",
|
|
"updatedAt": "2026-04-14T12:34:56.000Z"
|
|
}
|
|
```
|
|
|
|
### Workspace Member
|
|
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"workspaceId": 1001,
|
|
"userId": "uuid",
|
|
"inviteEmail": "member@example.com",
|
|
"name": "Alex",
|
|
"role": "viewer",
|
|
"acceptedAt": "2026-04-14T12:34:56.000Z",
|
|
"createdAt": "2026-04-14T12:34:56.000Z"
|
|
}
|
|
```
|
|
|
|
### Bird
|
|
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"workspaceId": 1001,
|
|
"name": "Kiwi",
|
|
"tagId": "FP-001",
|
|
"species": "Cockatiel",
|
|
"dateOfBirth": "2023-05-10",
|
|
"gotchaDay": "2023-08-21",
|
|
"chartColor": "#cb3a35",
|
|
"photoDataUrl": null,
|
|
"notifyOnDob": false,
|
|
"notifyOnGotchaDay": true,
|
|
"createdAt": "2026-04-14T12:34:56.000Z",
|
|
"latestWeightGrams": 92,
|
|
"latestRecordedOn": "2026-04-14"
|
|
}
|
|
```
|
|
|
|
### Weight
|
|
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"birdId": "uuid",
|
|
"weightGrams": 92,
|
|
"recordedOn": "2026-04-14",
|
|
"notes": "Morning check"
|
|
}
|
|
```
|
|
|
|
### Vet Visit
|
|
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"birdId": "uuid",
|
|
"visitedOn": "2026-04-14",
|
|
"clinicName": "Avian Care Center",
|
|
"reason": "Wellness exam",
|
|
"notes": "Healthy"
|
|
}
|
|
```
|
|
|
|
## Common Validation Rules
|
|
|
|
- Dates use `YYYY-MM-DD`
|
|
- `workspaceType` is `standard` or `rescue`
|
|
- member `role` is `owner`, `manager`, `staff`, or `viewer`
|
|
- bird `chartColor` must be a `#RRGGBB` hex color
|
|
- `photoDataUrl` must be a base64 `data:image/...` URL
|
|
- `weightGrams` must be a positive number up to `10000`
|
|
|
|
Validation failures return `400` with this shape:
|
|
|
|
```json
|
|
{
|
|
"error": "Invalid ... payload",
|
|
"details": {}
|
|
}
|
|
```
|
|
|
|
## Endpoints
|
|
|
|
### Health
|
|
|
|
#### `GET /api/health`
|
|
|
|
Public health check.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{ "ok": true }
|
|
```
|
|
|
|
### Authentication
|
|
|
|
#### `GET /api/auth/providers`
|
|
|
|
Public list of configured OAuth providers.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"providers": [
|
|
{
|
|
"providerKey": "google",
|
|
"displayName": "Google",
|
|
"enabled": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### `POST /api/auth/register`
|
|
|
|
Password registration is disabled.
|
|
|
|
Response `410`:
|
|
|
|
```json
|
|
{
|
|
"error": "Password-based registration is disabled. Use a magic link or an identity provider."
|
|
}
|
|
```
|
|
|
|
#### `POST /api/auth/login`
|
|
|
|
Password sign-in is disabled.
|
|
|
|
Response `410`:
|
|
|
|
```json
|
|
{
|
|
"error": "Password-based sign-in is disabled. Use a magic link or an identity provider."
|
|
}
|
|
```
|
|
|
|
#### `POST /api/auth/magic-link/request`
|
|
|
|
Starts a passwordless sign-in flow.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"email": "person@example.com",
|
|
"name": "Taylor",
|
|
"redirectTo": "http://localhost:3000"
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `name` is optional
|
|
- `redirectTo` is optional and defaults to the frontend base URL
|
|
- if email delivery is not configured, the API returns a preview URL instead
|
|
|
|
Response `202`:
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"message": "If that address can sign in, a magic link is on the way.",
|
|
"previewUrl": "http://localhost:5000/api/auth/magic-link/verify?token=...",
|
|
"delivery": "preview"
|
|
}
|
|
```
|
|
|
|
`curl` example:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:5000/api/auth/magic-link/request \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{
|
|
"email": "person@example.com",
|
|
"name": "Taylor",
|
|
"redirectTo": "http://localhost:3000"
|
|
}'
|
|
```
|
|
|
|
Local-development example response when SMTP is not configured:
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"message": "If that address can sign in, a magic link is on the way.",
|
|
"previewUrl": "http://localhost:5000/api/auth/magic-link/verify?token=...",
|
|
"delivery": "preview"
|
|
}
|
|
```
|
|
|
|
#### `GET /api/auth/magic-link/verify?token=...`
|
|
|
|
Consumes a single-use magic-link token, creates or loads the user, creates a session, and redirects to the frontend with `auth_token` in the query string.
|
|
|
|
Responses:
|
|
|
|
- `302` redirect on success
|
|
- `400` if the token is missing, invalid, or expired
|
|
|
|
If you are testing locally and received a `previewUrl`, open that URL in a browser or inspect the redirect target to capture the `auth_token`.
|
|
|
|
#### `POST /api/auth/logout`
|
|
|
|
Requires a browser session. Invalidates the current session.
|
|
|
|
Response `204` with no body.
|
|
|
|
#### `GET /api/auth/session`
|
|
|
|
Requires a browser session. Returns the current session context.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"token": "raw-session-token",
|
|
"session": {
|
|
"user": {
|
|
"id": "uuid",
|
|
"email": "person@example.com",
|
|
"name": "Taylor",
|
|
"createdAt": "2026-04-14T12:34:56.000Z"
|
|
},
|
|
"activeWorkspace": {
|
|
"id": 1001,
|
|
"name": "Home Flock",
|
|
"workspaceType": "standard",
|
|
"billingEmail": null,
|
|
"billingPlan": "household_basic",
|
|
"createdAt": "2026-04-14T12:34:56.000Z",
|
|
"updatedAt": "2026-04-14T12:34:56.000Z"
|
|
},
|
|
"activeMembership": {
|
|
"id": "uuid",
|
|
"workspaceId": 1001,
|
|
"userId": "uuid",
|
|
"inviteEmail": "person@example.com",
|
|
"name": "Taylor",
|
|
"role": "owner",
|
|
"acceptedAt": "2026-04-14T12:34:56.000Z",
|
|
"createdAt": "2026-04-14T12:34:56.000Z"
|
|
},
|
|
"workspaces": [],
|
|
"providers": []
|
|
}
|
|
}
|
|
```
|
|
|
|
`curl` example:
|
|
|
|
```bash
|
|
curl http://localhost:5000/api/auth/session \
|
|
-H 'Authorization: Bearer YOUR_SESSION_TOKEN'
|
|
```
|
|
|
|
#### `POST /api/auth/switch-workspace`
|
|
|
|
Requires a browser session. Switches the session's active workspace.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"workspaceId": 1002
|
|
}
|
|
```
|
|
|
|
Response `200` returns the same shape as `GET /api/auth/session`.
|
|
|
|
`curl` example:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:5000/api/auth/switch-workspace \
|
|
-H 'Authorization: Bearer YOUR_SESSION_TOKEN' \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{
|
|
"workspaceId": 1002
|
|
}'
|
|
```
|
|
|
|
Possible errors:
|
|
|
|
- `403` if the user is not a member of the requested workspace
|
|
|
|
#### `GET /api/auth/oauth/{provider}/start`
|
|
|
|
Starts an OAuth login flow and redirects to the external identity provider.
|
|
|
|
Path params:
|
|
|
|
- `provider`: `google`, `microsoft`, or `apple`
|
|
|
|
Concrete examples:
|
|
|
|
- `/api/auth/oauth/google/start`
|
|
- `/api/auth/oauth/microsoft/start`
|
|
- `/api/auth/oauth/apple/start`
|
|
|
|
Query params:
|
|
|
|
- `redirectTo` optional frontend redirect target after successful login
|
|
|
|
Responses:
|
|
|
|
- `302` redirect to provider on success
|
|
- `404` for an unknown provider
|
|
- `400` if the provider is not configured
|
|
|
|
Browser-oriented example:
|
|
|
|
```text
|
|
http://localhost:5000/api/auth/oauth/google/start?redirectTo=http://localhost:3000
|
|
```
|
|
|
|
`curl` can show the initial redirect, but this flow is meant to complete in a browser:
|
|
|
|
```bash
|
|
curl -i "http://localhost:5000/api/auth/oauth/google/start?redirectTo=http://localhost:3000"
|
|
```
|
|
|
|
#### `GET /api/auth/oauth/{provider}/callback`
|
|
#### `POST /api/auth/oauth/{provider}/callback`
|
|
|
|
OAuth callback used by providers. On success, the backend redirects to the frontend with `auth_token` in the query string.
|
|
|
|
Path params:
|
|
|
|
- `provider`: `google`, `microsoft`, or `apple`
|
|
|
|
Responses:
|
|
|
|
- `302` redirect on success
|
|
- `400` for missing or expired OAuth state
|
|
- `404` for unknown provider
|
|
|
|
### Transfers
|
|
|
|
#### `POST /api/transfers/draft`
|
|
|
|
Requires auth with write access. Prepares a bird transfer to another owner email and optionally triggers a magic-link invite for that email when no user exists yet.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"birdId": "uuid",
|
|
"destinationOwnerEmail": "new-owner@example.com",
|
|
"notes": "Optional draft note"
|
|
}
|
|
```
|
|
|
|
Response `201`:
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"bird": {},
|
|
"destinationOwnerEmail": "new-owner@example.com",
|
|
"destinationOwnerExists": false,
|
|
"inviteSent": true,
|
|
"invitePreviewUrl": "http://localhost:5000/api/auth/magic-link/verify?token=...",
|
|
"inviteDelivery": "preview"
|
|
}
|
|
```
|
|
|
|
Possible errors:
|
|
|
|
- `404` if the bird is not in the active workspace
|
|
|
|
### Workspaces
|
|
|
|
#### `GET /api/workspaces`
|
|
|
|
Requires a browser session. Lists the signed-in user's workspace memberships.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"workspaces": []
|
|
}
|
|
```
|
|
|
|
#### `POST /api/workspaces`
|
|
|
|
Requires a browser session. Creates a new workspace and makes the current user its `owner`.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"name": "Home Flock",
|
|
"workspaceType": "standard",
|
|
"billingEmail": "billing@example.com",
|
|
"billingPlan": "household_plus"
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `workspaceType` must be `standard` or `rescue`
|
|
- `billingPlan` may be `household_basic`, `household_plus`, or `household_macaw`
|
|
- rescue workspaces are forced to `rescue_free`
|
|
|
|
Response `201`:
|
|
|
|
```json
|
|
{
|
|
"workspace": {}
|
|
}
|
|
```
|
|
|
|
#### `GET /api/workspace`
|
|
|
|
Requires auth. Returns the active workspace. Browser sessions and integration tokens can both use this endpoint.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"workspace": {}
|
|
}
|
|
```
|
|
|
|
#### `PUT /api/workspace`
|
|
|
|
Requires auth with write access and role `owner` or `manager`. Updates the active workspace.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"name": "Updated Flock",
|
|
"workspaceType": "standard",
|
|
"billingEmail": "billing@example.com",
|
|
"billingPlan": "household_basic"
|
|
}
|
|
```
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"workspace": {}
|
|
}
|
|
```
|
|
|
|
#### `GET /api/workspace/members`
|
|
|
|
Requires auth. Lists members for the active workspace. Browser sessions and integration tokens can both use this endpoint.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"members": []
|
|
}
|
|
```
|
|
|
|
#### `POST /api/workspace/members`
|
|
|
|
Requires auth with write access and role `owner` or `manager`. Invites or upserts a workspace member.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"name": "Alex",
|
|
"email": "alex@example.com",
|
|
"role": "viewer"
|
|
}
|
|
```
|
|
|
|
Response `201`:
|
|
|
|
```json
|
|
{
|
|
"member": {}
|
|
}
|
|
```
|
|
|
|
#### `DELETE /api/workspace/members/:memberId`
|
|
|
|
Requires auth with write access and role `owner` or `manager`. Removes a non-owner member.
|
|
|
|
Response `204` with no body.
|
|
|
|
Possible errors:
|
|
|
|
- `404` if the member was not found or is an owner
|
|
|
|
### Birds
|
|
|
|
#### `GET /api/birds`
|
|
|
|
Requires auth. Lists birds in the active workspace. Browser sessions and integration tokens can both use this endpoint.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"birds": []
|
|
}
|
|
```
|
|
|
|
#### `POST /api/birds`
|
|
|
|
Requires auth with write access and role `owner`, `manager`, or `staff`. Creates a bird.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"name": "Kiwi",
|
|
"tagId": "FP-001",
|
|
"species": "Cockatiel",
|
|
"dateOfBirth": "2023-05-10",
|
|
"gotchaDay": "2023-08-21",
|
|
"chartColor": "#cb3a35",
|
|
"photoDataUrl": "",
|
|
"notifyOnDob": false,
|
|
"notifyOnGotchaDay": true
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `dateOfBirth`, `gotchaDay`, and `photoDataUrl` may be omitted or sent as empty strings
|
|
- `chartColor` defaults to `#cb3a35`
|
|
|
|
Response `201`:
|
|
|
|
```json
|
|
{
|
|
"bird": {}
|
|
}
|
|
```
|
|
|
|
Possible errors:
|
|
|
|
- `409` if the workspace already uses that `tagId`
|
|
|
|
#### `PUT /api/birds/:birdId`
|
|
|
|
Requires auth with write access and role `owner`, `manager`, or `staff`. Updates a bird.
|
|
|
|
Request body matches `POST /api/birds`.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"bird": {}
|
|
}
|
|
```
|
|
|
|
Possible errors:
|
|
|
|
- `404` if the bird does not exist in the active workspace
|
|
- `409` if the workspace already uses that `tagId`
|
|
|
|
#### `DELETE /api/birds/:birdId`
|
|
|
|
Requires auth with write access and role `owner`, `manager`, or `staff`. Deletes a bird.
|
|
|
|
Response `204` with no body.
|
|
|
|
Possible errors:
|
|
|
|
- `404` if the bird does not exist in the active workspace
|
|
|
|
### Weights
|
|
|
|
#### `GET /api/birds/:birdId/weights`
|
|
|
|
Requires auth. Lists weight entries for a bird in the active workspace.
|
|
|
|
Query params:
|
|
|
|
- `days` optional, clamped to `1` through `365`, default `30`
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"weights": []
|
|
}
|
|
```
|
|
|
|
#### `POST /api/birds/:birdId/weights`
|
|
|
|
Requires auth with write access and role `owner`, `manager`, or `staff`. Creates a weight entry.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"weightGrams": 92,
|
|
"recordedOn": "2026-04-14",
|
|
"notes": "Morning check"
|
|
}
|
|
```
|
|
|
|
Response `201`:
|
|
|
|
```json
|
|
{
|
|
"weight": {}
|
|
}
|
|
```
|
|
|
|
Possible errors:
|
|
|
|
- `404` if the bird does not exist in the active workspace
|
|
- `409` if a weight already exists for that bird on that date
|
|
|
|
### Vet Visits
|
|
|
|
#### `GET /api/birds/:birdId/vet-visits`
|
|
|
|
Requires auth. Lists vet visits for a bird in the active workspace.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"vetVisits": []
|
|
}
|
|
```
|
|
|
|
#### `POST /api/birds/:birdId/vet-visits`
|
|
|
|
Requires auth with write access and role `owner`, `manager`, or `staff`. Creates a vet visit.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"visitedOn": "2026-04-14",
|
|
"clinicName": "Avian Care Center",
|
|
"reason": "Wellness exam",
|
|
"notes": "Healthy"
|
|
}
|
|
```
|
|
|
|
Response `201`:
|
|
|
|
```json
|
|
{
|
|
"vetVisit": {}
|
|
}
|
|
```
|
|
|
|
Possible errors:
|
|
|
|
- `404` if the bird does not exist in the active workspace
|
|
|
|
### Integration Tokens
|
|
|
|
These endpoints are for browser-session users managing their own automation tokens. They are not accessible with an integration token itself.
|
|
|
|
#### `GET /api/integration-tokens`
|
|
|
|
Requires a browser session. Lists the current user's active integration tokens for the active workspace.
|
|
|
|
Response `200`:
|
|
|
|
```json
|
|
{
|
|
"integrationTokens": [
|
|
{
|
|
"id": "uuid",
|
|
"userId": "uuid",
|
|
"workspaceId": 1001,
|
|
"name": "n8n household sync",
|
|
"tokenPrefix": "flpt_1234abcd56",
|
|
"scope": "read_write",
|
|
"lastUsedAt": "2026-04-14T12:34:56.000Z",
|
|
"expiresAt": null,
|
|
"revokedAt": null,
|
|
"createdAt": "2026-04-14T12:00:00.000Z"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### `POST /api/integration-tokens`
|
|
|
|
Requires a browser session. Creates a new integration token for the active workspace and returns the raw token once.
|
|
|
|
Request body:
|
|
|
|
```json
|
|
{
|
|
"name": "n8n household sync",
|
|
"scope": "read_write",
|
|
"expiresInDays": 90
|
|
}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `scope` may be `read_only` or `read_write`
|
|
- `expiresInDays` is optional
|
|
- the raw token is only returned at creation time
|
|
|
|
Response `201`:
|
|
|
|
```json
|
|
{
|
|
"integrationToken": {
|
|
"id": "uuid",
|
|
"userId": "uuid",
|
|
"workspaceId": 1001,
|
|
"name": "n8n household sync",
|
|
"tokenPrefix": "flpt_1234abcd56",
|
|
"scope": "read_write",
|
|
"lastUsedAt": null,
|
|
"expiresAt": "2026-07-13T12:00:00.000Z",
|
|
"revokedAt": null,
|
|
"createdAt": "2026-04-14T12:00:00.000Z"
|
|
},
|
|
"token": "flpt_..."
|
|
}
|
|
```
|
|
|
|
`curl` example:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:5000/api/integration-tokens \
|
|
-H 'Authorization: Bearer YOUR_SESSION_TOKEN' \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{
|
|
"name": "n8n household sync",
|
|
"scope": "read_write",
|
|
"expiresInDays": 90
|
|
}'
|
|
```
|
|
|
|
Use the returned token in your automation tool:
|
|
|
|
```http
|
|
Authorization: Bearer flpt_...
|
|
```
|
|
|
|
#### `DELETE /api/integration-tokens/:tokenId`
|
|
|
|
Requires a browser session. Revokes an integration token owned by the current user in the active workspace.
|
|
|
|
Response `204` with no body.
|
|
|
|
## Error Summary
|
|
|
|
Common status codes used by the API:
|
|
|
|
- `200` successful read or update
|
|
- `201` resource created
|
|
- `202` async or queued success for magic-link requests
|
|
- `204` successful delete or logout with no response body
|
|
- `400` invalid request payload or expired callback state
|
|
- `401` authentication required
|
|
- `403` authenticated but not authorized for the action
|
|
- `404` resource or provider not found
|
|
- `409` uniqueness conflict
|
|
- `410` password-based auth endpoints intentionally disabled
|
|
|
|
## Source of Truth
|
|
|
|
This document reflects the routes currently implemented in:
|
|
|
|
- `backend/src/app.ts`
|
|
|
|
If the docs and code ever disagree, treat the code as the source of truth.
|
|
|
|
## Quick `curl` Workflow
|
|
|
|
Basic local-development auth check:
|
|
|
|
1. Request a magic link:
|
|
|
|
```bash
|
|
curl -X POST http://localhost:5000/api/auth/magic-link/request \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{
|
|
"email": "person@example.com",
|
|
"name": "Taylor",
|
|
"redirectTo": "http://localhost:3000"
|
|
}'
|
|
```
|
|
|
|
2. Copy the `previewUrl` from the response if local email is not configured.
|
|
|
|
3. Open that URL in a browser and capture `auth_token` from the frontend redirect URL.
|
|
|
|
4. Use the token:
|
|
|
|
```bash
|
|
curl http://localhost:5000/api/auth/session \
|
|
-H 'Authorization: Bearer YOUR_SESSION_TOKEN'
|
|
```
|