API reference
Pay
Pay history. Reading your own pay works with a key; recording pay happens in the web app.
3 actions · base URL https://api.bizisy.com/v1 · generated from the same definitions as the API.
List a person's pay#
POST/v1/org/pay.listRead
Returns a person's pay history (amount, currency, period: year, month or hour; effective from valid_from until the next row) and the row in force today. Visible to the person themselves and to owners, admins and HR in the app; managers never see pay. Over MCP or an API key, pay is only returned for yourself.
- Who can call it
- Manage key any Manage role
Me key anyone - Keys and apps
- Only your own pay.
- MCP tool
org_pay_liston My Workplace, HR Assistant- Method
POSTwith a JSON body, orGETwith the input as query parameters
Input
person_idstringrequired
Returns
person_idstringrequiredcurrentobject | nullrequired8 fields
idstringrequiredvalid_fromstringrequiredvalid_tostring | nullrequiredamountnumberrequiredcurrencystringrequiredperiod"year" | "month" | "hour"requirednotestring | nullrequiredcreated_atstringrequired
historyobject[]required8 fields
idstringrequiredvalid_fromstringrequiredvalid_tostring | nullrequiredamountnumberrequiredcurrencystringrequiredperiod"year" | "month" | "hour"requirednotestring | nullrequiredcreated_atstringrequired
payroll_changed_atstring | nullrequired
Errors
validation_failed unauthenticated forbidden not_found rate_limited internal
curl https://api.bizisy.com/v1/org/pay.list \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"person_id":"p1"}'const res = await fetch('https://api.bizisy.com/v1/org/pay.list', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"person_id": "p1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os
import requests
res = requests.post(
"https://api.bizisy.com/v1/org/pay.list",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}"},
json={
"person_id": "p1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"person_id": "p1",
"current": {
"id": "pay1",
"valid_from": "2024-01-15",
"valid_to": null,
"amount": 42000,
"currency": "EUR",
"period": "year",
"note": null,
"created_at": "2026-10-04T10:00:00.000Z"
},
"history": [
{
"id": "pay1",
"valid_from": "2024-01-15",
"valid_to": null,
"amount": 42000,
"currency": "EUR",
"period": "year",
"note": null,
"created_at": "2026-10-04T10:00:00.000Z"
}
],
"payroll_changed_at": "2026-09-01T10:00:00.000Z"
}
}Record a pay change#
POST/v1/org/pay.addWrite
Records pay from effective_date (YYYY-MM-DD, may be in the future): amount (gross, at most 2 decimals), currency (ISO code, e.g. EUR), period (year, month or hour) and an optional note. It applies until the next recorded change. One row per date: a second change on the same date is refused (remove the wrong one with org_pay_remove first). Only in the app (never over MCP or an API key), by owners, admins and HR, never for their own pay; an HR member's pay only by an owner or admin, an owner's only by another owner. When Settings → Approval rules requires HR approval for pay changes, a request is created instead (approval in the result) and the pay applies when another owner, admin or HR member approves it.
- Web app only
- Refused for API keys and connected apps. Pay is recorded in the app only.
- MCP tool
org_pay_addon HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key prevents a second run, but the result is never stored (it holds a secret or personal data): a retry gets a 409 that points to Activity
Input
person_idstringrequiredeffective_datestringrequiredamountnumberrequiredFrom 0 to 100000000.
currencyanyrequiredperiod"year" | "month" | "hour"requirednotestringUp to 200 characters.
Returns
person_idstringrequiredcurrentobject | nullrequired8 fields
idstringrequiredvalid_fromstringrequiredvalid_tostring | nullrequiredamountnumberrequiredcurrencystringrequiredperiod"year" | "month" | "hour"requirednotestring | nullrequiredcreated_atstringrequired
historyobject[]required8 fields
idstringrequiredvalid_fromstringrequiredvalid_tostring | nullrequiredamountnumberrequiredcurrencystringrequiredperiod"year" | "month" | "hour"requirednotestring | nullrequiredcreated_atstringrequired
payroll_changed_atstring | nullrequiredapprovalobject | nullrequired11 fields
idstringrequiredstatus"pending" | "approved"requiredwaiting_for"manager" | "hr"requiredapproversstring[]requiredautomaticbooleanrequirednote"proposed_by_approver" | "no_other_approver"requiredfallbackbooleanrequiredteam_leadobject | nullrequired3 fields
unit_idstringrequiredunit_namestringrequiredreason"no_manager" | "manager_left"required
team_lead_blockedobject | nullrequired3 fields
unit_idstringrequiredunit_namestringrequiredwhat"lead" | "removed" | "moved" | "archived"required
untrusted"no_login" | "invited_by_proposer"requiredthen"manager" | "hr"required
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/org/pay.add \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"person_id": "p1",
"effective_date": "2026-11-01",
"amount": 21.5,
"currency": "EUR",
"period": "hour",
"note": "Promotion"
}'const res = await fetch('https://api.bizisy.com/v1/org/pay.add', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"person_id": "p1",
"effective_date": "2026-11-01",
"amount": 21.5,
"currency": "EUR",
"period": "hour",
"note": "Promotion"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/org/pay.add",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"person_id": "p1",
"effective_date": "2026-11-01",
"amount": 21.5,
"currency": "EUR",
"period": "hour",
"note": "Promotion",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"person_id": "p1",
"current": {
"id": "pay1",
"valid_from": "2024-01-15",
"valid_to": null,
"amount": 42000,
"currency": "EUR",
"period": "year",
"note": null,
"created_at": "2026-10-04T10:00:00.000Z"
},
"history": [
{
"id": "pay1",
"valid_from": "2024-01-15",
"valid_to": null,
"amount": 42000,
"currency": "EUR",
"period": "year",
"note": null,
"created_at": "2026-10-04T10:00:00.000Z"
}
],
"payroll_changed_at": "2026-09-01T10:00:00.000Z",
"approval": null
}
}Remove a pay row (fix a mistake)#
POST/v1/org/pay.removeDestructive
Deletes one pay row recorded by mistake (pay_id from org_pay_list); the previous row then applies until the next one. Same rules as org_pay_add: in the app only, never your own pay. When Settings → Approval rules requires HR approval for pay changes, removing the row in force today or a scheduled one creates a request instead (approval in the result); removing an older row applies at once.
- Web app only
- Refused for API keys and connected apps. Pay is changed in the app only.
- MCP tool
org_pay_removeon HR Assistant- Preview
?dry_run=trueruns every check and saves nothing- Retries
- An Idempotency-Key replays the first result
Input
pay_idstringrequired
Returns
person_idstringrequiredcurrentobject | nullrequired8 fields
idstringrequiredvalid_fromstringrequiredvalid_tostring | nullrequiredamountnumberrequiredcurrencystringrequiredperiod"year" | "month" | "hour"requirednotestring | nullrequiredcreated_atstringrequired
historyobject[]required8 fields
idstringrequiredvalid_fromstringrequiredvalid_tostring | nullrequiredamountnumberrequiredcurrencystringrequiredperiod"year" | "month" | "hour"requirednotestring | nullrequiredcreated_atstringrequired
payroll_changed_atstring | nullrequiredapprovalobject | nullrequired11 fields
idstringrequiredstatus"pending" | "approved"requiredwaiting_for"manager" | "hr"requiredapproversstring[]requiredautomaticbooleanrequirednote"proposed_by_approver" | "no_other_approver"requiredfallbackbooleanrequiredteam_leadobject | nullrequired3 fields
unit_idstringrequiredunit_namestringrequiredreason"no_manager" | "manager_left"required
team_lead_blockedobject | nullrequired3 fields
unit_idstringrequiredunit_namestringrequiredwhat"lead" | "removed" | "moved" | "archived"required
untrusted"no_login" | "invited_by_proposer"requiredthen"manager" | "hr"required
Errors
validation_failed unauthenticated forbidden not_found conflict rate_limited internal
curl https://api.bizisy.com/v1/org/pay.remove \
-H "Authorization: Bearer $BIZISY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"pay_id":"pay1"}'const res = await fetch('https://api.bizisy.com/v1/org/pay.remove', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BIZISY_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"pay_id": "pay1"
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
console.log(body.data);import os, uuid
import requests
res = requests.post(
"https://api.bizisy.com/v1/org/pay.remove",
headers={"Authorization": f"Bearer {os.environ['BIZISY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"pay_id": "pay1",
},
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
print(body["data"]){
"data": {
"person_id": "p1",
"current": null,
"history": [],
"payroll_changed_at": null,
"approval": null
}
}Something missing or wrong on this page? Write to hello@bizisy.com.