added full api
This commit is contained in:
@@ -0,0 +1,929 @@
|
||||
# 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 endpoints require a bearer token:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <auth_token>
|
||||
```
|
||||
|
||||
Tokens are created after either:
|
||||
|
||||
- a successful magic-link sign-in
|
||||
- a successful OAuth sign-in with Google, Microsoft, or Apple
|
||||
|
||||
The backend redirects the browser back to the frontend with an `auth_token` query parameter after successful sign-in. Clients should store that token and send it as a bearer token on authenticated requests.
|
||||
|
||||
If authentication is missing or invalid, the API returns:
|
||||
|
||||
```json
|
||||
{ "error": "Authentication required." }
|
||||
```
|
||||
|
||||
FlockPal now supports two bearer token types:
|
||||
|
||||
- browser session tokens returned after magic-link or OAuth sign-in
|
||||
- integration tokens created from the Settings UI for automation tools like n8n
|
||||
|
||||
Integration tokens are workspace-scoped and support:
|
||||
|
||||
- `read_only`
|
||||
- `read_write`
|
||||
|
||||
## How `auth_token` Is Issued
|
||||
|
||||
FlockPal issues the 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 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
|
||||
```
|
||||
|
||||
### Important implementation note
|
||||
|
||||
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.
|
||||
|
||||
Integration tokens follow the same bearer-token header format, but they are created separately and are intended for scripts and automation tools rather than 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 auth. Invalidates the current session.
|
||||
|
||||
Response `204` with no body.
|
||||
|
||||
#### `GET /api/auth/session`
|
||||
|
||||
Requires auth. 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 auth. 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. 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 auth. Lists the signed-in user's workspace memberships.
|
||||
|
||||
Response `200`:
|
||||
|
||||
```json
|
||||
{
|
||||
"workspaces": []
|
||||
}
|
||||
```
|
||||
|
||||
#### `POST /api/workspaces`
|
||||
|
||||
Requires auth. 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 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 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 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 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 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 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 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 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'
|
||||
```
|
||||
Reference in New Issue
Block a user