@php $groups = [ 'System' => [ ['GET', '/api/health', 'API health check', 'Public', 'Returns {"status":"ok"}.'], ['GET', '/api/public/ping', 'Public API health check', 'Public', 'Checks availability of the unauthenticated API surface.'], ], 'Authentication & registration' => [ ['POST', '/api/auth/login', 'Create an API token', 'Public', 'JSON: email, password, optional device_name.'], ['POST', '/api/auth/logout', 'Revoke the current token', 'Bearer', 'Revokes the token used for this request.'], ['POST', '/api/auth/refresh', 'Rotate the current token', 'Bearer', 'Returns a replacement Sanctum bearer token.'], ['GET', '/api/auth/me', 'Get the current account', 'Bearer', 'Returns the authenticated user and resolved organization context.'], ['POST', '/api/auth/forgot-password', 'Request a password reset', 'Public', 'JSON: email. Always returns a safe non-enumerating response.'], ['POST', '/api/auth/reset-password', 'Reset a password', 'Public', 'JSON: email, token, password, password_confirmation.'], ['POST', '/api/auth/reset-password/revoke-sessions', 'Revoke reset-related sessions', 'Public', 'JSON: session_management_token.'], ['POST', '/api/register', 'Start workspace registration', 'Public', 'JSON: name, email, password, terms_accepted. Phone and job title are optional.'], ['GET', '/api/register/{token}', 'Read registration progress', 'Public', 'Returns the current step and safe registration summary.'], ['POST', '/api/register/{token}/verify', 'Verify registration email', 'Public', 'JSON: code (six digits).'], ['POST', '/api/register/{token}/resend', 'Resend verification code', 'Public', 'Rate limited to prevent abuse.'], ['PUT', '/api/register/{token}/organization', 'Save workspace details', 'Public', 'JSON: name, slug, optional phone, job_title, and settings.'], ['POST', '/api/register/{token}/complete', 'Provision the workspace', 'Public', 'Completes registration and returns an authenticated session.'], ], 'Platform administration' => [ ['GET', '/api/admin/organizations', 'List organizations', 'Super admin', 'Paginated platform-wide organization list.'], ['POST', '/api/admin/organizations', 'Create an organization', 'Super admin', 'Creates and provisions a tenant workspace.'], ['GET', '/api/admin/organizations/{organization}/stats', 'Organization statistics', 'Super admin', 'Returns note, project, member, attachment, and storage totals.'], ['POST', '/api/admin/organizations/{organization}/suspend', 'Suspend an organization', 'Super admin', 'Makes tenant mutations read-only.'], ['POST', '/api/admin/organizations/{organization}/activate', 'Activate an organization', 'Super admin', 'Restores normal tenant mutations.'], ], 'Organization' => [ ['POST', '/api/organizations', 'Create my organization', 'Bearer', 'JSON: name and slug. Creates a workspace and makes the current account its Org Admin.'], ['GET', '/api/organization', 'Get organization settings', 'Member', 'Returns branding, settings, and current workspace information.'], ['PUT', '/api/organization', 'Update organization settings', 'Org admin', 'Accepts name, slug, and supported settings fields.'], ['POST', '/api/organization/logo', 'Upload organization logo', 'Org admin', 'Multipart: logo. JPEG, PNG, GIF, or WebP up to 5 MB.'], ], 'Projects' => [ ['GET', '/api/projects', 'List projects', 'Member', 'Paginated tenant-scoped project collection.'], ['POST', '/api/projects', 'Create a project', 'Editor+', 'JSON: name, optional description, key, member_ids.'], ['GET', '/api/projects/{project}', 'Get a project', 'Member', 'Returns project details and related metadata.'], ['PUT', '/api/projects/{project}', 'Update a project', 'Editor+', 'Partial JSON update for name, description, key, members, status, or progress.'], ['DELETE', '/api/projects/{project}', 'Delete a project', 'Editor+', 'Soft-deletes the project according to policy.'], ['POST', '/api/projects/{project}/share', 'Create or refresh a share link', 'Editor+', 'Returns the public project share token and URL.'], ['DELETE', '/api/projects/{project}/share', 'Revoke a share link', 'Editor+', 'Immediately invalidates the active project link.'], ], 'Notes' => [ ['GET', '/api/projects/{project}/notes', 'List project notes', 'Member', 'Supports pagination and server-side note filters.'], ['POST', '/api/projects/{project}/notes', 'Create a note', 'Editor+', 'JSON: title, content, optional type, note_status_id, assignee_ids, label_ids.'], ['POST', '/api/notes/bulk-labels', 'Bulk update note labels', 'Editor+', 'JSON: note_ids, label_ids, operation (add, remove, or replace).'], ['GET', '/api/notes/{note}', 'Get a note', 'Member', 'Returns note, assignments, labels, status, and attachments.'], ['PUT', '/api/notes/{note}', 'Update a note', 'Editor+', 'Partial JSON update of editable note fields.'], ['DELETE', '/api/notes/{note}', 'Delete a note', 'Editor+', 'Soft-deletes the note.'], ['POST', '/api/notes/{note}/status', 'Change note status', 'Editor+', 'JSON: note_status_id. Adds a status-change timeline event.'], ['POST', '/api/notes/{note}/request-update', 'Request an external update', 'Editor+', 'JSON: recipient_email and optional message.'], ['POST', '/api/notes/{note}/reply', 'Post a reply', 'Editor+', 'JSON: content and optional mentioned_user_ids.'], ['GET', '/api/notes/{note}/timeline', 'Get note timeline', 'Member', 'Chronological creation, update, reply, status, label, and attachment events.'], ['GET', '/api/notes/{note}/update-requests', 'List update requests', 'Member', 'Returns active, used, expired, and revoked update links.'], ['DELETE', '/api/notes/{note}/update-requests/{shareToken}', 'Revoke an update request', 'Editor+', 'Invalidates a single external update link.'], ['POST', '/api/notes/{note}/update-requests/{shareToken}/resend', 'Resend an update request', 'Editor+', 'Queues another delivery of the existing request.'], ], 'Attachments' => [ ['POST', '/api/notes/{note}/attachments', 'Upload an attachment', 'Editor+', 'Multipart: file, maximum 50 MB. The response begins with scan_status=pending.'], ['GET', '/api/attachments/{attachment}', 'Get attachment metadata', 'Member', 'Returns scan status, preview kind, size, hashes, and download URL.'], ['GET', '/api/attachments/{attachment}/download', 'Download an attachment', 'Member', 'Returns HTTP 423 until the malware scan is clean.'], ['POST', '/api/attachments/{attachment}/rescan', 'Retry a failed scan', 'Org admin', 'Allowed only when scan_status=error and the quarantined object exists.'], ['DELETE', '/api/attachments/{attachment}', 'Delete an attachment', 'Editor+', 'Deletes both the private object and attachment record.'], ], 'Members' => [ ['GET', '/api/users', 'List organization members', 'Member', 'Tenant-scoped member collection.'], ['POST', '/api/users/invite', 'Add a member', 'Org admin', 'JSON: name, email, role. Existing accounts retain their credentials.'], ['PUT', '/api/users/{user}/role', 'Change membership role', 'Org admin', 'Updates the role only in the selected organization.'], ['PATCH', '/api/users/{user}/access', 'Enable or disable membership', 'Org admin', 'JSON: enabled. Disabled memberships preserve assignments.'], ['DELETE', '/api/users/{user}', 'Remove a membership', 'Org admin', 'Detaches current assignments without deleting the global account.'], ['POST', '/api/users/{user}/resend-invitation', 'Resend an invitation', 'Org admin', 'Queues another invitation email.'], ], 'Statuses & labels' => [ ['GET', '/api/statuses', 'List note statuses', 'Member', 'Ordered tenant status collection.'], ['POST', '/api/statuses', 'Create a status', 'Org admin', 'JSON: label, tone_key, optional sort_order.'], ['PUT', '/api/statuses/{status}', 'Update a status', 'Org admin', 'Partial status update.'], ['DELETE', '/api/statuses/{status}', 'Delete a status', 'Org admin', 'Protected when the status is still in use.'], ['POST', '/api/statuses/reorder', 'Reorder statuses', 'Org admin', 'JSON: ids in the desired order.'], ['GET', '/api/labels', 'List note labels', 'Member', 'Ordered tenant label collection.'], ['POST', '/api/labels', 'Create a label', 'Org admin', 'JSON: name, color (#RRGGBB), optional sort_order.'], ['PUT', '/api/labels/{label}', 'Update a label', 'Org admin', 'Partial label update.'], ['DELETE', '/api/labels/{label}', 'Delete a label', 'Org admin', 'Detaches and deletes the label.'], ['POST', '/api/labels/reorder', 'Reorder labels', 'Org admin', 'JSON: label_ids in the desired order.'], ], 'Requests, activity & notifications' => [ ['GET', '/api/pending-requests', 'List pending public note requests', 'Member', 'Returns unmoderated requests and their scanned images.'], ['POST', '/api/pending-requests/{pendingNoteRequest}/approve', 'Approve a pending request', 'Editor+', 'Creates a normal note from the public submission.'], ['POST', '/api/pending-requests/{pendingNoteRequest}/reject', 'Reject a pending request', 'Editor+', 'Rejects and removes its quarantined attachments.'], ['GET', '/api/activity-logs', 'List activity logs', 'Member', 'Paginated tenant audit trail.'], ['GET', '/api/notifications', 'List current-user notifications', 'Bearer', 'Returns unread and recent notification records.'], ['POST', '/api/notifications/read-all', 'Mark all notifications read', 'Bearer', 'Updates all unread notifications for the current user.'], ['POST', '/api/notifications/{id}/read', 'Mark one notification read', 'Bearer', 'Only affects a notification owned by the current user.'], ], 'Mail & outbound messages' => [ ['GET', '/api/mail-settings', 'Get mail configuration', 'Org admin', 'Returns safe SMTP state and notification preferences; secrets are never returned.'], ['PUT', '/api/mail-settings', 'Update mail configuration', 'Org admin', 'Stores SMTP credentials encrypted.'], ['POST', '/api/mail-settings/test', 'Send a test email', 'Org admin', 'Validates the pending SMTP settings.'], ['POST', '/api/mail-settings/activate', 'Activate organization mail', 'Org admin', 'Enables the tested configuration.'], ['POST', '/api/mail-settings/deactivate', 'Deactivate organization mail', 'Org admin', 'Falls back to platform mail behavior.'], ['GET', '/api/outbound-messages', 'List outbound messages', 'Org admin', 'Paginated encrypted outbox and delivery state.'], ['GET', '/api/outbound-messages/{outboundMailMessage}', 'Get an outbound message', 'Org admin', 'Returns one tenant-scoped message record.'], ['POST', '/api/outbound-messages/{outboundMailMessage}/resend', 'Resend an outbound message', 'Org admin', 'Queues another delivery attempt.'], ], 'Public sharing' => [ ['GET', '/api/public/organizations/{organization}/logo', 'Read public organization logo', 'Public', 'Returns only the public branding asset.'], ['GET', '/api/public/p/{token}', 'Open a shared project', 'Public', 'Returns project branding, global notes, and public-safe timelines.'], ['POST', '/api/public/p/{token}/request-note', 'Request a new note', 'Public', 'Multipart or JSON: name, email, title, details, optional image attachments.'], ['GET', '/api/public/update/{token}', 'Open an update request', 'Public', 'Returns a safe note/request summary and token state.'], ['POST', '/api/public/update/{token}', 'Submit a one-time update', 'Public', 'Multipart: name, email, message, optional six-digit code and attachments/files.'], ], ]; $endpointCount = collect($groups)->sum(fn ($items) => count($items)); $baseUrl = rtrim(url('/api'), '/'); @endphp {{ config('app.name') }} API Documentation

