Back to API documentation
# API Admin Setup and Management Guide This guide is for Lightning Payroll partners who have been given an API-admin account and need to provision, brand, and manage their integration client. Base URL used in examples: ```text https://api.dev.intellitron.com.au ``` ## What an API admin is An API admin is a Lightning Payroll customer account that is allowed to own an OAuth client and manage partner-facing integration settings. That API-admin account can: - provision its OAuth client ID and client secret - manage registered redirect URIs - configure partner branding shown during hosted login and onboarding flows - inspect linked customer connections - revoke linked customer connections - review connection activity and error summaries for its client Swagger provides the endpoint-by-endpoint contract. This guide explains the recommended setup flow, the purpose of each public API-admin surface, and the operational details partners usually need while integrating. ## Before you start You will need: 1. a Lightning Payroll customer account that has been granted API-admin access 2. the ability to sign in as that API-admin account 3. a normal Lightning Payroll bearer token for that signed-in account This guide is about partner setup and management. It is separate from the OAuth `client_id` / `client_secret` flow your customers use when they authorise your integration. ## Authentication for API-admin endpoints These endpoints do **not** use `client_id` and `client_secret`. They require a normal authenticated Lightning Payroll bearer token for the API-admin customer account. Think of this as the API token for your own partner account, not the OAuth client credentials used later by customer authorisation. Example shell variables: ```bash BASE_URL="https://api.dev.intellitron.com.au" ADMIN_TOKEN="<lightning-payroll-api-admin-access-token>" ``` Every request must include: ```bash -H "Authorization: Bearer $ADMIN_TOKEN" ``` If the caller is not an API admin, the server returns: ```json {"detail":"Forbidden"} ``` ## Recommended setup sequence 1. `GET /api/init-api-client` 2. `POST /api/update-api-client` 3. Upload optional branding assets 4. Start using the **OAuth Authentication Guide** 5. Use overview, connections, activity, and errors endpoints for monitoring ## Two response objects you will see often Many API-admin responses include two branding objects: - `configured_branding`: the branding values saved directly on your API-admin account - `effective_branding`: the branding Lightning Payroll will actually use after fallbacks and overrides are applied If you are simply configuring your own partner branding, these two objects will usually match once setup is complete. ## Endpoint Summary | Method | Path | Purpose | |---|---|---| | `GET` | `/api/init-api-client` | Create the OAuth client if missing, or return the existing client | | `POST` | `/api/update-api-client` | Update redirect URIs, rotate secret, timezone, and branding metadata | | `GET` | `/api/api-client/whitelabel-logo` | Read primary logo metadata | | `POST` | `/api/api-client/whitelabel-logo` | Upload primary logo | | `DELETE` | `/api/api-client/whitelabel-logo` | Delete primary logo | | `GET` | `/api/api-client/whitelabel-dark-logo` | Read dark-mode logo metadata | | `POST` | `/api/api-client/whitelabel-dark-logo` | Upload dark-mode logo | | `DELETE` | `/api/api-client/whitelabel-dark-logo` | Delete dark-mode logo | | `GET` | `/api/api-client/whitelabel-style` | Read stylesheet metadata and CSS text | | `POST` | `/api/api-client/whitelabel-style` | Upload stylesheet | | `DELETE` | `/api/api-client/whitelabel-style` | Delete stylesheet | | `GET` | `/api/public-branding` | Resolve public branding by `client_id` or `branding_token` | | `GET` | `/api/public-branding/logo` | Fetch public logo bytes | | `GET` | `/api/api-client/overview` | Roll-up metrics for the API client | | `GET` | `/api/api-client/connections` | List connected customer accounts | | `DELETE` | `/api/api-client/connections/{customer_id}` | Revoke all refresh tokens for one connected customer | | `GET` | `/api/api-client/activity` | Recent authorization-code and refresh-token activity | | `GET` | `/api/api-client/errors` | Recent error logs and summary | ## 1) Initialise or fetch the API client This is the safest first call to make. If your client does not exist yet, Lightning Payroll creates it. If it already exists, Lightning Payroll returns the current configuration instead. ### Request ```bash curl -sS "$BASE_URL/api/init-api-client" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` ### First-time response ```json { "status": "Client created", "timezone": "UTC", "configured_branding": { "displayName": "", "subtitle": "", "supportEmail": "", "supportPhone": "", "homepageUrl": "", "supportUrl": "", "disableDarkMode": false, "publicBrandingToken": "public-branding-token" }, "effective_branding": { "source_type": "none", "source_customer_id": null, "source_client_id": null, "branding_token": null, "add_on_key": null, "add_on_label": "", "display_name": "", "subtitle": "", "company_name": "Lightning Payroll", "support_email": "support@lightningpayroll.com.au", "support_phone": "1300 515 895", "homepage_url": "", "support_url": "", "has_logo": false, "has_dark_logo": false, "has_style": false, "disable_dark_mode": false, "uses_standalone_shell": false }, "client": { "clientId": "your-client-id", "redirectUris": [], "hasClientSecret": true, "clientSecret": "plain-text-secret-shown-once" } } ``` ### Existing-client response ```json { "status": "Client already exists", "timezone": "Australia/Brisbane", "configured_branding": { "displayName": "Farm Focus", "subtitle": "Powered by Lightning Payroll", "supportEmail": "support@example.com", "supportPhone": "1300 000 111", "homepageUrl": "https://partner.example.com", "supportUrl": "https://partner.example.com/support", "disableDarkMode": false, "publicBrandingToken": "public-branding-token" }, "effective_branding": { "source_type": "self", "source_customer_id": 12345, "source_client_id": null, "branding_token": "public-branding-token", "add_on_key": null, "add_on_label": "", "display_name": "Farm Focus", "subtitle": "Powered by Lightning Payroll", "company_name": "Farm Focus Pty Ltd", "support_email": "support@example.com", "support_phone": "1300 000 111", "homepage_url": "https://partner.example.com", "support_url": "https://partner.example.com/support", "has_logo": true, "has_dark_logo": true, "has_style": true, "disable_dark_mode": false, "uses_standalone_shell": false }, "client": { "clientId": "your-client-id", "redirectUris": [ "https://partner.example.com/oauth/callback" ], "hasClientSecret": true } } ``` ### Important behaviour - `clientSecret` is returned only when the client is first created. - If a client already exists, the plaintext secret is **not** returned again. - If the saved timezone is invalid, the response falls back to `UTC`. - A branding row is created automatically the first time this endpoint runs. - For many partners, this endpoint and `POST /api/update-api-client` are the only setup calls needed before moving to OAuth. ## 2) Update client settings Use this endpoint to maintain your callback URLs, rotate the secret, and update the branding metadata used in hosted flows. ### Supported request fields | Field | Type | Notes | |---|---|---| | `redirect_uris` | `string[]` | Must be a JSON array. These are stored as exact-match callback URIs. | | `regenerate_secret` | `boolean` | When `true`, rotates the client secret and returns the new plaintext secret once. | | `timezone` | `string` | IANA timezone name, for example `UTC` or `Australia/Brisbane`. | | `branding_display_name` | `string` | Partner brand name shown in hosted flows. | | `branding_subtitle` | `string` | Secondary line used in hosted flows. | | `branding_support_email` | `string` | Support contact shown in branding payloads. | | `branding_support_phone` | `string` | Support phone shown in branding payloads. | | `homepage_url` | `string` | Partner homepage URL. | | `support_url` | `string` | Partner support URL. | | `disable_dark_mode` | `boolean` | Hints that hosted pages should avoid dark mode. | ### Request ```bash curl -sS "$BASE_URL/api/update-api-client" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ --data '{ "redirect_uris": [ "https://partner.example.com/oauth/callback", "https://partner.example.com/oauth/callback-alt" ], "timezone": "Australia/Brisbane", "branding_display_name": "Farm Focus", "branding_subtitle": "Powered by Lightning Payroll", "branding_support_email": "support@farmfocus.example", "branding_support_phone": "1300 000 111", "homepage_url": "https://partner.example.com", "support_url": "https://partner.example.com/support", "disable_dark_mode": false }' ``` ### Response ```json { "message": "Client updated successfully", "new_secret": "unchanged", "timezone": "Australia/Brisbane", "configured_branding": { "displayName": "Farm Focus", "subtitle": "Powered by Lightning Payroll", "supportEmail": "support@farmfocus.example", "supportPhone": "1300 000 111", "homepageUrl": "https://partner.example.com", "supportUrl": "https://partner.example.com/support", "disableDarkMode": false, "publicBrandingToken": "public-branding-token" }, "effective_branding": { "source_type": "self", "source_customer_id": 12345, "source_client_id": null, "branding_token": "public-branding-token", "add_on_key": null, "add_on_label": "", "display_name": "Farm Focus", "subtitle": "Powered by Lightning Payroll", "company_name": "Farm Focus Pty Ltd", "support_email": "support@farmfocus.example", "support_phone": "1300 000 111", "homepage_url": "https://partner.example.com", "support_url": "https://partner.example.com/support", "has_logo": false, "has_dark_logo": false, "has_style": false, "disable_dark_mode": false, "uses_standalone_shell": false } } ``` ### Secret rotation example ```bash curl -sS "$BASE_URL/api/update-api-client" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ --data '{"regenerate_secret": true}' ``` The response returns the new secret in `new_secret`. Store it immediately. It is not recoverable later. ### Important behaviour - `redirect_uris` must be a list or the server returns `422` with `redirect_uris must be a list`. - Redirect URIs are treated as opaque strings. The OAuth flow later requires an **exact** string match. - Invalid `timezone` returns `422` with `Invalid timezone`. - If no client exists yet, this endpoint returns `404` with `Client not found`. ## 3) Branding assets These endpoints manage the images and custom CSS shown in hosted login and onboarding flows for your integration. ### Asset rules | Asset | Endpoint base | Allowed files | Max size | |---|---|---|---| | Primary logo | `/api/api-client/whitelabel-logo` | `jpg`, `jpeg`, `png`, `gif` | 1 MB | | Dark-mode logo | `/api/api-client/whitelabel-dark-logo` | `jpg`, `jpeg`, `png`, `gif` | 1 MB | | Stylesheet | `/api/api-client/whitelabel-style` | `.css`, UTF-8 encoded | 64 KB | ### Asset error handling Asset-management endpoints now use standard `4xx` status codes for user-correctable problems and still return a JSON body with an `error` field. Example overwrite response: ```json { "error": "Stylesheet already exists. Set overwrite_existing=true to replace it.", "requires_overwrite": true } ``` ### Common asset errors | Status | Meaning | |---|---| | `400` | Invalid upload such as empty file, wrong extension, unsupported image type, or oversized payload | | `404` | Attempted to delete an asset that does not exist | | `409` | Asset already exists and `overwrite_existing=true` was not supplied | | `422` | Stylesheet upload was not valid UTF-8 | On any non-`2xx` response, inspect the JSON body for `error` and, where relevant, `requires_overwrite`. ### Upload a primary logo ```bash curl -sS "$BASE_URL/api/api-client/whitelabel-logo" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -F "file=@partner-logo.png" ``` To replace an existing logo: ```bash curl -sS "$BASE_URL/api/api-client/whitelabel-logo" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -F "overwrite_existing=true" \ -F "file=@partner-logo.png" ``` ### Upload a dark-mode logo ```bash curl -sS "$BASE_URL/api/api-client/whitelabel-dark-logo" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -F "file=@partner-logo-dark.png" ``` ### Upload a stylesheet ```bash curl -sS "$BASE_URL/api/api-client/whitelabel-style" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -F "file=@partner-theme.css" ``` ### Read current asset metadata ```bash curl -sS "$BASE_URL/api/api-client/whitelabel-logo" \ -H "Authorization: Bearer $ADMIN_TOKEN" curl -sS "$BASE_URL/api/api-client/whitelabel-dark-logo" \ -H "Authorization: Bearer $ADMIN_TOKEN" curl -sS "$BASE_URL/api/api-client/whitelabel-style" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` ### Delete an asset ```bash curl -sS -X DELETE "$BASE_URL/api/api-client/whitelabel-style" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` ### Asset response fields - Logo endpoints return `whitelabel_logo` or `whitelabel_dark_logo`. - Style endpoints return `whitelabel_style`. - Common fields include: - `has_logo` / `has_dark_logo` / `has_style` - `image_name` or `css_name` - `image_data` or `css_text` - `updated_at` ## 4) Public branding endpoints These endpoints are unauthenticated and are used by hosted login and onboarding flows. ### Resolve branding by `client_id` ```bash curl -sS "$BASE_URL/api/public-branding?client_id=your-client-id" ``` ### Resolve branding by public branding token ```bash curl -sS "$BASE_URL/api/public-branding?branding_token=public-branding-token" ``` ### Fetch logo bytes ```bash curl -sS "$BASE_URL/api/public-branding/logo?client_id=your-client-id" --output logo.bin curl -sS "$BASE_URL/api/public-branding/logo?client_id=your-client-id&mode=dark" --output logo-dark.bin ``` ### Public branding notes - calling `/api/public-branding` with neither `client_id` nor `branding_token` returns the default Lightning Payroll branding payload - `client_id` lookup returns `404` if the client does not exist. - `client_id` lookup returns `403` if the owning customer is not an API admin. - `branding_token` lookup returns `404` if the branding record is missing. - `/api/public-branding/logo` falls back to the primary logo when `mode=dark` is requested but no dark logo exists. - for partner preview and hosted-flow branding checks, treat `/api/public-branding` as the canonical public branding API. ## 5) Connection monitoring and support All monitoring endpoints require the API-admin bearer token and an existing client. Request-log retention is currently 90 days. ### Overview ```bash curl -sS "$BASE_URL/api/api-client/overview" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` Returns roll-up metrics such as: - `totalConnections` - `activeConnections` - `totalTokens` - `activeTokens` - `authsLast30Days` - `tokensIssuedLast30Days` - `requestsLast90Days` - `errorRateLast90Days` - `errorsLast24Hours` - `errorsLast7Days` - `errorsLast30Days` - `errorsLast90Days` - `avgDurationMsLast90Days` - `lastActivityAt` - `lastRequestAt` ### Connections ```bash curl -sS "$BASE_URL/api/api-client/connections?status=all" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` Supported `status` values: - `all` - `active` - `inactive` Each connection item includes: - `customerId` - `companyName` - `email` - `status` - `activeTokens` - `totalTokens` - `revokedTokens` - `expiredTokens` - `firstAuthorizedAt` - `lastAuthAt` - `lastTokenIssuedAt` - `tokensLast30Days` - `authsLast30Days` - `requestsLast24Hours` - `requestsLast7Days` - `requestsLast30Days` - `requestsLast90Days` - `errorRateLast90Days` - `avgDurationMsLast90Days` - `lastRequestAt` - `scopes` ### Revoke one customer connection ```bash curl -sS -X DELETE "$BASE_URL/api/api-client/connections/17193" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` Response: ```json { "message": "Connection revoked", "revokedTokens": 1 } ``` This revokes all non-revoked refresh tokens for that customer under your client. It does not delete historical logs. If the customer has no refresh-token rows for your client, the server returns `404` with `No active connection found for that customer`. ### Activity feed ```bash curl -sS "$BASE_URL/api/api-client/activity?limit=50" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` Optional filters: - `customer_id` - `limit` (1 to 250) Event types currently returned: - `authorization_code_issued` - `refresh_token_issued` ### Error summary ```bash curl -sS "$BASE_URL/api/api-client/errors?limit=100" \ -H "Authorization: Bearer $ADMIN_TOKEN" ``` Returns: - summary counts for the last 24 hours, 7 days, 30 days, and 90 days - top status-code breakdown - top failing endpoints - recent error entries with customer identifiers, method, path, status, error details, request ID, and timestamp ## Interpreting `effective_branding.source_type` `effective_branding.source_type` tells you where the resolved branding came from. It can currently be: - `none` - `self` - `oauth_client` - `add_on` For most API-admin setup work you will see `self` once your own branding identity exists. ## Operational recommendations 1. Call `GET /api/init-api-client` once during partner setup and store the returned `clientId`. 2. Register every production and test callback URL you plan to use in `redirect_uris`. 3. Treat the client secret like a password. If exposed, rotate it immediately with `regenerate_secret=true`. 4. Check upload responses for `error` on any non-`2xx` response, and handle `409` by prompting for an overwrite confirmation. 5. Use `/api/api-client/connections`, `/api/api-client/activity`, and `/api/api-client/errors` as your first-line support tools when a customer reports an integration issue.