Every request to the Payroll API is authenticated. This article covers the two methods, the conventions every request follows, and the shape of an error. It is generated from the API reference, version 0.5.0.
How do I authenticate?
There are two ways to authenticate, and which one you want depends on what you are building.
API key: for server-to-server integrations. Send both headers on every request:
curl "https://payroll-api.moonworkers.co.uk/api/employer/" \
-H "X-API-Key: YOUR_API_KEY" \
-H "X-Client-Secret: YOUR_CLIENT_SECRET"
import requests
headers = {
'X-API-Key': 'YOUR_API_KEY',
'X-Client-Secret': 'YOUR_CLIENT_SECRET',
}
response = requests.get('https://payroll-api.moonworkers.co.uk/api/employer/', headers=headers)
const response = await fetch('https://payroll-api.moonworkers.co.uk/api/employer/', {
headers: {
'X-API-Key': 'YOUR_API_KEY',
'X-Client-Secret': 'YOUR_CLIENT_SECRET',
},
})
Bearer token: used by the Moonworkers web app. POST /api/auth/login/ returns an
access_token; send it as a bearer token, and refresh it through
POST /api/auth/token/refresh/ when it expires:
curl "https://payroll-api.moonworkers.co.uk/api/employer/" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
The authentication endpoints themselves: login, registration, activation, password reset and the social OAuth flow: exist for the web app. If you are building an integration, use an API key rather than logging in as a user.
A handful of endpoints take a bearer token only, and refuse an API key with
TokenAuthRequiredException (403). They act on behalf of the signed-in person rather than
on the account: their own profile, password and two-factor settings, the notifications
addressed to them, the team roster they administer, and the billing calls that hand a
human a Stripe checkout page. An API key names an account, not a person, so on these
routes it has no one to act as. Each one says so at the top of its description, and lists
only the bearer scheme under its padlock.
Which base URL do I use?
The sandbox is at https://payroll-api-sandbox.moonworkers.co.uk and production at https://payroll-api.moonworkers.co.uk. The examples below use production; swap the host while you build. The sandbox also has a Swagger UI at https://payroll-api-sandbox.moonworkers.co.uk/api/docs/ to try calls in the browser.
How are requests shaped?
Most resources hang off an employer: /api/employer/{employer_pk}/..., and reports are
nested the same way: employer-level ones such as the P30 and P32 under
/api/employer/{employer_pk}/report/..., and per-employee documents such as the P45, P60
and P11D under /api/employer/{employer_pk}/employee/{employee_pk}/report/....
Every path ends in a trailing slash. Without it a GET redirects and a POST fails.
Updates use PUT and replace the whole record. PATCH is not supported, so send every field you want to keep, not just the ones you are changing.
How do errors come back?
A failed request returns the error class name and a message:
{"errorCode": "PayrunNotEditableException", "errorMessage": "This payrun is finalized."}
Branch on errorCode rather than on the message text: messages may be reworded, codes
will not. Authentication failures are the exception: they come from the framework itself
and return {"detail": "..."}.
The full list of error codes is in the "Payroll API error codes" articles.
Get started
The full reference is at https://payroll-api.moonworkers.co.uk/api/redoc/. No key yet? See "How do I get a Payroll API sandbox key?".