REST API reference

Build clear client-workflows on Note Tracker.

A tenant-safe Laravel API for projects, notes, public collaboration, private attachments, update requests, mail delivery, and auditable workspace administration.

{{ $endpointCount }} documented endpointsJSON over HTTPSLaravel SanctumCheck API health ↗

Quick start

Make your first request

All authenticated endpoints live under /api. Send JSON with an Accept: application/json header and use the token returned by login.

Base URL

{{ $baseUrl }}

Content type

application/json, except multipart uploads.

Health

GET /api/health requires no token.

curl -X POST '{{ $baseUrl }}/auth/login' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "alice@example.com",
    "password": "your-password",
    "device_name": "integration"
  }'

Security

Bearer authentication

The login endpoint returns a Sanctum token. Store it securely and attach it to subsequent requests. Logout revokes only the current token; refresh rotates it.

curl '{{ $baseUrl }}/projects' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Isolation

Tenancy and roles

Tenant members

The organization is resolved from the authenticated account. Cross-tenant model identifiers return 404.

Super administrators

Platform routes use /api/admin. A selected tenant context may be supplied with X-Organization-ID where supported.

Role model

super_admin, org_admin, editor, and viewer. Suspended tenants remain readable but cannot mutate data.

Response contract

Status and error conventions

StatusMeaningTypical shape
200 / 201Successful read or creationResource key or paginated data
401Missing or invalid token{"message":"Unauthenticated."}
403Role/policy denial or suspended mutation{"message":"…"}
404Missing or cross-tenant resource{"message":"Not Found"}
409 / 410Used, revoked, or expired one-time flow{"message":"…"}
422Validation failure{"message":"…","errors":{…}}
423Attachment has not passed scanning{"message":"…"}
429Rate limit exceededStandard Laravel throttle response

Private files

Attachment lifecycle

Uploads enter private quarantine with scan_status=pending. A worker streams them to ClamAV. Clean files become previewable; infected files are deleted; scanner errors remain fail-closed and can be retried by an organization administrator.

curl -X POST '{{ $baseUrl }}/notes/42/attachments' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -F 'file=@./screenshot.png'

Complete catalog

Endpoint reference

Search by method, path, capability, or access level. Path parameters use braces; list endpoints return Laravel pagination metadata where applicable.

@foreach ($groups as $name => $items)

{{ $name }}

{{ count($items) }} endpoints
@foreach ($items as [$method, $path, $title, $access, $description])
{{ $method }} {{ $path }} {{ $title }}{{ $description }} {{ $access }}
@endforeach
@endforeach
No endpoints match that search.