API reference
Base URL https://api.odinpayroll.com (sandbox: https://api.sandbox.odinpayroll.com). Authenticate with a partner API key as a Bearer token. Generated from openapi.json, which the API's CI keeps in step with the code.
API keys
List partner API keys
Responses: 200, 400, 401, 403, 404, 409
Create a partner API key (shown once)
| Body field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | |
expiresInDays | integer |
Responses: 201, 400, 401, 403, 404, 409
Revoke a partner API key
Responses: 200, 400, 401, 403, 404, 409
Audit
Audit entries for the active context (x-odin-context), newest first
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404
Outbound email captured for the active context (x-odin-context: global or partner:<id>)
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404
Authentication
Verify email and password
| Body field | Type | Required | Notes |
|---|---|---|---|
email | string | yes | |
password | string | yes |
Responses: 200, 400, 401, 429
Complete sign-in with an authenticator code
| Body field | Type | Required | Notes |
|---|---|---|---|
ticket | string | yes | |
code | string | yes | pattern ^\d{6}$ |
Responses: 200, 400, 401, 429
Email a one-time sign-in code
| Body field | Type | Required | Notes |
|---|---|---|---|
ticket | string | yes |
Responses: 200, 400, 401, 429
Complete sign-in with an emailed code
| Body field | Type | Required | Notes |
|---|---|---|---|
ticket | string | yes | |
code | string | yes | pattern ^\d{6}$ |
Responses: 200, 400, 401, 429
Email a sign-in link
| Body field | Type | Required | Notes |
|---|---|---|---|
email | string | yes |
Responses: 202, 400, 401, 429
Use a sign-in link
| Body field | Type | Required | Notes |
|---|---|---|---|
token | string | yes |
Responses: 200, 400, 401, 429
Email a password reset link
| Body field | Type | Required | Notes |
|---|---|---|---|
email | string | yes |
Responses: 202, 400, 401, 429
Set a new password from a reset link
| Body field | Type | Required | Notes |
|---|---|---|---|
token | string | yes | |
password | string | yes |
Responses: 200, 400, 401, 429
Accept an invitation
| Body field | Type | Required | Notes |
|---|---|---|---|
token | string | yes | |
name | string | yes | |
password | string |
Responses: 200, 400, 401, 429
End the current session
Responses: 200, 401, 403, 404
Billing
Billing method and status
Responses: 200, 400, 401, 403, 404, 502
Set the billing method (Platform Operator)
| Body field | Type | Required | Notes |
|---|---|---|---|
method | string | yes | one of stripe, odin_osa |
osaEndpoints | object | ||
osaEndpoints.employees | string | ||
osaEndpoints.entities | string | ||
osaEndpoints.platform | string | ||
osaTokens | object | ||
osaTokens.employees | string | ||
osaTokens.entities | string | ||
osaTokens.platform | string |
Responses: 200, 400, 401, 403, 404, 502
Start a Stripe page to add a payment method or manage billing
| Body field | Type | Required | Notes |
|---|---|---|---|
kind | string | yes | one of setup, portal |
Responses: 200, 400, 401, 403, 404, 502
Month-to-date usage: employees paid, payroll entities, platform seat
Responses: 200, 400, 401, 403, 404, 502
Branding
Public branding for a host, used before sign-in
Parameters: host (query)
Responses: 200
Get partner branding
Responses: 200, 400, 401, 403, 404
Set partner branding. Colours failing WCAG AA contrast are rejected with the measured ratio.
| Body field | Type | Required | Notes |
|---|---|---|---|
productName | string | yes | |
logoUrl | string | ||
faviconUrl | string | ||
colors | object | yes | |
colors.accent | string | yes | pattern ^#[0-9A-Fa-f]{6}$ |
colors.accentText | string | yes | pattern ^#[0-9A-Fa-f]{6}$ |
colors.accentOnDark | string | yes | pattern ^#[0-9A-Fa-f]{6}$ |
colors.emberCta | string | yes | pattern ^#[0-9A-Fa-f]{6}$ |
colors.chrome | string | yes | pattern ^#[0-9A-Fa-f]{6}$ |
supportEmail | string | ||
supportUrl | string | ||
termsUrl | string | ||
privacyUrl | string |
Responses: 200, 400, 401, 403, 404
Me
The signed-in person, their memberships and staff state
Responses: 200, 401, 403, 404
Contexts the person can switch between
Responses: 200, 401, 403, 404
Scopes and feature toggles for the active context (x-odin-context header)
Responses: 200, 401, 403, 404
Start authenticator app enrollment
Responses: 200, 401, 403, 404
Confirm authenticator app enrollment
| Body field | Type | Required | Notes |
|---|---|---|---|
code | string | yes | pattern ^\d{6}$ |
Responses: 200, 400, 401, 403, 404
List personal access tokens
Responses: 200, 401, 403, 404
Create a personal access token (shown once)
| Body field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | |
expiresInDays | integer |
Responses: 201, 401, 403, 404
Revoke a personal access token
Responses: 200, 401, 403, 404
In-app notifications, newest first
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404
Mark one notification read (`all` marks every one)
Responses: 200, 400, 401, 403, 404
Members
List partner administrators
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404, 409
Invite a partner administrator
| Body field | Type | Required | Notes |
|---|---|---|---|
email | string | yes | |
role | string | yes |
Responses: 202, 400, 401, 403, 404, 409
Remove a partner administrator
Responses: 200, 400, 401, 403, 404, 409
List organization administrators
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404, 409
Invite an organization administrator
| Body field | Type | Required | Notes |
|---|---|---|---|
email | string | yes | |
role | string | yes |
Responses: 202, 400, 401, 403, 404, 409
Remove an organization administrator
Responses: 200, 400, 401, 403, 404, 409
Organizations
List a partner's organizations
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404, 409
Create an organization
| Body field | Type | Required | Notes |
|---|---|---|---|
name | string | yes |
Responses: 201, 400, 401, 403, 404, 409
Get an organization
Responses: 200, 400, 401, 403, 404, 409
Partners
List partners (Odin staff)
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404, 409
Create a partner (Platform Operator)
| Body field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | |
slug | string | yes | pattern ^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$ |
Responses: 201, 400, 401, 403, 404, 409
Get a partner
Responses: 200, 400, 401, 403, 404, 409
Resolved feature toggles
Responses: 200, 400, 401, 403, 404, 409
Set feature toggles (full map; omitted keys default on)
| Body field | Type | Required | Notes |
|---|---|---|---|
features | object | yes |
Responses: 200, 400, 401, 403, 404, 409
Payroll entities
Create a payroll entity (one legal employer) in an organization
Parameters: idempotency-key (header)
| Body field | Type | Required | Notes |
|---|---|---|---|
legalName | string | yes | |
doingBusinessAs | string | ||
website | string | ||
admin | object | yes | The company's primary business user in the payroll engine (usually the owner). |
admin.firstName | string | yes | |
admin.lastName | string | yes | |
admin.email | string | yes | |
admin.phone | string | yes | pattern ^\d{10}$ |
termsAccepted | boolean | yes | one of true |
Responses: 200, 201, 400, 401, 403, 404, 409, 502
List an organization's payroll entities, with live details from the payroll engine
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404, 409, 502
Get a payroll entity
Responses: 200, 400, 401, 403, 404, 409, 502
Staff
View the product as another person, read-only (Support, Super Admin)
| Body field | Type | Required | Notes |
|---|---|---|---|
personId | string | yes | pattern ^[A-Za-z0-9_-]{1,64}$ |
reason | string | yes |
Responses: 200, 400, 401, 403, 404, 409
Stop acting as someone
Responses: 200, 400, 401, 403, 404, 409
Start a time-boxed break-glass elevation (Super Admin)
| Body field | Type | Required | Notes |
|---|---|---|---|
scopeType | string | yes | one of partner, organization |
scopeId | string | yes | pattern ^[A-Za-z0-9_-]{1,64}$ |
reason | string | yes | |
minutes | integer | yes |
Responses: 201, 400, 401, 403, 404, 409
Active elevations across the platform
Responses: 200, 400, 401, 403, 404, 409
End the current elevation early
Responses: 200, 400, 401, 403, 404, 409
Find a person by email, with their memberships (Odin staff)
Parameters: email (query, required)
Responses: 200, 400, 401, 403, 404, 409
Webhooks and events
List webhook endpoints
Responses: 200, 400, 401, 403, 404
Add a webhook endpoint. The signing secret is returned once.
| Body field | Type | Required | Notes |
|---|---|---|---|
url | string | yes | |
events | string[] | ||
description | string |
Responses: 201, 400, 401, 403, 404
Remove a webhook endpoint
Responses: 200, 400, 401, 403, 404
Send a signed test event now
Responses: 200, 400, 401, 403, 404
Recent delivery attempts
Responses: 200, 400, 401, 403, 404
The partner's event log, newest first (for polling or replay)
Parameters: limit (query), cursor (query)
Responses: 200, 400, 401, 403, 404