Authentication API

Authentication Documentation

Secure your integration with TendedLoop using JWT tokens, API keys, OAuth single sign-on, or passwordless magic links.

JWT + Refresh Tokens Role-Based Access 4 Auth Methods

Overview

TendedLoop supports four authentication methods, each designed for different use cases. Choose the method that best fits your integration scenario.

Method Best For Token Lifetime
JWT Tokens Web and mobile applications 15 min (access) / 30 days (refresh)
API Keys Server-to-server integrations No expiry (revocable)
OAuth (SSO) Enterprise single sign-on Returns JWT tokens
Magic Links Passwordless operator login 15 min (link) / returns JWT
Quick start: For most integrations, use JWT authentication with email/password login. For backend services, use API keys for simpler, long-lived credentials.

JWT Authentication

JWT (JSON Web Token) is the primary authentication method for TendedLoop. Authenticate with your email and password to receive a short-lived access token and a long-lived refresh token.

Login

Send a POST request to /api/auth/login with your credentials. On success, you receive an access token (15-minute expiry) and a refresh token (30-day expiry).

cURL Login request

curl -X POST https://api.tendedloop.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@yourcompany.com",
    "password": "your-password"
  }'

Response

{
  "success": true,
  "data": {
    "user": {
      "id": "clx1abc...",
      "email": "admin@yourcompany.com",
      "name": "Jane Admin",
      "roles": ["ADMIN"]
    },
    "tokens": {
      "accessToken": "eyJhbGciOiJIUzI1NiIs...",
      "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
    }
  }
}

Using the access token

Include the access token in the Authorization header of all subsequent requests:

curl https://api.tendedloop.com/api/dashboard/overview \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Token refresh

When the access token expires, use the refresh token to obtain a new pair without re-authenticating:

curl -X POST https://api.tendedloop.com/api/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{
    "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
  }'

Response

{
  "success": true,
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
  }
}

JS Node.js example

const response = await fetch('https://api.tendedloop.com/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: 'admin@yourcompany.com',
    password: 'your-password',
  }),
});

const { data } = await response.json();
const { accessToken, refreshToken } = data.tokens;

// Use the access token for subsequent requests
const dashboard = await fetch('https://api.tendedloop.com/api/dashboard/overview', {
  headers: { 'Authorization': `Bearer ${accessToken}` },
});

const result = await dashboard.json();
console.log(result.data);
Important: Access tokens expire after 15 minutes. Always implement token refresh logic in your application to maintain uninterrupted access. Store refresh tokens securely and never expose them in client-side code.

API Keys

API keys provide a simple, long-lived authentication method ideal for server-to-server integrations, CI/CD pipelines, and backend services. Unlike JWT tokens, API keys do not expire automatically.

Creating an API key

  1. Navigate to Integrations > API Keys in the admin dashboard.
  2. Click Create API Key and assign a descriptive name.
  3. Select the scoped permissions (read, write, webhooks:manage).
  4. Copy the generated key immediately; it is only shown once.

Using an API key

Include your API key in the X-API-Key header:

curl https://api.tendedloop.com/api/dashboard/overview \
  -H "X-API-Key: tl_k_a1b2c3d4e5f6..."

JS Node.js example

const response = await fetch('https://api.tendedloop.com/api/dashboard/overview', {
  headers: {
    'X-API-Key': process.env.TENDEDLOOP_API_KEY,
  },
});

const { data } = await response.json();
console.log(data);
Property Details
Header X-API-Key: <apiKey>
Expiry No automatic expiry
Permissions Scoped per key at creation time
Revocation Revoke instantly from the dashboard
Important: The API key is only displayed once when created. Store it securely in your environment variables or secrets manager. If you lose it, revoke the old key and create a new one.

OAuth (SSO)

TendedLoop supports Google and Microsoft OAuth for enterprise single sign-on. Users authenticate with their identity provider and receive JWT tokens for API access. On first login, a trial tenant is automatically created.

Google OAuth

Exchange a Google credential token for TendedLoop JWT tokens.

curl -X POST https://api.tendedloop.com/api/auth/google \
  -H "Content-Type: application/json" \
  -d '{
    "credential": "eyJhbGciOiJSUzI1NiIs..."
  }'

Response

{
  "success": true,
  "data": {
    "user": {
      "id": "clx1abc...",
      "email": "user@company.com",
      "name": "Jane Smith",
      "roles": ["ADMIN"]
    },
    "tokens": {
      "accessToken": "eyJhbGciOiJIUzI1NiIs...",
      "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
    },
    "isNewUser": false
  }
}

Microsoft OAuth

Exchange a Microsoft access token for TendedLoop JWT tokens.

curl -X POST https://api.tendedloop.com/api/auth/microsoft \
  -H "Content-Type: application/json" \
  -d '{
    "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGci..."
  }'
Auto-provisioning: When a user signs in via OAuth for the first time, TendedLoop automatically creates a trial tenant and assigns the user as ADMIN. No separate signup is required.

Role-Based Access

TendedLoop uses role-based access control (RBAC) to determine what each user can do. Users can hold multiple roles simultaneously, and the highest privilege wins when checking permissions.

Role Access Level Capabilities
ADMIN Full access All features, settings, user management, billing, webhooks, API keys, routing rules
MANAGER Read + analytics Dashboards, feedback analytics, SLA monitoring, export, task management
TECHNICIAN Task-only View and complete assigned tasks, update task status, add task notes

Multi-role users

A user can hold up to 3 roles (e.g., ["ADMIN", "MANAGER"]). The JWT payload includes a roles array. When an endpoint requires a specific role, TendedLoop checks if the user holds that role or a higher-privilege one.

// JWT payload structure
{
  "userId": "clx1abc...",
  "tenantId": "clx2def...",
  "roles": ["ADMIN", "MANAGER"],
  "type": "access",
  "iat": 1707820000,
  "exp": 1707820900
}
Tenant isolation: All API queries are automatically scoped to the tenant in the JWT token. There is no way to access data from another tenant, even with an ADMIN role.

Rate Limiting

Authentication endpoints are rate-limited to prevent brute-force attacks and abuse. When limits are exceeded, the API returns a 429 Too Many Requests response.

Endpoint Limit Scope
/api/auth/login Per email address Prevents brute-force password attacks
/api/auth/magic-link/request 5 requests / 15 minutes Per email address
/api/auth/change-password Per user Prevents password enumeration

Rate limit response

{
  "success": false,
  "error": "Too many attempts. Please try again later.",
  "code": "RATE_LIMITED"
}
Testing: During development and testing, you can bypass rate limits by including the X-System-Secret header with your system secret. This should never be used in production client-side code.

Error Codes

Authentication errors follow a consistent response format. Use the HTTP status code and the code field to handle errors programmatically.

401

Unauthorized

The request is missing a valid token, or the token has expired.

{
  "success": false,
  "error": "Invalid or expired token",
  "code": "UNAUTHORIZED"
}

Fix: Refresh your access token using the refresh endpoint, or re-authenticate.

403

Forbidden

The token is valid, but the user does not have the required role to access this resource.

{
  "success": false,
  "error": "Insufficient permissions",
  "code": "FORBIDDEN"
}

Fix: Ensure the authenticated user has the required role (ADMIN, MANAGER, or TECHNICIAN) for the endpoint.

429

Too Many Requests

Rate limit exceeded. Wait before retrying.

{
  "success": false,
  "error": "Too many attempts. Please try again later.",
  "code": "RATE_LIMITED"
}

Fix: Implement exponential backoff in your retry logic. Avoid sending requests in tight loops.

Ready to integrate?

Start building with the TendedLoop API in minutes.