{
  "openapi": "3.0.3",
  "info": {
    "title": "Soom API",
    "version": "v1",
    "description": "Read your company’s data in Soom from your own software, and make the changes Soom approved. A company or HR admin registers your app in Settings ▸ Integrations ▸ Soom API, Soom approves it, and your app swaps its client id and secret for an access token that works for an hour. An app reads only what it was approved for, and changes something only when that change was approved too."
  },
  "servers": [
    {
      "url": "https://api.soom.co.in/api/public/v1"
    }
  ],
  "security": [
    {
      "soomApp": []
    }
  ],
  "tags": [
    {
      "name": "Employees",
      "description": "The people in the company: who they are, where they sit and who they report to. And adding someone new."
    },
    {
      "name": "Company setup",
      "description": "How the company is set up in Soom: its departments, designations, branches, shifts and holidays, each with the id employees point at."
    },
    {
      "name": "Attendance",
      "description": "Each person’s days: clock-in and clock-out times and how the day turned out, the overtime they claimed, and what they asked to change: a day’s times, or the shift they work. And recording clock-ins from a clock of your own."
    },
    {
      "name": "Leave",
      "description": "Leave people applied for or HR added, the company’s leave types, and what each person has left. And applying for leave for someone."
    },
    {
      "name": "Time off",
      "description": "Requests to work from home, and permissions: a few hours away during a working day."
    },
    {
      "name": "Assets",
      "description": "The company’s equipment: what it owns, who has each item now and who had it before, and what people have asked for."
    },
    {
      "name": "Expenses",
      "description": "Expense claims people made and payment vouchers the company recorded: what was spent, where each stands and how it was paid. Receipts, bank details and approvers are never shared."
    },
    {
      "name": "Documents",
      "description": "Which documents each person has on file, by the company’s document categories, and the required ones they haven’t given yet. The files, their names and the numbers on them never leave Soom."
    },
    {
      "name": "Onboarding",
      "description": "Each joiner’s onboarding: its steps and its checklist, and which are done. What people signed, uploaded or filled in stays in Soom."
    },
    {
      "name": "Daily reports",
      "description": "What people wrote they worked on each day: each piece of work, how long it took, where it stands, and the client it was for."
    },
    {
      "name": "Announcements",
      "description": "What the company announced to everyone in Soom."
    },
    {
      "name": "Projects",
      "description": "Projects and their tasks: who owns and works on each, where every task stands, who has it and when it is due. Comments and files on tasks are never shared."
    },
    {
      "name": "Performance",
      "description": "Review cycles, where each person’s review stands, and their goals. A final rating goes out only once the review is released to the person. What anyone wrote in a review, and goals still in draft, stay in Soom."
    },
    {
      "name": "Recruitment",
      "description": "The company’s job openings and the candidates for them: each opening’s pipeline, and where every candidate stands. And adding the people who apply, with their resume. Salary ranges, and candidates’ phones, resumes, notes, ratings and answers, stay in Soom."
    },
    {
      "name": "Clients",
      "description": "The companies your people work for: each client, who of yours works for which, and what you invoiced them. Contacts, addresses, tax numbers and the rate for each person stay in Soom."
    },
    {
      "name": "Payroll",
      "description": "Each month’s payroll and each person’s payslip totals: gross pay, deductions and net pay. An app reads them only when Soom approved Payroll for it. Salaries, the lines of a payslip, bank details and PAN, UAN, PF and ESI numbers stay in Soom. A company that runs its payroll in Xero gets PAYROLL_IN_XERO."
    }
  ],
  "paths": {
    "/employees": {
      "get": {
        "operationId": "list-employees",
        "tags": [
          "Employees"
        ],
        "summary": "List employees",
        "description": "Everyone in the company, in employee code order. People who have left are only listed when you ask for them. Needs an app approved for Employees.",
        "security": [
          {
            "soomApp": [
              "employees"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "current (the default) is everyone still working, exited is people who have left, all is both.",
            "schema": {
              "type": "string",
              "enum": [
                "current",
                "exited",
                "all"
              ]
            },
            "example": "current"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employeeCode",
                              "firstName",
                              "lastName",
                              "email",
                              "jobTitle",
                              "employeeType",
                              "status",
                              "department",
                              "designation",
                              "location",
                              "reportingManager",
                              "hireDate",
                              "exitDate",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the person."
                              },
                              "employeeCode": {
                                "type": "string",
                                "description": "The code your company gave them.",
                                "nullable": true
                              },
                              "firstName": {
                                "type": "string",
                                "description": "First name."
                              },
                              "lastName": {
                                "type": "string",
                                "description": "Last name."
                              },
                              "email": {
                                "type": "string",
                                "description": "The email they sign in to Soom with."
                              },
                              "jobTitle": {
                                "type": "string",
                                "description": "Job title.",
                                "nullable": true
                              },
                              "employeeType": {
                                "type": "string",
                                "description": "Kind of employment.",
                                "enum": [
                                  "administrator",
                                  "consultant",
                                  "contractor",
                                  "fulltimehourly",
                                  "fulltimeinternship",
                                  "fulltimesalaried",
                                  "parttimehourly",
                                  "parttimeinternship",
                                  "parttimesalaried",
                                  "casual"
                                ],
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where they are in their time with the company. invited is someone who hasn’t signed in yet.",
                                "enum": [
                                  "invited",
                                  "active",
                                  "probation",
                                  "onNotice",
                                  "exited",
                                  "suspended"
                                ]
                              },
                              "department": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List departments."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "Their department.",
                                "nullable": true
                              },
                              "designation": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List designations."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "Their designation.",
                                "nullable": true
                              },
                              "location": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List locations."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The branch they work at. Their days and shift times run on its time zone.",
                                "nullable": true
                              },
                              "reportingManager": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who they report to.",
                                "nullable": true
                              },
                              "hireDate": {
                                "type": "string",
                                "format": "date",
                                "description": "The day they joined.",
                                "nullable": true
                              },
                              "exitDate": {
                                "type": "string",
                                "format": "date",
                                "description": "The day they left, when they have.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f1c2ab7e94d0012a3c4d5",
                        "employeeCode": "EMP0032",
                        "firstName": "Priya",
                        "lastName": "Sharma",
                        "email": "priya.sharma@yourcompany.com",
                        "jobTitle": "Senior Developer",
                        "employeeType": "fulltimesalaried",
                        "status": "active",
                        "department": {
                          "id": "665f0a11b7e94d0012a3b101",
                          "name": "Engineering"
                        },
                        "designation": {
                          "id": "665f0a11b7e94d0012a3b201",
                          "name": "Senior Developer"
                        },
                        "location": {
                          "id": "665f0a11b7e94d0012a3b301",
                          "name": "Hyderabad"
                        },
                        "reportingManager": {
                          "id": "665f1c2ab7e94d0012a3c4c1",
                          "employeeCode": "EMP0007",
                          "name": "Ravi Kumar"
                        },
                        "hireDate": "2024-06-03",
                        "exitDate": null,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "add-employee",
        "tags": [
          "Employees"
        ],
        "summary": "Add an employee",
        "description": "Adds one person, as HR ▸ Employees ▸ Add employee does: Soom emails them an invite to sign in, and HR sees they were added through the Soom API. They are invited until they sign in. Needs an app approved for Add employees.",
        "security": [
          {
            "soomApp": [
              "add_employees"
            ]
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "firstName",
                  "lastName",
                  "email"
                ],
                "additionalProperties": false,
                "properties": {
                  "firstName": {
                    "type": "string",
                    "description": "First name."
                  },
                  "lastName": {
                    "type": "string",
                    "description": "Last name."
                  },
                  "email": {
                    "type": "string",
                    "description": "The email they will sign in with. No one in Soom can have it already."
                  },
                  "employeeCode": {
                    "type": "string",
                    "description": "Their employee code. The one after your latest code when left out."
                  },
                  "jobTitle": {
                    "type": "string",
                    "description": "Job title."
                  },
                  "employeeType": {
                    "type": "string",
                    "description": "Kind of employment.",
                    "enum": [
                      "administrator",
                      "consultant",
                      "contractor",
                      "fulltimehourly",
                      "fulltimeinternship",
                      "fulltimesalaried",
                      "parttimehourly",
                      "parttimeinternship",
                      "parttimesalaried",
                      "casual"
                    ]
                  },
                  "departmentId": {
                    "type": "string",
                    "description": "Their department, an id from List departments."
                  },
                  "designationId": {
                    "type": "string",
                    "description": "Their designation, an id from List designations."
                  },
                  "locationId": {
                    "type": "string",
                    "description": "The branch they work at, an id from List locations."
                  },
                  "shiftId": {
                    "type": "string",
                    "description": "A shift of their own, an id from List shifts. Without one they work the default shift."
                  },
                  "reportingManagerId": {
                    "type": "string",
                    "description": "Who they report to, the id of someone still working, from List employees."
                  },
                  "hireDate": {
                    "type": "string",
                    "format": "date",
                    "description": "The day they join, like 2026-12-01."
                  }
                }
              },
              "example": {
                "firstName": "Anjali",
                "lastName": "Verma",
                "email": "anjali.verma@yourcompany.com",
                "jobTitle": "Senior Developer",
                "employeeType": "fulltimesalaried",
                "departmentId": "665f0a11b7e94d0012a3b101",
                "designationId": "665f0a11b7e94d0012a3b201",
                "locationId": "665f0a11b7e94d0012a3b301",
                "reportingManagerId": "665f1c2ab7e94d0012a3c4c1",
                "hireDate": "2026-12-01"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "What was made.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "employee",
                        "inviteEmailSent"
                      ],
                      "properties": {
                        "employee": {
                          "type": "object",
                          "required": [
                            "id",
                            "employeeCode",
                            "firstName",
                            "lastName",
                            "email",
                            "jobTitle",
                            "employeeType",
                            "status",
                            "department",
                            "designation",
                            "location",
                            "reportingManager",
                            "hireDate",
                            "exitDate",
                            "updatedAt"
                          ],
                          "properties": {
                            "id": {
                              "type": "string",
                              "description": "Soom’s id for the person."
                            },
                            "employeeCode": {
                              "type": "string",
                              "description": "The code your company gave them.",
                              "nullable": true
                            },
                            "firstName": {
                              "type": "string",
                              "description": "First name."
                            },
                            "lastName": {
                              "type": "string",
                              "description": "Last name."
                            },
                            "email": {
                              "type": "string",
                              "description": "The email they sign in to Soom with."
                            },
                            "jobTitle": {
                              "type": "string",
                              "description": "Job title.",
                              "nullable": true
                            },
                            "employeeType": {
                              "type": "string",
                              "description": "Kind of employment.",
                              "enum": [
                                "administrator",
                                "consultant",
                                "contractor",
                                "fulltimehourly",
                                "fulltimeinternship",
                                "fulltimesalaried",
                                "parttimehourly",
                                "parttimeinternship",
                                "parttimesalaried",
                                "casual"
                              ],
                              "nullable": true
                            },
                            "status": {
                              "type": "string",
                              "description": "Where they are in their time with the company. invited is someone who hasn’t signed in yet.",
                              "enum": [
                                "invited",
                                "active",
                                "probation",
                                "onNotice",
                                "exited",
                                "suspended"
                              ]
                            },
                            "department": {
                              "type": "object",
                              "required": [
                                "id",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for it, the id in List departments."
                                },
                                "name": {
                                  "type": "string",
                                  "description": "Its name."
                                }
                              },
                              "description": "Their department.",
                              "nullable": true
                            },
                            "designation": {
                              "type": "object",
                              "required": [
                                "id",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for it, the id in List designations."
                                },
                                "name": {
                                  "type": "string",
                                  "description": "Its name."
                                }
                              },
                              "description": "Their designation.",
                              "nullable": true
                            },
                            "location": {
                              "type": "object",
                              "required": [
                                "id",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for it, the id in List locations."
                                },
                                "name": {
                                  "type": "string",
                                  "description": "Its name."
                                }
                              },
                              "description": "The branch they work at. Their days and shift times run on its time zone.",
                              "nullable": true
                            },
                            "reportingManager": {
                              "type": "object",
                              "required": [
                                "id",
                                "employeeCode",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for the person, the id in List employees."
                                },
                                "employeeCode": {
                                  "type": "string",
                                  "description": "The code your company gave them.",
                                  "nullable": true
                                },
                                "name": {
                                  "type": "string",
                                  "description": "First and last name."
                                }
                              },
                              "description": "Who they report to.",
                              "nullable": true
                            },
                            "hireDate": {
                              "type": "string",
                              "format": "date",
                              "description": "The day they joined.",
                              "nullable": true
                            },
                            "exitDate": {
                              "type": "string",
                              "format": "date",
                              "description": "The day they left, when they have.",
                              "nullable": true
                            },
                            "updatedAt": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                              "nullable": true
                            }
                          },
                          "description": "The new person, as List employees gives them."
                        },
                        "inviteEmailSent": {
                          "type": "boolean",
                          "description": "false when the invite email couldn’t go. HR can send it again from HR ▸ Employees."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "employee": {
                      "id": "665f1c2ab7e94d0012a3c4e9",
                      "employeeCode": "EMP0033",
                      "firstName": "Anjali",
                      "lastName": "Verma",
                      "email": "anjali.verma@yourcompany.com",
                      "jobTitle": "Senior Developer",
                      "employeeType": "fulltimesalaried",
                      "status": "invited",
                      "department": {
                        "id": "665f0a11b7e94d0012a3b101",
                        "name": "Engineering"
                      },
                      "designation": {
                        "id": "665f0a11b7e94d0012a3b201",
                        "name": "Senior Developer"
                      },
                      "location": {
                        "id": "665f0a11b7e94d0012a3b301",
                        "name": "Hyderabad"
                      },
                      "reportingManager": {
                        "id": "665f1c2ab7e94d0012a3c4c1",
                        "employeeCode": "EMP0007",
                        "name": "Ravi Kumar"
                      },
                      "hireDate": "2026-12-01",
                      "exitDate": null,
                      "updatedAt": "2026-11-12T06:40:00.000Z"
                    },
                    "inviteEmailSent": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/departments": {
      "get": {
        "operationId": "list-departments",
        "tags": [
          "Company setup"
        ],
        "summary": "List departments",
        "description": "Every department, in the order Settings ▸ Departments shows them. Needs an app approved for Company setup.",
        "security": [
          {
            "soomApp": [
              "company"
            ]
          }
        ],
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "description",
                              "head",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the department, the id in an employee’s department."
                              },
                              "name": {
                                "type": "string",
                                "description": "Department name."
                              },
                              "description": {
                                "type": "string",
                                "description": "What it does, when written down.",
                                "nullable": true
                              },
                              "head": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who heads it.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b101",
                        "name": "Engineering",
                        "description": "Builds and runs the product.",
                        "head": {
                          "id": "665f1c2ab7e94d0012a3c4c1",
                          "employeeCode": "EMP0007",
                          "name": "Ravi Kumar"
                        },
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/designations": {
      "get": {
        "operationId": "list-designations",
        "tags": [
          "Company setup"
        ],
        "summary": "List designations",
        "description": "Every designation, in the order Settings ▸ Designations shows them. Needs an app approved for Company setup.",
        "security": [
          {
            "soomApp": [
              "company"
            ]
          }
        ],
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "description",
                              "department",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the designation, the id in an employee’s designation."
                              },
                              "name": {
                                "type": "string",
                                "description": "Designation name."
                              },
                              "description": {
                                "type": "string",
                                "description": "What it means, when written down.",
                                "nullable": true
                              },
                              "department": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List departments."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The department it belongs to, when it has one.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b201",
                        "name": "Senior Developer",
                        "description": null,
                        "department": {
                          "id": "665f0a11b7e94d0012a3b101",
                          "name": "Engineering"
                        },
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/locations": {
      "get": {
        "operationId": "list-locations",
        "tags": [
          "Company setup"
        ],
        "summary": "List locations",
        "description": "Every branch, in the order Settings ▸ Locations shows them, with the time zone its people work on. Needs an app approved for Company setup.",
        "security": [
          {
            "soomApp": [
              "company"
            ]
          }
        ],
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "city",
                              "state",
                              "country",
                              "timezone",
                              "isHeadquarters",
                              "manager",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the branch, the id in an employee’s location."
                              },
                              "name": {
                                "type": "string",
                                "description": "Branch name."
                              },
                              "city": {
                                "type": "string",
                                "description": "City.",
                                "nullable": true
                              },
                              "state": {
                                "type": "string",
                                "description": "State.",
                                "nullable": true
                              },
                              "country": {
                                "type": "string",
                                "description": "Country.",
                                "nullable": true
                              },
                              "timezone": {
                                "type": "string",
                                "description": "Time zone, like Asia/Kolkata: the clock its people’s days and shift times run on. The company’s own when the branch has none set."
                              },
                              "isHeadquarters": {
                                "type": "boolean",
                                "description": "true for the head office."
                              },
                              "manager": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "The branch manager.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b301",
                        "name": "Hyderabad",
                        "city": "Hyderabad",
                        "state": "Telangana",
                        "country": "India",
                        "timezone": "Asia/Kolkata",
                        "isHeadquarters": true,
                        "manager": {
                          "id": "665f1c2ab7e94d0012a3c4c1",
                          "employeeCode": "EMP0007",
                          "name": "Ravi Kumar"
                        },
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/shifts": {
      "get": {
        "operationId": "list-shifts",
        "tags": [
          "Company setup"
        ],
        "summary": "List shifts",
        "description": "Every shift, with its hours, break and working days, and the rules that make a day late or a half day. Needs an app approved for Company setup.",
        "security": [
          {
            "soomApp": [
              "company"
            ]
          }
        ],
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "startTime",
                              "endTime",
                              "isOvernight",
                              "breakMinutes",
                              "workMinutes",
                              "workingDays",
                              "graceMinutes",
                              "halfDayHours",
                              "isDefault",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the shift."
                              },
                              "name": {
                                "type": "string",
                                "description": "Shift name."
                              },
                              "startTime": {
                                "type": "string",
                                "description": "When it starts, like 09:30, on the clock of the branch each person works at."
                              },
                              "endTime": {
                                "type": "string",
                                "description": "When it ends, like 18:30. Earlier than startTime when it ends the next morning."
                              },
                              "isOvernight": {
                                "type": "boolean",
                                "description": "true when it ends the next morning."
                              },
                              "breakMinutes": {
                                "type": "number",
                                "description": "Minutes of break in it."
                              },
                              "workMinutes": {
                                "type": "number",
                                "description": "A full day on it less the break: what a day of leave or a holiday counts as."
                              },
                              "workingDays": {
                                "type": "array",
                                "items": {
                                  "type": "string",
                                  "enum": [
                                    "Monday",
                                    "Tuesday",
                                    "Wednesday",
                                    "Thursday",
                                    "Friday",
                                    "Saturday",
                                    "Sunday"
                                  ]
                                },
                                "description": "The days it is worked. A person can have their own working days, and theirs win."
                              },
                              "graceMinutes": {
                                "type": "number",
                                "description": "Minutes after the start someone can clock in without being late. The company’s grace when the shift has none of its own."
                              },
                              "halfDayHours": {
                                "type": "number",
                                "description": "A day worked shorter than this many hours is a half day. 0 means there is no such rule."
                              },
                              "isDefault": {
                                "type": "boolean",
                                "description": "true for the shift everyone without a shift of their own works."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b401",
                        "name": "General",
                        "startTime": "09:30",
                        "endTime": "18:30",
                        "isOvernight": false,
                        "breakMinutes": 60,
                        "workMinutes": 480,
                        "workingDays": [
                          "Monday",
                          "Tuesday",
                          "Wednesday",
                          "Thursday",
                          "Friday"
                        ],
                        "graceMinutes": 10,
                        "halfDayHours": 4,
                        "isDefault": true,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/holidays": {
      "get": {
        "operationId": "list-holidays",
        "tags": [
          "Company setup"
        ],
        "summary": "List holidays",
        "description": "Every holiday in a year, by date, with the branches it is for. Needs an app approved for Company setup.",
        "security": [
          {
            "soomApp": [
              "company"
            ]
          }
        ],
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Holidays in this year, like 2026. This year on the company’s clock when left out.",
            "schema": {
              "type": "string"
            },
            "example": "2026"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "date",
                              "name",
                              "type",
                              "description",
                              "locations",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the holiday."
                              },
                              "date": {
                                "type": "string",
                                "format": "date",
                                "description": "The day."
                              },
                              "name": {
                                "type": "string",
                                "description": "Holiday name."
                              },
                              "type": {
                                "type": "string",
                                "description": "public is a day off for the people it covers. optional keeps the office open: it is marked on calendars, and leave taken for it counts.",
                                "enum": [
                                  "public",
                                  "optional"
                                ]
                              },
                              "description": {
                                "type": "string",
                                "description": "A note about it, when written down.",
                                "nullable": true
                              },
                              "locations": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "id",
                                    "name"
                                  ],
                                  "properties": {
                                    "id": {
                                      "type": "string",
                                      "description": "Soom’s id for the branch, the id in List locations."
                                    },
                                    "name": {
                                      "type": "string",
                                      "description": "Branch name."
                                    }
                                  }
                                },
                                "description": "The branches it is for. Empty means the whole company, and someone with no branch only gets those."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b501",
                        "date": "2026-06-02",
                        "name": "Telangana Formation Day",
                        "type": "public",
                        "description": "Hyderabad office only.",
                        "locations": [
                          {
                            "id": "665f0a11b7e94d0012a3b301",
                            "name": "Hyderabad"
                          }
                        ],
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/attendance": {
      "get": {
        "operationId": "list-attendance",
        "tags": [
          "Attendance"
        ],
        "summary": "List attendance days",
        "description": "Every day with a record between two dates, newest first. A day nobody has a record for yet is not listed. Needs an app approved for Attendance.",
        "security": [
          {
            "soomApp": [
              "attendance"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Days on these dates are listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "employee",
                              "date",
                              "status",
                              "clockIn",
                              "clockOut",
                              "workedMinutes",
                              "lateMinutes",
                              "earlyLeaveMinutes",
                              "workFrom",
                              "updatedAt"
                            ],
                            "properties": {
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who it belongs to.",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "format": "date",
                                "description": "The working day."
                              },
                              "status": {
                                "type": "string",
                                "description": "How the day turned out. absent is a working day with no clock-in and no leave.",
                                "enum": [
                                  "present",
                                  "late",
                                  "half_day",
                                  "absent",
                                  "leave",
                                  "wfh",
                                  "permission",
                                  "holiday",
                                  "off"
                                ]
                              },
                              "clockIn": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they clocked in, in UTC.",
                                "nullable": true
                              },
                              "clockOut": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they clocked out, in UTC.",
                                "nullable": true
                              },
                              "workedMinutes": {
                                "type": "number",
                                "description": "Minutes worked, less the shift’s break."
                              },
                              "lateMinutes": {
                                "type": "number",
                                "description": "Minutes late, after the grace period."
                              },
                              "earlyLeaveMinutes": {
                                "type": "number",
                                "description": "Minutes left before the shift ended."
                              },
                              "workFrom": {
                                "type": "string",
                                "description": "Where they worked from.",
                                "enum": [
                                  "office",
                                  "wfh"
                                ],
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "date": "2026-11-02",
                        "status": "late",
                        "clockIn": "2026-11-02T04:12:00.000Z",
                        "clockOut": "2026-11-02T13:05:00.000Z",
                        "workedMinutes": 473,
                        "lateMinutes": 12,
                        "earlyLeaveMinutes": 0,
                        "workFrom": "office",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/clock-ins": {
      "post": {
        "operationId": "record-clock-in",
        "tags": [
          "Attendance"
        ],
        "summary": "Record a clock-in",
        "description": "Records when someone clocked in, and when they clocked out once they have, judged as their own clock-in in Soom is: the day on their branch’s clock, late and early against their shift, nothing late on a weekly off. Send the same day again with clockOut when they leave. It answers 201 when it starts a day and 200 when it updates one it started. A day with times from anywhere else in Soom is never changed. Needs an app approved for Record clock-ins.",
        "security": [
          {
            "soomApp": [
              "record_clock_ins"
            ]
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "employeeCode",
                  "clockIn"
                ],
                "additionalProperties": false,
                "properties": {
                  "employeeCode": {
                    "type": "string",
                    "description": "Who clocked in, by the employee code your company gave them."
                  },
                  "clockIn": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When they clocked in, with its offset like 2026-11-09T09:28:00+05:30, or in UTC ending in Z."
                  },
                  "clockOut": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When they clocked out. Leave it out until they have; a clock-out already recorded is kept when it is left out."
                  },
                  "date": {
                    "type": "string",
                    "format": "date",
                    "description": "The working day it belongs to: the clock-in’s own day on their branch’s clock when left out. Send it for a night shift clocked in after midnight; it can only be that day or the day before."
                  },
                  "workFrom": {
                    "type": "string",
                    "description": "Where they worked from. When left out: home on a day they have an approved request to work from home, or if they always work from home, else the office.",
                    "enum": [
                      "office",
                      "wfh"
                    ]
                  }
                }
              },
              "example": {
                "employeeCode": "EMP0032",
                "clockIn": "2026-11-09T09:28:00+05:30",
                "clockOut": "2026-11-09T18:41:00+05:30"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "What was updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "day",
                        "created"
                      ],
                      "properties": {
                        "day": {
                          "type": "object",
                          "required": [
                            "employee",
                            "date",
                            "status",
                            "clockIn",
                            "clockOut",
                            "workedMinutes",
                            "lateMinutes",
                            "earlyLeaveMinutes",
                            "workFrom",
                            "updatedAt"
                          ],
                          "properties": {
                            "employee": {
                              "type": "object",
                              "required": [
                                "id",
                                "employeeCode",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for the person, the id in List employees."
                                },
                                "employeeCode": {
                                  "type": "string",
                                  "description": "The code your company gave them.",
                                  "nullable": true
                                },
                                "name": {
                                  "type": "string",
                                  "description": "First and last name."
                                }
                              },
                              "description": "Who it belongs to.",
                              "nullable": true
                            },
                            "date": {
                              "type": "string",
                              "format": "date",
                              "description": "The working day."
                            },
                            "status": {
                              "type": "string",
                              "description": "How the day turned out. absent is a working day with no clock-in and no leave.",
                              "enum": [
                                "present",
                                "late",
                                "half_day",
                                "absent",
                                "leave",
                                "wfh",
                                "permission",
                                "holiday",
                                "off"
                              ]
                            },
                            "clockIn": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When they clocked in, in UTC.",
                              "nullable": true
                            },
                            "clockOut": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When they clocked out, in UTC.",
                              "nullable": true
                            },
                            "workedMinutes": {
                              "type": "number",
                              "description": "Minutes worked, less the shift’s break."
                            },
                            "lateMinutes": {
                              "type": "number",
                              "description": "Minutes late, after the grace period."
                            },
                            "earlyLeaveMinutes": {
                              "type": "number",
                              "description": "Minutes left before the shift ended."
                            },
                            "workFrom": {
                              "type": "string",
                              "description": "Where they worked from.",
                              "enum": [
                                "office",
                                "wfh"
                              ],
                              "nullable": true
                            },
                            "updatedAt": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                              "nullable": true
                            }
                          },
                          "description": "The day, as List attendance days gives it."
                        },
                        "created": {
                          "type": "boolean",
                          "description": "true when this started the day, false when it updated a day it started before."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "day": {
                      "employee": {
                        "id": "665f1c2ab7e94d0012a3c4d5",
                        "employeeCode": "EMP0032",
                        "name": "Priya Sharma"
                      },
                      "date": "2026-11-09",
                      "status": "present",
                      "clockIn": "2026-11-09T03:58:00.000Z",
                      "clockOut": "2026-11-09T13:11:00.000Z",
                      "workedMinutes": 493,
                      "lateMinutes": 0,
                      "earlyLeaveMinutes": 0,
                      "workFrom": "office",
                      "updatedAt": "2026-11-12T06:40:00.000Z"
                    },
                    "created": true
                  }
                }
              }
            }
          },
          "201": {
            "description": "What was made.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "day",
                        "created"
                      ],
                      "properties": {
                        "day": {
                          "type": "object",
                          "required": [
                            "employee",
                            "date",
                            "status",
                            "clockIn",
                            "clockOut",
                            "workedMinutes",
                            "lateMinutes",
                            "earlyLeaveMinutes",
                            "workFrom",
                            "updatedAt"
                          ],
                          "properties": {
                            "employee": {
                              "type": "object",
                              "required": [
                                "id",
                                "employeeCode",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for the person, the id in List employees."
                                },
                                "employeeCode": {
                                  "type": "string",
                                  "description": "The code your company gave them.",
                                  "nullable": true
                                },
                                "name": {
                                  "type": "string",
                                  "description": "First and last name."
                                }
                              },
                              "description": "Who it belongs to.",
                              "nullable": true
                            },
                            "date": {
                              "type": "string",
                              "format": "date",
                              "description": "The working day."
                            },
                            "status": {
                              "type": "string",
                              "description": "How the day turned out. absent is a working day with no clock-in and no leave.",
                              "enum": [
                                "present",
                                "late",
                                "half_day",
                                "absent",
                                "leave",
                                "wfh",
                                "permission",
                                "holiday",
                                "off"
                              ]
                            },
                            "clockIn": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When they clocked in, in UTC.",
                              "nullable": true
                            },
                            "clockOut": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When they clocked out, in UTC.",
                              "nullable": true
                            },
                            "workedMinutes": {
                              "type": "number",
                              "description": "Minutes worked, less the shift’s break."
                            },
                            "lateMinutes": {
                              "type": "number",
                              "description": "Minutes late, after the grace period."
                            },
                            "earlyLeaveMinutes": {
                              "type": "number",
                              "description": "Minutes left before the shift ended."
                            },
                            "workFrom": {
                              "type": "string",
                              "description": "Where they worked from.",
                              "enum": [
                                "office",
                                "wfh"
                              ],
                              "nullable": true
                            },
                            "updatedAt": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                              "nullable": true
                            }
                          },
                          "description": "The day, as List attendance days gives it."
                        },
                        "created": {
                          "type": "boolean",
                          "description": "true when this started the day, false when it updated a day it started before."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "day": {
                      "employee": {
                        "id": "665f1c2ab7e94d0012a3c4d5",
                        "employeeCode": "EMP0032",
                        "name": "Priya Sharma"
                      },
                      "date": "2026-11-09",
                      "status": "present",
                      "clockIn": "2026-11-09T03:58:00.000Z",
                      "clockOut": "2026-11-09T13:11:00.000Z",
                      "workedMinutes": 493,
                      "lateMinutes": 0,
                      "earlyLeaveMinutes": 0,
                      "workFrom": "office",
                      "updatedAt": "2026-11-12T06:40:00.000Z"
                    },
                    "created": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/overtime": {
      "get": {
        "operationId": "list-overtime",
        "tags": [
          "Attendance"
        ],
        "summary": "List overtime",
        "description": "Overtime claimed for days between two dates, newest first. In Soom, time on the clock past the end of a shift is overtime only once someone claims it and the claim is approved, so only approved claims are listed unless you ask for others. Needs an app approved for Attendance.",
        "security": [
          {
            "soomApp": [
              "attendance"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Claims for days on these dates are listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "approved (the default), pending, rejected, or all of them.",
            "schema": {
              "type": "string",
              "enum": [
                "approved",
                "pending",
                "rejected",
                "all"
              ]
            },
            "example": "approved"
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Only extra hours on working days, or only work on weekly offs.",
            "schema": {
              "type": "string",
              "enum": [
                "extra_hours",
                "weekly_off"
              ]
            },
            "example": "extra_hours"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "date",
                              "kind",
                              "minutes",
                              "enteredByHand",
                              "status",
                              "decision",
                              "compOffDays",
                              "appliedAt",
                              "decidedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the claim."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who claimed it.",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "format": "date",
                                "description": "The day worked."
                              },
                              "kind": {
                                "type": "string",
                                "description": "extra_hours is time worked past a working day. weekly_off is working on a day off.",
                                "enum": [
                                  "extra_hours",
                                  "weekly_off"
                                ]
                              },
                              "minutes": {
                                "type": "number",
                                "description": "Minutes claimed, for extra hours. null for a weekly off, which is claimed as a day: its hours are that day’s workedMinutes in List attendance days.",
                                "nullable": true
                              },
                              "enteredByHand": {
                                "type": "boolean",
                                "description": "true when they typed the hours, as for work done after leaving. false when the hours come from their clock times."
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands. pending is still with an approver or HR.",
                                "enum": [
                                  "pending",
                                  "approved",
                                  "rejected"
                                ]
                              },
                              "decision": {
                                "type": "string",
                                "description": "How approved overtime is given: paid, or comp_off as days of leave. null until it is approved.",
                                "enum": [
                                  "paid",
                                  "comp_off"
                                ],
                                "nullable": true
                              },
                              "compOffDays": {
                                "type": "number",
                                "description": "Days of leave given for it, when decision is comp_off.",
                                "nullable": true
                              },
                              "appliedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was claimed, in UTC.",
                                "nullable": true
                              },
                              "decidedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was approved or rejected, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6af1a2b3c4d5e6f708192a6e",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "date": "2026-11-05",
                        "kind": "extra_hours",
                        "minutes": 120,
                        "enteredByHand": false,
                        "status": "approved",
                        "decision": "paid",
                        "compOffDays": null,
                        "appliedAt": "2026-11-06T04:20:00.000Z",
                        "decidedAt": "2026-11-07T10:15:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/attendance-corrections": {
      "get": {
        "operationId": "list-attendance-corrections",
        "tags": [
          "Attendance"
        ],
        "summary": "List attendance corrections",
        "description": "Requests to correct a day’s clock-in or clock-out time, for days between two dates, newest first. Soom calls them regularizations. Once one is approved, the day in List attendance days has the corrected times. Why it was asked for, and what approvers wrote, stay in Soom. Needs an app approved for Attendance.",
        "security": [
          {
            "soomApp": [
              "attendance"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Requests for days on these dates are listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only requests with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ]
            },
            "example": "approved"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "date",
                              "clockIn",
                              "clockOut",
                              "status",
                              "appliedAt",
                              "decidedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the request."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who asked.",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "format": "date",
                                "description": "The day to correct."
                              },
                              "clockIn": {
                                "type": "string",
                                "format": "date-time",
                                "description": "The clock-in time asked for, in UTC. null when only the clock-out is to change.",
                                "nullable": true
                              },
                              "clockOut": {
                                "type": "string",
                                "format": "date-time",
                                "description": "The clock-out time asked for, in UTC. null when only the clock-in is to change.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "pending",
                                  "approved",
                                  "rejected",
                                  "cancelled"
                                ]
                              },
                              "appliedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was asked for, in UTC.",
                                "nullable": true
                              },
                              "decidedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was approved or rejected, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6af1a2b3c4d5e6f708192b80",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "date": "2026-11-03",
                        "clockIn": "2026-11-03T03:55:00.000Z",
                        "clockOut": "2026-11-03T12:40:00.000Z",
                        "status": "approved",
                        "appliedAt": "2026-11-04T05:20:00.000Z",
                        "decidedAt": "2026-11-04T09:02:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/shift-changes": {
      "get": {
        "operationId": "list-shift-changes",
        "tags": [
          "Attendance"
        ],
        "summary": "List shift changes",
        "description": "Requests to work another shift on a day, for days between two dates, newest first. Once one is approved, they work that shift that day, and Soom judges the day against it. Why it was asked for, and what approvers wrote, stay in Soom. Needs an app approved for Attendance.",
        "security": [
          {
            "soomApp": [
              "attendance"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Requests for days on these dates are listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only requests with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ]
            },
            "example": "approved"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "date",
                              "fromShift",
                              "toShift",
                              "status",
                              "appliedAt",
                              "decidedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the request."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who asked.",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "format": "date",
                                "description": "The day."
                              },
                              "fromShift": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List shifts."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The shift they had that day when they asked. null when they had none.",
                                "nullable": true
                              },
                              "toShift": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List shifts."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The shift they asked to work instead.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "pending",
                                  "approved",
                                  "rejected",
                                  "cancelled"
                                ]
                              },
                              "appliedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was asked for, in UTC.",
                                "nullable": true
                              },
                              "decidedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was approved or rejected, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6af1a2b3c4d5e6f708192b91",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "date": "2026-11-20",
                        "fromShift": {
                          "id": "665f0a11b7e94d0012a3b401",
                          "name": "General"
                        },
                        "toShift": {
                          "id": "665f0a11b7e94d0012a3b402",
                          "name": "Night"
                        },
                        "status": "approved",
                        "appliedAt": "2026-11-17T06:10:00.000Z",
                        "decidedAt": "2026-11-17T11:30:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/leave": {
      "get": {
        "operationId": "list-leave",
        "tags": [
          "Leave"
        ],
        "summary": "List leave",
        "description": "Every leave that touches the dates you give, latest start first, whatever its status unless you pick one. Needs an app approved for Leave.",
        "security": [
          {
            "soomApp": [
              "leave"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Leave that touches any day from here to to is listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only leave with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ]
            },
            "example": "approved"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "leaveType",
                              "startDate",
                              "endDate",
                              "days",
                              "dayBreakdown",
                              "status",
                              "appliedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the leave."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who it belongs to.",
                                "nullable": true
                              },
                              "leaveType": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List leave types."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The leave type.",
                                "nullable": true
                              },
                              "startDate": {
                                "type": "string",
                                "format": "date",
                                "description": "First day of the leave."
                              },
                              "endDate": {
                                "type": "string",
                                "format": "date",
                                "description": "Last day of the leave."
                              },
                              "days": {
                                "type": "number",
                                "description": "Days it takes, with half days as 0.5."
                              },
                              "dayBreakdown": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "date",
                                    "portion"
                                  ],
                                  "properties": {
                                    "date": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The day."
                                    },
                                    "portion": {
                                      "type": "string",
                                      "description": "The whole day, or the first or second half.",
                                      "enum": [
                                        "full",
                                        "firstHalf",
                                        "secondHalf"
                                      ]
                                    }
                                  }
                                },
                                "description": "Each day it covers, and which part of it."
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "pending",
                                  "approved",
                                  "rejected",
                                  "cancelled"
                                ]
                              },
                              "appliedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was applied for, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6af1a2b3c4d5e6f708192a3b",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "leaveType": {
                          "id": "665f0a11b7e94d0012a3b601",
                          "name": "Casual Leave"
                        },
                        "startDate": "2026-11-12",
                        "endDate": "2026-11-13",
                        "days": 1.5,
                        "dayBreakdown": [
                          {
                            "date": "2026-11-12",
                            "portion": "full"
                          },
                          {
                            "date": "2026-11-13",
                            "portion": "firstHalf"
                          }
                        ],
                        "status": "approved",
                        "appliedAt": "2026-11-05T06:30:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "apply-for-leave",
        "tags": [
          "Leave"
        ],
        "summary": "Apply for leave",
        "description": "Applies for leave for someone, as they would in Soom: weekly offs and holidays aren’t counted, the leave type’s rules hold (who can take it, the notice it needs, the fewest and most days), and it goes to their approvers, who are told as usual. It is pending until they decide, unless the person approves their own leave. A leave type that needs a document has to be applied for in Soom. Needs an app approved for Apply for leave.",
        "security": [
          {
            "soomApp": [
              "apply_for_leave"
            ]
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "employeeCode",
                  "leaveTypeId",
                  "startDate",
                  "endDate",
                  "reason"
                ],
                "additionalProperties": false,
                "properties": {
                  "employeeCode": {
                    "type": "string",
                    "description": "Who the leave is for, by the employee code your company gave them."
                  },
                  "leaveTypeId": {
                    "type": "string",
                    "description": "The leave type, an id from List leave types. It has to be in use."
                  },
                  "startDate": {
                    "type": "string",
                    "format": "date",
                    "description": "First day of the leave, like 2026-11-26. It can be a day gone by, when the leave type needs no notice."
                  },
                  "endDate": {
                    "type": "string",
                    "format": "date",
                    "description": "Last day, on or after startDate. The same day for a one-day leave."
                  },
                  "startPortion": {
                    "type": "string",
                    "description": "How much of startDate they are away: the whole day when left out, or only its first half (the morning) or second half.",
                    "enum": [
                      "full",
                      "firstHalf",
                      "secondHalf"
                    ]
                  },
                  "endPortion": {
                    "type": "string",
                    "description": "How much of endDate they are away, for a leave longer than one day: the whole day when left out.",
                    "enum": [
                      "full",
                      "firstHalf",
                      "secondHalf"
                    ]
                  },
                  "reason": {
                    "type": "string",
                    "description": "Why, in their words, up to 1000 characters. Their approvers read it."
                  }
                }
              },
              "example": {
                "employeeCode": "EMP0032",
                "leaveTypeId": "665f0a11b7e94d0012a3b601",
                "startDate": "2026-11-26",
                "endDate": "2026-11-27",
                "endPortion": "firstHalf",
                "reason": "Family function in Vijayawada"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "What was made.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "leave",
                        "beyondBalance"
                      ],
                      "properties": {
                        "leave": {
                          "type": "object",
                          "required": [
                            "id",
                            "employee",
                            "leaveType",
                            "startDate",
                            "endDate",
                            "days",
                            "dayBreakdown",
                            "status",
                            "appliedAt",
                            "updatedAt"
                          ],
                          "properties": {
                            "id": {
                              "type": "string",
                              "description": "Soom’s id for the leave."
                            },
                            "employee": {
                              "type": "object",
                              "required": [
                                "id",
                                "employeeCode",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for the person, the id in List employees."
                                },
                                "employeeCode": {
                                  "type": "string",
                                  "description": "The code your company gave them.",
                                  "nullable": true
                                },
                                "name": {
                                  "type": "string",
                                  "description": "First and last name."
                                }
                              },
                              "description": "Who it belongs to.",
                              "nullable": true
                            },
                            "leaveType": {
                              "type": "object",
                              "required": [
                                "id",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for it, the id in List leave types."
                                },
                                "name": {
                                  "type": "string",
                                  "description": "Its name."
                                }
                              },
                              "description": "The leave type.",
                              "nullable": true
                            },
                            "startDate": {
                              "type": "string",
                              "format": "date",
                              "description": "First day of the leave."
                            },
                            "endDate": {
                              "type": "string",
                              "format": "date",
                              "description": "Last day of the leave."
                            },
                            "days": {
                              "type": "number",
                              "description": "Days it takes, with half days as 0.5."
                            },
                            "dayBreakdown": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "required": [
                                  "date",
                                  "portion"
                                ],
                                "properties": {
                                  "date": {
                                    "type": "string",
                                    "format": "date",
                                    "description": "The day."
                                  },
                                  "portion": {
                                    "type": "string",
                                    "description": "The whole day, or the first or second half.",
                                    "enum": [
                                      "full",
                                      "firstHalf",
                                      "secondHalf"
                                    ]
                                  }
                                }
                              },
                              "description": "Each day it covers, and which part of it."
                            },
                            "status": {
                              "type": "string",
                              "description": "Where it stands.",
                              "enum": [
                                "pending",
                                "approved",
                                "rejected",
                                "cancelled"
                              ]
                            },
                            "appliedAt": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When it was applied for, in UTC.",
                              "nullable": true
                            },
                            "updatedAt": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                              "nullable": true
                            }
                          },
                          "description": "The leave, as List leave gives it."
                        },
                        "beyondBalance": {
                          "type": "boolean",
                          "description": "true when it asks for more days than they had available. It still goes for approval, and their available in List leave balances drops below 0."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "leave": {
                      "id": "6af1a2b3c4d5e6f708192a7f",
                      "employee": {
                        "id": "665f1c2ab7e94d0012a3c4d5",
                        "employeeCode": "EMP0032",
                        "name": "Priya Sharma"
                      },
                      "leaveType": {
                        "id": "665f0a11b7e94d0012a3b601",
                        "name": "Casual Leave"
                      },
                      "startDate": "2026-11-26",
                      "endDate": "2026-11-27",
                      "days": 1.5,
                      "dayBreakdown": [
                        {
                          "date": "2026-11-26",
                          "portion": "full"
                        },
                        {
                          "date": "2026-11-27",
                          "portion": "firstHalf"
                        }
                      ],
                      "status": "pending",
                      "appliedAt": "2026-11-10T05:42:00.000Z",
                      "updatedAt": "2026-11-12T06:40:00.000Z"
                    },
                    "beyondBalance": false
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/leave-types": {
      "get": {
        "operationId": "list-leave-types",
        "tags": [
          "Leave"
        ],
        "summary": "List leave types",
        "description": "Every leave type, in use or not, by name as Settings ▸ Leave Types lists them, with how its days are given and the rules for asking for it. Needs an app approved for Leave.",
        "security": [
          {
            "soomApp": [
              "leave"
            ]
          }
        ],
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "code",
                              "description",
                              "color",
                              "isPaid",
                              "accrual",
                              "daysPerYear",
                              "daysPerMonth",
                              "carriesForward",
                              "carryForwardMaxDays",
                              "hasBalance",
                              "minDaysPerRequest",
                              "maxDaysPerRequest",
                              "noticeDays",
                              "attachmentRequired",
                              "eligibility",
                              "isActive",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the leave type, the id in a leave’s leaveType."
                              },
                              "name": {
                                "type": "string",
                                "description": "Leave type name."
                              },
                              "code": {
                                "type": "string",
                                "description": "Its short code, like CL."
                              },
                              "description": {
                                "type": "string",
                                "description": "What it is for, when written down.",
                                "nullable": true
                              },
                              "color": {
                                "type": "string",
                                "description": "The colour Soom shows it in, like #22C55E."
                              },
                              "isPaid": {
                                "type": "boolean",
                                "description": "false for leave without pay."
                              },
                              "accrual": {
                                "type": "string",
                                "description": "How days are given. upfront gives the year’s days on 1 January, or on the 1st after someone joins. monthly adds daysPerMonth on the 1st of each month. none gives nothing on a schedule: days come only from comp-off or from HR.",
                                "enum": [
                                  "upfront",
                                  "monthly",
                                  "none"
                                ]
                              },
                              "daysPerYear": {
                                "type": "number",
                                "description": "Days given over a year. Less than 12 × daysPerMonth when some months give none."
                              },
                              "daysPerMonth": {
                                "type": "number",
                                "description": "Days added each month, when accrual is monthly. 0 otherwise."
                              },
                              "carriesForward": {
                                "type": "boolean",
                                "description": "true when days left at the end of the year move into the next. false when they lapse."
                              },
                              "carryForwardMaxDays": {
                                "type": "number",
                                "description": "The most days that move into the next year. 0 means no limit."
                              },
                              "hasBalance": {
                                "type": "boolean",
                                "description": "false for leave kept off the balances, like maternity: it isn’t in List leave balances, and a request for it is never short of days."
                              },
                              "minDaysPerRequest": {
                                "type": "number",
                                "description": "The fewest days one request can be for. 0.5 is half a day, 0 is any length."
                              },
                              "maxDaysPerRequest": {
                                "type": "number",
                                "description": "The most days one request can be for. 0 means no limit."
                              },
                              "noticeDays": {
                                "type": "number",
                                "description": "Days ahead it has to be asked for. 0 means no notice is needed."
                              },
                              "attachmentRequired": {
                                "type": "boolean",
                                "description": "true when a request needs a document, like a doctor’s note."
                              },
                              "eligibility": {
                                "type": "object",
                                "required": [
                                  "gender",
                                  "employeeTypes"
                                ],
                                "properties": {
                                  "gender": {
                                    "type": "string",
                                    "description": "all, or only people of this gender.",
                                    "enum": [
                                      "all",
                                      "male",
                                      "female"
                                    ]
                                  },
                                  "employeeTypes": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    },
                                    "description": "Only people with these kinds of employment, the employeeType in List employees. Empty means everyone."
                                  }
                                },
                                "description": "Who can take it."
                              },
                              "isActive": {
                                "type": "boolean",
                                "description": "false when it can’t be asked for any more. Older leave can still be of this type."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b601",
                        "name": "Casual Leave",
                        "code": "CL",
                        "description": "For personal errands and short breaks.",
                        "color": "#22C55E",
                        "isPaid": true,
                        "accrual": "monthly",
                        "daysPerYear": 12,
                        "daysPerMonth": 1,
                        "carriesForward": true,
                        "carryForwardMaxDays": 5,
                        "hasBalance": true,
                        "minDaysPerRequest": 0.5,
                        "maxDaysPerRequest": 3,
                        "noticeDays": 1,
                        "attachmentRequired": false,
                        "eligibility": {
                          "gender": "all",
                          "employeeTypes": []
                        },
                        "isActive": true,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/leave-balances": {
      "get": {
        "operationId": "list-leave-balances",
        "tags": [
          "Leave"
        ],
        "summary": "List leave balances",
        "description": "What each person has of every leave type they can take, for one year, in employee code order: the figures HR ▸ Leave Balances shows. A company that keeps its leave balances in Xero has none in Soom, and gets BALANCES_IN_PAYROLL. Needs an app approved for Leave.",
        "security": [
          {
            "soomApp": [
              "leave"
            ]
          }
        ],
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Balances for this year, like 2026. This year on the company’s clock when left out.",
            "schema": {
              "type": "string"
            },
            "example": "2026"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "current (the default) is everyone still working, exited is people who have left, all is both.",
            "schema": {
              "type": "string",
              "enum": [
                "current",
                "exited",
                "all"
              ]
            },
            "example": "current"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "employee",
                              "year",
                              "balances"
                            ],
                            "properties": {
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Whose balances they are."
                              },
                              "year": {
                                "type": "number",
                                "description": "The year, January to December."
                              },
                              "balances": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "leaveType",
                                    "entitled",
                                    "used",
                                    "pending",
                                    "carriedForward",
                                    "encashed",
                                    "available"
                                  ],
                                  "properties": {
                                    "leaveType": {
                                      "type": "object",
                                      "required": [
                                        "id",
                                        "name"
                                      ],
                                      "properties": {
                                        "id": {
                                          "type": "string",
                                          "description": "Soom’s id for it, the id in List leave types."
                                        },
                                        "name": {
                                          "type": "string",
                                          "description": "Its name."
                                        }
                                      },
                                      "description": "The leave type."
                                    },
                                    "entitled": {
                                      "type": "number",
                                      "description": "Days given for the year so far, with any carried forward and HR’s changes."
                                    },
                                    "used": {
                                      "type": "number",
                                      "description": "Days of approved leave."
                                    },
                                    "pending": {
                                      "type": "number",
                                      "description": "Days asked for and waiting for approval."
                                    },
                                    "carriedForward": {
                                      "type": "number",
                                      "description": "Days brought from last year, already counted in entitled."
                                    },
                                    "encashed": {
                                      "type": "number",
                                      "description": "Days paid out, or set aside to be paid out, instead of taken."
                                    },
                                    "available": {
                                      "type": "number",
                                      "description": "Days they can still ask for: entitled less used, pending and encashed. Below 0 when more was approved than they had."
                                    }
                                  }
                                },
                                "description": "One for each leave type they can take, by name. Types kept off the balances, and types not in use, are left out."
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "year": 2026,
                        "balances": [
                          {
                            "leaveType": {
                              "id": "665f0a11b7e94d0012a3b601",
                              "name": "Casual Leave"
                            },
                            "entitled": 12,
                            "used": 4.5,
                            "pending": 1,
                            "carriedForward": 2,
                            "encashed": 0,
                            "available": 6.5
                          }
                        ]
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/work-from-home": {
      "get": {
        "operationId": "list-work-from-home",
        "tags": [
          "Time off"
        ],
        "summary": "List work from home",
        "description": "Every request to work from home that touches the dates you give, latest start first. Someone who picked work from home when clocking in, with no request, is in List attendance days with workFrom wfh. Needs an app approved for Time off.",
        "security": [
          {
            "soomApp": [
              "timeoff"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Requests that touch any day from here to to are listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only requests with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ]
            },
            "example": "approved"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "startDate",
                              "endDate",
                              "days",
                              "status",
                              "appliedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the request."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who it belongs to.",
                                "nullable": true
                              },
                              "startDate": {
                                "type": "string",
                                "format": "date",
                                "description": "First day."
                              },
                              "endDate": {
                                "type": "string",
                                "format": "date",
                                "description": "Last day."
                              },
                              "days": {
                                "type": "number",
                                "description": "Days from startDate to endDate, both counted."
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "pending",
                                  "approved",
                                  "rejected",
                                  "cancelled"
                                ]
                              },
                              "appliedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was asked for, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6af1a2b3c4d5e6f708192a4c",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "startDate": "2026-11-18",
                        "endDate": "2026-11-19",
                        "days": 2,
                        "status": "approved",
                        "appliedAt": "2026-11-16T05:10:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/permissions": {
      "get": {
        "operationId": "list-permissions",
        "tags": [
          "Time off"
        ],
        "summary": "List permissions",
        "description": "Every permission on the dates you give, latest first. A permission is a few hours away from work within a working day, like leaving at 2 for an appointment. Needs an app approved for Time off.",
        "security": [
          {
            "soomApp": [
              "timeoff"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Permissions on these dates are listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only permissions with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "cancelled"
              ]
            },
            "example": "approved"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "date",
                              "fromTime",
                              "toTime",
                              "hours",
                              "status",
                              "appliedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the permission."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who it belongs to.",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "format": "date",
                                "description": "The day."
                              },
                              "fromTime": {
                                "type": "string",
                                "description": "When it starts, like 14:00, on the clock of the branch they work at.",
                                "nullable": true
                              },
                              "toTime": {
                                "type": "string",
                                "description": "When it ends, like 16:00.",
                                "nullable": true
                              },
                              "hours": {
                                "type": "number",
                                "description": "Hours away, to 2 decimal places."
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "pending",
                                  "approved",
                                  "rejected",
                                  "cancelled"
                                ]
                              },
                              "appliedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was asked for, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6af1a2b3c4d5e6f708192a5d",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "date": "2026-11-24",
                        "fromTime": "14:00",
                        "toTime": "16:00",
                        "hours": 2,
                        "status": "approved",
                        "appliedAt": "2026-11-23T09:45:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/assets": {
      "get": {
        "operationId": "list-assets",
        "tags": [
          "Assets"
        ],
        "summary": "List assets",
        "description": "Everything the company owns, in asset code order, with who has it now. Needs an app approved for Assets.",
        "security": [
          {
            "soomApp": [
              "assets"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only assets in this state.",
            "schema": {
              "type": "string",
              "enum": [
                "in_stock",
                "assigned",
                "under_repair",
                "lost",
                "retired"
              ]
            },
            "example": "assigned"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Only this kind, a code from List asset categories.",
            "schema": {
              "type": "string"
            },
            "example": "laptop"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only what this person has now, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "assetCode",
                              "name",
                              "category",
                              "brand",
                              "model",
                              "serialNumber",
                              "status",
                              "location",
                              "heldBy",
                              "heldSince",
                              "expectedReturnDate",
                              "purchaseDate",
                              "warrantyEndDate",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the asset."
                              },
                              "assetCode": {
                                "type": "string",
                                "description": "The code on its label, like LT-0042."
                              },
                              "name": {
                                "type": "string",
                                "description": "Its name."
                              },
                              "category": {
                                "type": "object",
                                "required": [
                                  "code",
                                  "name"
                                ],
                                "properties": {
                                  "code": {
                                    "type": "string",
                                    "description": "Its code, from List asset categories, or other."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The kind of asset."
                              },
                              "brand": {
                                "type": "string",
                                "description": "Who made it.",
                                "nullable": true
                              },
                              "model": {
                                "type": "string",
                                "description": "Its model.",
                                "nullable": true
                              },
                              "serialNumber": {
                                "type": "string",
                                "description": "Its serial number.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands. in_stock is free to hand out. Something under_repair can still be with someone.",
                                "enum": [
                                  "in_stock",
                                  "assigned",
                                  "under_repair",
                                  "lost",
                                  "retired"
                                ]
                              },
                              "location": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List locations."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The branch it belongs to.",
                                "nullable": true
                              },
                              "heldBy": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who has it now. null when nobody does.",
                                "nullable": true
                              },
                              "heldSince": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they were given it, in UTC.",
                                "nullable": true
                              },
                              "expectedReturnDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When they are due to give it back, if a day was set.",
                                "nullable": true
                              },
                              "purchaseDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When the company bought it.",
                                "nullable": true
                              },
                              "warrantyEndDate": {
                                "type": "string",
                                "format": "date",
                                "description": "The last day of its warranty.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b02c3d4e5f6a7b8c9d0e1f2",
                        "assetCode": "LT-0042",
                        "name": "Dell Latitude 5440",
                        "category": {
                          "code": "laptop",
                          "name": "Laptop"
                        },
                        "brand": "Dell",
                        "model": "Latitude 5440",
                        "serialNumber": "7HX2QK3",
                        "status": "assigned",
                        "location": {
                          "id": "665f0a11b7e94d0012a3b301",
                          "name": "Hyderabad"
                        },
                        "heldBy": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "heldSince": "2025-01-06T05:30:00.000Z",
                        "expectedReturnDate": null,
                        "purchaseDate": "2024-12-18",
                        "warrantyEndDate": "2027-12-17",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/asset-categories": {
      "get": {
        "operationId": "list-asset-categories",
        "tags": [
          "Assets"
        ],
        "summary": "List asset categories",
        "description": "The kinds of asset the company keeps, in the order Settings ▸ Asset Categories lists them. A company that never changed them has Soom’s own. Needs an app approved for Assets.",
        "security": [
          {
            "soomApp": [
              "assets"
            ]
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "code",
                              "name",
                              "isActive"
                            ],
                            "properties": {
                              "code": {
                                "type": "string",
                                "description": "Its code, the code in an asset’s category."
                              },
                              "name": {
                                "type": "string",
                                "description": "Its name."
                              },
                              "isActive": {
                                "type": "boolean",
                                "description": "false when nothing new can be added to it. Older assets can still be of this kind."
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "code": "laptop",
                        "name": "Laptop",
                        "isActive": true
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/asset-assignments": {
      "get": {
        "operationId": "list-asset-assignments",
        "tags": [
          "Assets"
        ],
        "summary": "List asset assignments",
        "description": "Every time an asset was handed to someone, newest first: who had it, from when, and when they gave it back. Needs an app approved for Assets.",
        "security": [
          {
            "soomApp": [
              "assets"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "open is what people still have, returned is what came back, all (the default) is both.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "returned",
                "all"
              ]
            },
            "example": "open"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "assetCode",
            "in": "query",
            "required": false,
            "description": "Only this asset, by the code on its label.",
            "schema": {
              "type": "string"
            },
            "example": "LT-0042"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "asset",
                              "employee",
                              "assignedAt",
                              "acknowledgedAt",
                              "expectedReturnDate",
                              "returnedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the hand-over."
                              },
                              "asset": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "assetCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the asset, the id in List assets."
                                  },
                                  "assetCode": {
                                    "type": "string",
                                    "description": "The code on its label."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The asset.",
                                "nullable": true
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who was given it.",
                                "nullable": true
                              },
                              "assignedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they were given it, in UTC."
                              },
                              "acknowledgedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they confirmed in Soom that they have it.",
                                "nullable": true
                              },
                              "expectedReturnDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When they are due to give it back, if a day was set.",
                                "nullable": true
                              },
                              "returnedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it came back, in UTC. null while they still have it.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b02c3d4e5f6a7b8c9d0e2a3",
                        "asset": {
                          "id": "6b02c3d4e5f6a7b8c9d0e1f2",
                          "assetCode": "LT-0042",
                          "name": "Dell Latitude 5440"
                        },
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "assignedAt": "2025-01-06T05:30:00.000Z",
                        "acknowledgedAt": "2025-01-06T07:02:00.000Z",
                        "expectedReturnDate": null,
                        "returnedAt": null,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/asset-requests": {
      "get": {
        "operationId": "list-asset-requests",
        "tags": [
          "Assets"
        ],
        "summary": "List asset requests",
        "description": "What people have asked for, newest first. An approved request is waiting to be handed over; a fulfilled one has been, with the asset they were given. Why they asked is not shared. Needs an app approved for Assets.",
        "security": [
          {
            "soomApp": [
              "assets"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only requests with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "approved",
                "rejected",
                "fulfilled",
                "cancelled"
              ]
            },
            "example": "pending"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "category",
                              "description",
                              "urgency",
                              "status",
                              "appliedAt",
                              "decidedAt",
                              "fulfilledAt",
                              "asset",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the request."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who asked.",
                                "nullable": true
                              },
                              "category": {
                                "type": "object",
                                "required": [
                                  "code",
                                  "name"
                                ],
                                "properties": {
                                  "code": {
                                    "type": "string",
                                    "description": "Its code, from List asset categories, or other."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The kind of asset."
                              },
                              "description": {
                                "type": "string",
                                "description": "What they asked for, in their words."
                              },
                              "urgency": {
                                "type": "string",
                                "description": "How soon they need it.",
                                "enum": [
                                  "low",
                                  "normal",
                                  "high"
                                ]
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "pending",
                                  "approved",
                                  "rejected",
                                  "fulfilled",
                                  "cancelled"
                                ]
                              },
                              "appliedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they asked, in UTC.",
                                "nullable": true
                              },
                              "decidedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was approved or rejected, in UTC.",
                                "nullable": true
                              },
                              "fulfilledAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was handed over, in UTC.",
                                "nullable": true
                              },
                              "asset": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "assetCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the asset, the id in List assets."
                                  },
                                  "assetCode": {
                                    "type": "string",
                                    "description": "The code on its label."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The asset they were given, once it was handed over.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b02c3d4e5f6a7b8c9d0e3b4",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "category": {
                          "code": "monitor",
                          "name": "Monitor"
                        },
                        "description": "A second monitor for design reviews",
                        "urgency": "normal",
                        "status": "pending",
                        "appliedAt": "2026-11-03T08:15:00.000Z",
                        "decidedAt": null,
                        "fulfilledAt": null,
                        "asset": null,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/expenses": {
      "get": {
        "operationId": "list-expenses",
        "tags": [
          "Expenses"
        ],
        "summary": "List expenses",
        "description": "Every claim and voucher spent on the days you give, newest first, or paid on them with by=paid. A claim with several bills lists each bill too. Needs an app approved for Expenses.",
        "security": [
          {
            "soomApp": [
              "expenses"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Days are the company’s, and are the day on the bill unless by is paid.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "by",
            "in": "query",
            "required": false,
            "description": "spent (the default) picks expenses by the day on the bill; paid picks them by the day they were paid, and lists only paid ones.",
            "schema": {
              "type": "string",
              "enum": [
                "spent",
                "paid"
              ]
            },
            "example": "paid"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only expenses at this stage.",
            "schema": {
              "type": "string",
              "enum": [
                "in_review",
                "to_be_paid",
                "paid",
                "rejected"
              ]
            },
            "example": "to_be_paid"
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "claim is someone’s own spending, paid back to them; voucher is a payment the company made to a vendor.",
            "schema": {
              "type": "string",
              "enum": [
                "claim",
                "voucher"
              ]
            },
            "example": "claim"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Only this category, a code from List expense categories. A claim with several bills is listed when any bill is in it.",
            "schema": {
              "type": "string"
            },
            "example": "travel"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person’s: what they claimed, or are paid back for.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "expenseNo",
                              "kind",
                              "employee",
                              "reimburseTo",
                              "vendor",
                              "category",
                              "otherCategory",
                              "description",
                              "expenseDate",
                              "amount",
                              "status",
                              "submittedAt",
                              "acceptedAt",
                              "paidAt",
                              "paymentMethod",
                              "paymentNotes",
                              "paidTogetherId",
                              "rejectedAt",
                              "bills",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the expense."
                              },
                              "expenseNo": {
                                "type": "string",
                                "description": "Its number in Soom, like EXP-00042.",
                                "nullable": true
                              },
                              "kind": {
                                "type": "string",
                                "description": "claim or voucher.",
                                "enum": [
                                  "claim",
                                  "voucher"
                                ]
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who made the claim, or who recorded the voucher.",
                                "nullable": true
                              },
                              "reimburseTo": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who the company pays back: usually who made the claim, or the person they claimed for. null for a voucher.",
                                "nullable": true
                              },
                              "vendor": {
                                "type": "string",
                                "description": "Who the money went to, when written down.",
                                "nullable": true
                              },
                              "category": {
                                "type": "object",
                                "required": [
                                  "code",
                                  "name"
                                ],
                                "properties": {
                                  "code": {
                                    "type": "string",
                                    "description": "Its code, from List expense categories."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "The company’s name for it."
                                  }
                                },
                                "description": "Its category."
                              },
                              "otherCategory": {
                                "type": "string",
                                "description": "What it was, typed when the category is other. Several categories for a claim whose bills are in more than one.",
                                "nullable": true
                              },
                              "description": {
                                "type": "string",
                                "description": "What it was for."
                              },
                              "expenseDate": {
                                "type": "string",
                                "format": "date",
                                "description": "The day on the bill; the earliest bill’s for a claim with several."
                              },
                              "amount": {
                                "type": "number",
                                "description": "How much, in the company’s currency; the bills added up for a claim with several."
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands: in_review with its approvers, to_be_paid once they accepted it, then paid, or rejected.",
                                "enum": [
                                  "in_review",
                                  "to_be_paid",
                                  "paid",
                                  "rejected"
                                ]
                              },
                              "submittedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was made in Soom, in UTC.",
                                "nullable": true
                              },
                              "acceptedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When its approvers accepted it to be paid, in UTC.",
                                "nullable": true
                              },
                              "paidAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was paid, in UTC. A payment recorded for an earlier day reads noon that day on the company’s clock.",
                                "nullable": true
                              },
                              "paymentMethod": {
                                "type": "string",
                                "description": "How it was paid.",
                                "enum": [
                                  "cash",
                                  "bank_transfer",
                                  "upi",
                                  "cheque",
                                  "credit_card",
                                  "other"
                                ],
                                "nullable": true
                              },
                              "paymentNotes": {
                                "type": "string",
                                "description": "What was noted when it was paid, like the bank reference.",
                                "nullable": true
                              },
                              "paidTogetherId": {
                                "type": "string",
                                "description": "The same on every expense paid as one payment. null for one paid on its own. Linking payments together later doesn’t change updatedAt.",
                                "nullable": true
                              },
                              "rejectedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was rejected, in UTC.",
                                "nullable": true
                              },
                              "bills": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "category",
                                    "otherCategory",
                                    "expenseDate",
                                    "amount",
                                    "vendor",
                                    "note"
                                  ],
                                  "properties": {
                                    "category": {
                                      "type": "object",
                                      "required": [
                                        "code",
                                        "name"
                                      ],
                                      "properties": {
                                        "code": {
                                          "type": "string",
                                          "description": "Its code, from List expense categories."
                                        },
                                        "name": {
                                          "type": "string",
                                          "description": "The company’s name for it."
                                        }
                                      },
                                      "description": "Its category."
                                    },
                                    "otherCategory": {
                                      "type": "string",
                                      "description": "What it was, typed when the category is other.",
                                      "nullable": true
                                    },
                                    "expenseDate": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "The day on the bill."
                                    },
                                    "amount": {
                                      "type": "number",
                                      "description": "How much."
                                    },
                                    "vendor": {
                                      "type": "string",
                                      "description": "Who it was paid to.",
                                      "nullable": true
                                    },
                                    "note": {
                                      "type": "string",
                                      "description": "What the bill was for.",
                                      "nullable": true
                                    }
                                  }
                                },
                                "description": "Each bill of a claim that has several. Empty for an expense with one bill, which is the expense itself."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b13d4e5f6a7b8c9d0e1f203",
                        "expenseNo": "EXP-00042",
                        "kind": "claim",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "reimburseTo": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "vendor": null,
                        "category": {
                          "code": "other",
                          "name": "Other"
                        },
                        "otherCategory": "Several categories",
                        "description": "Client visit to Pune",
                        "expenseDate": "2026-11-04",
                        "amount": 3850,
                        "status": "paid",
                        "submittedAt": "2026-11-05T06:12:00.000Z",
                        "acceptedAt": "2026-11-06T09:40:00.000Z",
                        "paidAt": "2026-11-08T06:30:00.000Z",
                        "paymentMethod": "bank_transfer",
                        "paymentNotes": "UTR 452188901132",
                        "paidTogetherId": null,
                        "rejectedAt": null,
                        "bills": [
                          {
                            "category": {
                              "code": "travel",
                              "name": "Travel"
                            },
                            "otherCategory": null,
                            "expenseDate": "2026-11-04",
                            "amount": 3200,
                            "vendor": "IndiGo",
                            "note": "Flight to Pune"
                          },
                          {
                            "category": {
                              "code": "meals",
                              "name": "Meals"
                            },
                            "otherCategory": null,
                            "expenseDate": "2026-11-04",
                            "amount": 650,
                            "vendor": null,
                            "note": null
                          }
                        ],
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/expense-categories": {
      "get": {
        "operationId": "list-expense-categories",
        "tags": [
          "Expenses"
        ],
        "summary": "List expense categories",
        "description": "The categories people pick from, in the company’s order: Soom’s own, renamed or turned off as the company chose, and any the company added. Needs an app approved for Expenses.",
        "security": [
          {
            "soomApp": [
              "expenses"
            ]
          }
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "code",
                              "name",
                              "isActive"
                            ],
                            "properties": {
                              "code": {
                                "type": "string",
                                "description": "Its code, the code in an expense’s category. Soom’s own are words like travel; the company’s own start with c_."
                              },
                              "name": {
                                "type": "string",
                                "description": "Its name."
                              },
                              "isActive": {
                                "type": "boolean",
                                "description": "false when it can’t be picked for a new expense. Older expenses can still be in it."
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "code": "travel",
                        "name": "Travel",
                        "isActive": true
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/employee-documents": {
      "get": {
        "operationId": "list-employee-documents",
        "tags": [
          "Documents"
        ],
        "summary": "List employee documents",
        "description": "Everyone’s documents on file, a person to a row in employee code order: the category and when each was added, and the required categories they still miss. Never the files themselves. Needs an app approved for Documents.",
        "security": [
          {
            "soomApp": [
              "documents"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "current (the default) is everyone still working, exited is people who have left, all is both.",
            "schema": {
              "type": "string",
              "enum": [
                "current",
                "exited",
                "all"
              ]
            },
            "example": "current"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "employee",
                              "documents",
                              "missing"
                            ],
                            "properties": {
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Whose documents they are."
                              },
                              "documents": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "category",
                                    "uploadedAt",
                                    "uploadedBy"
                                  ],
                                  "properties": {
                                    "category": {
                                      "type": "object",
                                      "required": [
                                        "id",
                                        "name"
                                      ],
                                      "properties": {
                                        "id": {
                                          "type": "string",
                                          "description": "Soom’s id for the category, the id in List document categories. null when that category has since been removed.",
                                          "nullable": true
                                        },
                                        "name": {
                                          "type": "string",
                                          "description": "Its name."
                                        }
                                      },
                                      "description": "The category it is filed under."
                                    },
                                    "uploadedAt": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When it was added, in UTC.",
                                      "nullable": true
                                    },
                                    "uploadedBy": {
                                      "type": "string",
                                      "description": "self when they added it themselves, hr when HR did.",
                                      "enum": [
                                        "self",
                                        "hr"
                                      ],
                                      "nullable": true
                                    }
                                  }
                                },
                                "description": "Each document they have, by category in the company’s order, then oldest first."
                              },
                              "missing": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "id",
                                    "name"
                                  ],
                                  "properties": {
                                    "id": {
                                      "type": "string",
                                      "description": "Soom’s id for the category, the id in List document categories."
                                    },
                                    "name": {
                                      "type": "string",
                                      "description": "Its name."
                                    }
                                  }
                                },
                                "description": "The required categories they have nothing in yet."
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "documents": [
                          {
                            "category": {
                              "id": "665f0a11b7e94d0012a3b701",
                              "name": "PAN card"
                            },
                            "uploadedAt": "2024-06-04T06:20:00.000Z",
                            "uploadedBy": "self"
                          },
                          {
                            "category": {
                              "id": "665f0a11b7e94d0012a3b702",
                              "name": "Offer letter"
                            },
                            "uploadedAt": "2024-06-03T10:05:00.000Z",
                            "uploadedBy": "hr"
                          }
                        ],
                        "missing": [
                          {
                            "id": "665f0a11b7e94d0012a3b703",
                            "name": "Address proof"
                          }
                        ]
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/document-categories": {
      "get": {
        "operationId": "list-document-categories",
        "tags": [
          "Documents"
        ],
        "summary": "List document categories",
        "description": "The kinds of document the company keeps on its people, in the order Settings ▸ Document Categories lists them. Needs an app approved for Documents.",
        "security": [
          {
            "soomApp": [
              "documents"
            ]
          }
        ],
        "parameters": [
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "description",
                              "isRequired",
                              "allowsMultiple",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the category."
                              },
                              "name": {
                                "type": "string",
                                "description": "Its name."
                              },
                              "description": {
                                "type": "string",
                                "description": "What goes in it, when written down.",
                                "nullable": true
                              },
                              "isRequired": {
                                "type": "boolean",
                                "description": "true when everyone should have one. List employee documents names who doesn’t yet."
                              },
                              "allowsMultiple": {
                                "type": "boolean",
                                "description": "true when a person can keep several files in it; false keeps one."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b701",
                        "name": "PAN card",
                        "description": "A copy of the PAN card, for TDS.",
                        "isRequired": true,
                        "allowsMultiple": false,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/onboarding": {
      "get": {
        "operationId": "list-onboarding",
        "tags": [
          "Onboarding"
        ],
        "summary": "List onboarding",
        "description": "Every onboarding, latest start first, with its steps and checklist in the order its template has them. Needs an app approved for Onboarding.",
        "security": [
          {
            "soomApp": [
              "onboarding"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only onboardings with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "inProgress",
                "completed",
                "cancelled"
              ]
            },
            "example": "inProgress"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this joiner’s, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "template",
                              "status",
                              "startDate",
                              "completedAt",
                              "steps",
                              "tasks",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the onboarding."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who is joining.",
                                "nullable": true
                              },
                              "template": {
                                "type": "string",
                                "description": "The template it was started from.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "inProgress",
                                  "completed",
                                  "cancelled"
                                ]
                              },
                              "startDate": {
                                "type": "string",
                                "format": "date",
                                "description": "The day it started, usually the day they join."
                              },
                              "completedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was finished, by the joiner or by HR, in UTC.",
                                "nullable": true
                              },
                              "steps": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "title",
                                    "type",
                                    "required",
                                    "dueDate",
                                    "done",
                                    "doneAt"
                                  ],
                                  "properties": {
                                    "title": {
                                      "type": "string",
                                      "description": "What it is."
                                    },
                                    "type": {
                                      "type": "string",
                                      "description": "consent is signing a form, document is uploading one, profileFields is filling in their details, policy is reading a policy, video is watching one, task is something to do.",
                                      "enum": [
                                        "consent",
                                        "document",
                                        "profileFields",
                                        "policy",
                                        "video",
                                        "task"
                                      ]
                                    },
                                    "required": {
                                      "type": "boolean",
                                      "description": "true when it has to be done to finish."
                                    },
                                    "dueDate": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "When it is due.",
                                      "nullable": true
                                    },
                                    "done": {
                                      "type": "boolean",
                                      "description": "true once it is done."
                                    },
                                    "doneAt": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When it was done, in UTC.",
                                      "nullable": true
                                    }
                                  }
                                },
                                "description": "What the joiner goes through, in order."
                              },
                              "tasks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "title",
                                    "assignee",
                                    "dueDate",
                                    "done",
                                    "completedAt"
                                  ],
                                  "properties": {
                                    "title": {
                                      "type": "string",
                                      "description": "What it is."
                                    },
                                    "assignee": {
                                      "type": "string",
                                      "description": "Who does it: HR, or the joiner.",
                                      "enum": [
                                        "hr",
                                        "employee"
                                      ]
                                    },
                                    "dueDate": {
                                      "type": "string",
                                      "format": "date",
                                      "description": "When it is due.",
                                      "nullable": true
                                    },
                                    "done": {
                                      "type": "boolean",
                                      "description": "true once it is done."
                                    },
                                    "completedAt": {
                                      "type": "string",
                                      "format": "date-time",
                                      "description": "When it was done, in UTC.",
                                      "nullable": true
                                    }
                                  }
                                },
                                "description": "The checklist around it, like ordering a laptop."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b79d0e1f20314253647586a",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4e9",
                          "employeeCode": "EMP0033",
                          "name": "Anjali Verma"
                        },
                        "template": "Engineering joiners",
                        "status": "inProgress",
                        "startDate": "2026-12-01",
                        "completedAt": null,
                        "steps": [
                          {
                            "title": "Sign the code of conduct",
                            "type": "consent",
                            "required": true,
                            "dueDate": "2026-12-01",
                            "done": true,
                            "doneAt": "2026-11-26T10:12:00.000Z"
                          },
                          {
                            "title": "Upload your PAN card",
                            "type": "document",
                            "required": true,
                            "dueDate": "2026-12-03",
                            "done": false,
                            "doneAt": null
                          }
                        ],
                        "tasks": [
                          {
                            "title": "Order a laptop",
                            "assignee": "hr",
                            "dueDate": "2026-11-28",
                            "done": true,
                            "completedAt": "2026-11-25T07:30:00.000Z"
                          },
                          {
                            "title": "Add to payroll",
                            "assignee": "hr",
                            "dueDate": "2026-12-01",
                            "done": false,
                            "completedAt": null
                          }
                        ],
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/daily-reports": {
      "get": {
        "operationId": "list-daily-reports",
        "tags": [
          "Daily reports"
        ],
        "summary": "List daily reports",
        "description": "Every daily report for days between two dates, newest first. A person has one a day at most. Needs an app approved for Daily reports.",
        "security": [
          {
            "soomApp": [
              "daily_reports"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "First day, like 2026-11-01. Reports for days on these dates are listed.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Last day, on or after from.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-30"
          },
          {
            "name": "clientId",
            "in": "query",
            "required": false,
            "description": "Only reports with work for this client, an id from List clients.",
            "schema": {
              "type": "string"
            },
            "example": "665f0a11b7e94d0012a3b801"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "date",
                              "tasks",
                              "totalMinutes",
                              "submittedAt",
                              "editedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the report."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Whose report it is.",
                                "nullable": true
                              },
                              "date": {
                                "type": "string",
                                "format": "date",
                                "description": "The day it is about."
                              },
                              "tasks": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "description",
                                    "minutes",
                                    "status",
                                    "client",
                                    "company"
                                  ],
                                  "properties": {
                                    "description": {
                                      "type": "string",
                                      "description": "What they did."
                                    },
                                    "minutes": {
                                      "type": "number",
                                      "description": "How long it took, in minutes."
                                    },
                                    "status": {
                                      "type": "string",
                                      "description": "Where it stands.",
                                      "enum": [
                                        "completed",
                                        "in_progress",
                                        "blocked"
                                      ]
                                    },
                                    "client": {
                                      "type": "object",
                                      "required": [
                                        "id",
                                        "name"
                                      ],
                                      "properties": {
                                        "id": {
                                          "type": "string",
                                          "description": "Soom’s id for it, the id in List clients."
                                        },
                                        "name": {
                                          "type": "string",
                                          "description": "Its name."
                                        }
                                      },
                                      "description": "The client it was for, when it was for one of the company’s clients.",
                                      "nullable": true
                                    },
                                    "company": {
                                      "type": "string",
                                      "description": "Who it was for, as they wrote it, when it wasn’t one of the company’s clients.",
                                      "nullable": true
                                    }
                                  }
                                },
                                "description": "What they worked on."
                              },
                              "totalMinutes": {
                                "type": "number",
                                "description": "All its minutes added up."
                              },
                              "submittedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was sent, in UTC.",
                                "nullable": true
                              },
                              "editedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last changed after that, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b79d0e1f20314253647597b",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "date": "2026-11-10",
                        "tasks": [
                          {
                            "description": "Built the store-wise sales export",
                            "minutes": 270,
                            "status": "completed",
                            "client": {
                              "id": "665f0a11b7e94d0012a3b801",
                              "name": "Northwind Retail"
                            },
                            "company": null
                          },
                          {
                            "description": "Reviewed pull requests for the payroll team",
                            "minutes": 90,
                            "status": "in_progress",
                            "client": null,
                            "company": "Internal"
                          }
                        ],
                        "totalMinutes": 360,
                        "submittedAt": "2026-11-10T12:45:00.000Z",
                        "editedAt": null,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/announcements": {
      "get": {
        "operationId": "list-announcements",
        "tags": [
          "Announcements"
        ],
        "summary": "List announcements",
        "description": "Every announcement, pinned ones first and then newest first, as Soom shows them. Needs an app approved for Announcements.",
        "security": [
          {
            "soomApp": [
              "announcements"
            ]
          }
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Only notices, or only celebrations.",
            "schema": {
              "type": "string",
              "enum": [
                "notice",
                "celebration"
              ]
            },
            "example": "notice"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "title",
                              "body",
                              "type",
                              "pinned",
                              "publishedBy",
                              "publishedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the announcement."
                              },
                              "title": {
                                "type": "string",
                                "description": "Its title."
                              },
                              "body": {
                                "type": "string",
                                "description": "What it says, as HTML with only these tags: p, br, strong, em, u, s, ul, ol, li, a, h1 to h3, blockquote, code, pre and img."
                              },
                              "type": {
                                "type": "string",
                                "description": "notice is news for everyone, like a deadline or an office closing; celebration is a greeting, like for a festival.",
                                "enum": [
                                  "notice",
                                  "celebration"
                                ]
                              },
                              "pinned": {
                                "type": "boolean",
                                "description": "true when it is pinned to the top."
                              },
                              "publishedBy": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who posted it.",
                                "nullable": true
                              },
                              "publishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was posted, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b79d0e1f2031425364760ac",
                        "title": "Office closed on 25 December",
                        "body": "<p>The office is closed on <strong>Friday 25 December</strong> for Christmas.</p>",
                        "type": "notice",
                        "pinned": true,
                        "publishedBy": {
                          "id": "665f1c2ab7e94d0012a3c4c1",
                          "employeeCode": "EMP0007",
                          "name": "Ravi Kumar"
                        },
                        "publishedAt": "2026-11-11T05:30:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/projects": {
      "get": {
        "operationId": "list-projects",
        "tags": [
          "Projects"
        ],
        "summary": "List projects",
        "description": "Every project, by name, with its people and how many of its tasks are at each stage. Needs an app approved for Projects.",
        "security": [
          {
            "soomApp": [
              "projects"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only projects with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "on_hold",
                "completed",
                "archived"
              ]
            },
            "example": "active"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only projects this person owns or is a member of.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "description",
                              "status",
                              "owner",
                              "members",
                              "client",
                              "startDate",
                              "dueDate",
                              "taskCounts",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the project, the projectId List tasks takes."
                              },
                              "name": {
                                "type": "string",
                                "description": "Its name."
                              },
                              "description": {
                                "type": "string",
                                "description": "What it is about, when written down.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "active",
                                  "on_hold",
                                  "completed",
                                  "archived"
                                ]
                              },
                              "owner": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who runs it.",
                                "nullable": true
                              },
                              "members": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "required": [
                                    "id",
                                    "employeeCode",
                                    "name"
                                  ],
                                  "properties": {
                                    "id": {
                                      "type": "string",
                                      "description": "Soom’s id for the person, the id in List employees."
                                    },
                                    "employeeCode": {
                                      "type": "string",
                                      "description": "The code your company gave them.",
                                      "nullable": true
                                    },
                                    "name": {
                                      "type": "string",
                                      "description": "First and last name."
                                    }
                                  }
                                },
                                "description": "Who works on it, besides its owner."
                              },
                              "client": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the client, the id in List clients."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The client it is for, when it is work done for a client.",
                                "nullable": true
                              },
                              "startDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it starts.",
                                "nullable": true
                              },
                              "dueDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it is due.",
                                "nullable": true
                              },
                              "taskCounts": {
                                "type": "object",
                                "required": [
                                  "todo",
                                  "in_progress",
                                  "in_review",
                                  "done"
                                ],
                                "properties": {
                                  "todo": {
                                    "type": "number",
                                    "description": "Still to do."
                                  },
                                  "in_progress": {
                                    "type": "number",
                                    "description": "Being worked on."
                                  },
                                  "in_review": {
                                    "type": "number",
                                    "description": "Waiting to be checked."
                                  },
                                  "done": {
                                    "type": "number",
                                    "description": "Finished."
                                  }
                                },
                                "description": "How many of its tasks are at each stage."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b24e5f6a7b8c9d0e1f20314",
                        "name": "Payroll go-live",
                        "description": "Move October payroll from spreadsheets to Soom.",
                        "status": "active",
                        "owner": {
                          "id": "665f1c2ab7e94d0012a3c4c1",
                          "employeeCode": "EMP0007",
                          "name": "Ravi Kumar"
                        },
                        "members": [
                          {
                            "id": "665f1c2ab7e94d0012a3c4d5",
                            "employeeCode": "EMP0032",
                            "name": "Priya Sharma"
                          }
                        ],
                        "client": null,
                        "startDate": "2026-10-01",
                        "dueDate": "2026-11-30",
                        "taskCounts": {
                          "todo": 4,
                          "in_progress": 2,
                          "in_review": 1,
                          "done": 9
                        },
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tasks": {
      "get": {
        "operationId": "list-tasks",
        "tags": [
          "Projects"
        ],
        "summary": "List tasks",
        "description": "Every task in every project, newest first. Needs an app approved for Projects.",
        "security": [
          {
            "soomApp": [
              "projects"
            ]
          }
        ],
        "parameters": [
          {
            "name": "projectId",
            "in": "query",
            "required": false,
            "description": "Only this project’s tasks, an id from List projects.",
            "schema": {
              "type": "string"
            },
            "example": "6b24e5f6a7b8c9d0e1f20314"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only tasks at this stage.",
            "schema": {
              "type": "string",
              "enum": [
                "todo",
                "in_progress",
                "in_review",
                "done"
              ]
            },
            "example": "in_progress"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only tasks assigned to this person.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "project",
                              "title",
                              "description",
                              "status",
                              "priority",
                              "assignee",
                              "dueDate",
                              "createdAt",
                              "completedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the task."
                              },
                              "project": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List projects."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The project it belongs to.",
                                "nullable": true
                              },
                              "title": {
                                "type": "string",
                                "description": "What it is."
                              },
                              "description": {
                                "type": "string",
                                "description": "More about it, when written down.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Its column on the board.",
                                "enum": [
                                  "todo",
                                  "in_progress",
                                  "in_review",
                                  "done"
                                ]
                              },
                              "priority": {
                                "type": "string",
                                "description": "How urgent it is.",
                                "enum": [
                                  "low",
                                  "medium",
                                  "high",
                                  "urgent"
                                ]
                              },
                              "assignee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who has it. null when nobody does yet.",
                                "nullable": true
                              },
                              "dueDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it is due.",
                                "nullable": true
                              },
                              "createdAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was added, in UTC.",
                                "nullable": true
                              },
                              "completedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was moved to done, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b24e5f6a7b8c9d0e1f20425",
                        "project": {
                          "id": "6b24e5f6a7b8c9d0e1f20314",
                          "name": "Payroll go-live"
                        },
                        "title": "Check October PF figures against last year",
                        "description": null,
                        "status": "in_progress",
                        "priority": "high",
                        "assignee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "dueDate": "2026-11-14",
                        "createdAt": "2026-11-02T07:45:00.000Z",
                        "completedAt": null,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/review-cycles": {
      "get": {
        "operationId": "list-review-cycles",
        "tags": [
          "Performance"
        ],
        "summary": "List review cycles",
        "description": "Every review cycle, the latest period first, with how many reviews are in. Needs an app approved for Performance.",
        "security": [
          {
            "soomApp": [
              "performance"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only cycles at this step.",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "self_review",
                "manager_review",
                "calibration",
                "closed"
              ]
            },
            "example": "closed"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "description",
                              "periodFrom",
                              "periodTo",
                              "status",
                              "selfReviewDeadline",
                              "managerReviewDeadline",
                              "people",
                              "selfReviewsDone",
                              "managerReviewsDone",
                              "openedAt",
                              "closedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the cycle, the cycleId List reviews and List goals take."
                              },
                              "name": {
                                "type": "string",
                                "description": "Its name."
                              },
                              "description": {
                                "type": "string",
                                "description": "What it is for, when written down.",
                                "nullable": true
                              },
                              "periodFrom": {
                                "type": "string",
                                "format": "date",
                                "description": "First day of the time it reviews."
                              },
                              "periodTo": {
                                "type": "string",
                                "format": "date",
                                "description": "Last day of the time it reviews."
                              },
                              "status": {
                                "type": "string",
                                "description": "Its step: draft, people reviewing themselves, managers reviewing, HR settling the ratings, or closed.",
                                "enum": [
                                  "draft",
                                  "self_review",
                                  "manager_review",
                                  "calibration",
                                  "closed"
                                ]
                              },
                              "selfReviewDeadline": {
                                "type": "string",
                                "format": "date",
                                "description": "When self-reviews are due, when set.",
                                "nullable": true
                              },
                              "managerReviewDeadline": {
                                "type": "string",
                                "format": "date",
                                "description": "When managers’ reviews are due, when set.",
                                "nullable": true
                              },
                              "people": {
                                "type": "number",
                                "description": "How many people it reviews."
                              },
                              "selfReviewsDone": {
                                "type": "number",
                                "description": "How many sent their self-review."
                              },
                              "managerReviewsDone": {
                                "type": "number",
                                "description": "How many had their manager’s review sent."
                              },
                              "openedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was opened, in UTC.",
                                "nullable": true
                              },
                              "closedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was closed, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b68c9d0e1f2031425364758",
                        "name": "April to September 2026",
                        "description": "How the first half of the financial year went.",
                        "periodFrom": "2026-04-01",
                        "periodTo": "2026-09-30",
                        "status": "closed",
                        "selfReviewDeadline": "2026-10-15",
                        "managerReviewDeadline": "2026-10-31",
                        "people": 42,
                        "selfReviewsDone": 41,
                        "managerReviewsDone": 42,
                        "openedAt": "2026-10-01T04:30:00.000Z",
                        "closedAt": "2026-11-06T09:30:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/reviews": {
      "get": {
        "operationId": "list-reviews",
        "tags": [
          "Performance"
        ],
        "summary": "List reviews",
        "description": "Each person’s review in each cycle, newest first: who reviews them, where it stands, and the final rating once it is released to them. Never the answers or comments. Needs an app approved for Performance.",
        "security": [
          {
            "soomApp": [
              "performance"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cycleId",
            "in": "query",
            "required": false,
            "description": "Only this review cycle’s, an id from List review cycles.",
            "schema": {
              "type": "string"
            },
            "example": "6b68c9d0e1f2031425364758"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only reviews where this stands.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "self_submitted",
                "manager_submitted",
                "closed"
              ]
            },
            "example": "closed"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "cycle",
                              "employee",
                              "reviewer",
                              "status",
                              "selfSubmittedAt",
                              "managerSubmittedAt",
                              "closedAt",
                              "finalRating",
                              "finalRatingLabel",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the review."
                              },
                              "cycle": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List review cycles."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The review cycle it is in.",
                                "nullable": true
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Whose review it is.",
                                "nullable": true
                              },
                              "reviewer": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who reviews them, usually their manager, when someone does.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands: waiting on them, self-review sent, manager’s review sent, or closed.",
                                "enum": [
                                  "pending",
                                  "self_submitted",
                                  "manager_submitted",
                                  "closed"
                                ]
                              },
                              "selfSubmittedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they sent their self-review, in UTC.",
                                "nullable": true
                              },
                              "managerSubmittedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When the reviewer sent theirs, in UTC.",
                                "nullable": true
                              },
                              "closedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was closed, in UTC.",
                                "nullable": true
                              },
                              "finalRating": {
                                "type": "number",
                                "description": "The final rating, once the review is released to them: it or its cycle closed. null before.",
                                "nullable": true
                              },
                              "finalRatingLabel": {
                                "type": "string",
                                "description": "What that rating means on the company’s scale.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b68c9d0e1f2031425364869",
                        "cycle": {
                          "id": "6b68c9d0e1f2031425364758",
                          "name": "April to September 2026"
                        },
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "reviewer": {
                          "id": "665f1c2ab7e94d0012a3c4c1",
                          "employeeCode": "EMP0007",
                          "name": "Ravi Kumar"
                        },
                        "status": "closed",
                        "selfSubmittedAt": "2026-10-12T08:20:00.000Z",
                        "managerSubmittedAt": "2026-10-28T11:05:00.000Z",
                        "closedAt": "2026-11-06T09:30:00.000Z",
                        "finalRating": 4,
                        "finalRatingLabel": "Exceeds expectations",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/goals": {
      "get": {
        "operationId": "list-goals",
        "tags": [
          "Performance"
        ],
        "summary": "List goals",
        "description": "Everyone’s goals, newest first. A goal its owner still has in draft isn’t listed. Needs an app approved for Performance.",
        "security": [
          {
            "soomApp": [
              "performance"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cycleId",
            "in": "query",
            "required": false,
            "description": "Only this review cycle’s, an id from List review cycles.",
            "schema": {
              "type": "string"
            },
            "example": "6b68c9d0e1f2031425364758"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only goals where this stands.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "on_track",
                "at_risk",
                "done",
                "missed"
              ]
            },
            "example": "on_track"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "employee",
                              "cycle",
                              "title",
                              "description",
                              "metric",
                              "status",
                              "weight",
                              "startDate",
                              "dueDate",
                              "createdAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the goal."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Whose goal it is.",
                                "nullable": true
                              },
                              "cycle": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List review cycles."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The review cycle it counts towards, when it is tied to one.",
                                "nullable": true
                              },
                              "title": {
                                "type": "string",
                                "description": "The goal."
                              },
                              "description": {
                                "type": "string",
                                "description": "More about it, when written down.",
                                "nullable": true
                              },
                              "metric": {
                                "type": "string",
                                "description": "How it is measured, when written down.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands.",
                                "enum": [
                                  "active",
                                  "on_track",
                                  "at_risk",
                                  "done",
                                  "missed"
                                ]
                              },
                              "weight": {
                                "type": "number",
                                "description": "How much it counts, out of 100, when weighted.",
                                "nullable": true
                              },
                              "startDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it starts, when set.",
                                "nullable": true
                              },
                              "dueDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it is due, when set.",
                                "nullable": true
                              },
                              "createdAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was set in Soom, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b68c9d0e1f203142536497a",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "cycle": {
                          "id": "6b68c9d0e1f2031425364758",
                          "name": "April to September 2026"
                        },
                        "title": "Move every branch’s payroll to Soom",
                        "description": "Every branch paid from Soom, with no spreadsheet step.",
                        "metric": "Branches paid from Soom",
                        "status": "on_track",
                        "weight": 40,
                        "startDate": "2026-04-01",
                        "dueDate": "2026-09-30",
                        "createdAt": "2026-04-03T06:15:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/jobs": {
      "get": {
        "operationId": "list-jobs",
        "tags": [
          "Recruitment"
        ],
        "summary": "List jobs",
        "description": "Every job opening, newest first, with how many candidates are at each stage. Ask for status=open to show what you are hiring for. Needs an app approved for Recruitment.",
        "security": [
          {
            "soomApp": [
              "recruitment"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only openings with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "on_hold",
                "closed",
                "filled"
              ]
            },
            "example": "open"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "title",
                              "department",
                              "location",
                              "employmentType",
                              "description",
                              "openings",
                              "status",
                              "hiringManager",
                              "candidateCounts",
                              "createdAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the opening, the jobId List candidates takes."
                              },
                              "title": {
                                "type": "string",
                                "description": "The role."
                              },
                              "department": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List departments."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The department it is in.",
                                "nullable": true
                              },
                              "location": {
                                "type": "string",
                                "description": "Where the role is, as written on the opening.",
                                "nullable": true
                              },
                              "employmentType": {
                                "type": "string",
                                "description": "Kind of role.",
                                "enum": [
                                  "full_time",
                                  "part_time",
                                  "contract",
                                  "intern"
                                ]
                              },
                              "description": {
                                "type": "string",
                                "description": "What the role is, when written down.",
                                "nullable": true
                              },
                              "openings": {
                                "type": "number",
                                "description": "How many people it is for."
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands. filled is when everyone was hired.",
                                "enum": [
                                  "open",
                                  "on_hold",
                                  "closed",
                                  "filled"
                                ]
                              },
                              "hiringManager": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who the role reports to, when set.",
                                "nullable": true
                              },
                              "candidateCounts": {
                                "type": "object",
                                "required": [
                                  "applied",
                                  "screening",
                                  "interview",
                                  "offer",
                                  "hired",
                                  "rejected"
                                ],
                                "properties": {
                                  "applied": {
                                    "type": "number",
                                    "description": "Applied, not looked at yet."
                                  },
                                  "screening": {
                                    "type": "number",
                                    "description": "Being screened."
                                  },
                                  "interview": {
                                    "type": "number",
                                    "description": "In interviews."
                                  },
                                  "offer": {
                                    "type": "number",
                                    "description": "Offered the job."
                                  },
                                  "hired": {
                                    "type": "number",
                                    "description": "Hired."
                                  },
                                  "rejected": {
                                    "type": "number",
                                    "description": "Not taken forward."
                                  }
                                },
                                "description": "How many candidates are at each stage."
                              },
                              "createdAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was opened in Soom, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b35f6a7b8c9d0e1f2031425",
                        "title": "Senior Developer",
                        "department": {
                          "id": "665f0a11b7e94d0012a3b101",
                          "name": "Engineering"
                        },
                        "location": "Hyderabad",
                        "employmentType": "full_time",
                        "description": "Build and run the payroll engine.",
                        "openings": 2,
                        "status": "open",
                        "hiringManager": {
                          "id": "665f1c2ab7e94d0012a3c4c1",
                          "employeeCode": "EMP0007",
                          "name": "Ravi Kumar"
                        },
                        "candidateCounts": {
                          "applied": 14,
                          "screening": 5,
                          "interview": 3,
                          "offer": 1,
                          "hired": 0,
                          "rejected": 6
                        },
                        "createdAt": "2026-10-20T05:00:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/candidates": {
      "get": {
        "operationId": "list-candidates",
        "tags": [
          "Recruitment"
        ],
        "summary": "List candidates",
        "description": "Every candidate, newest first, and where they stand. A hired candidate names the employee they became. Needs an app approved for Recruitment.",
        "security": [
          {
            "soomApp": [
              "recruitment"
            ]
          }
        ],
        "parameters": [
          {
            "name": "jobId",
            "in": "query",
            "required": false,
            "description": "Only this opening’s candidates, an id from List jobs.",
            "schema": {
              "type": "string"
            },
            "example": "6b35f6a7b8c9d0e1f2031425"
          },
          {
            "name": "stage",
            "in": "query",
            "required": false,
            "description": "Only candidates at this stage.",
            "schema": {
              "type": "string",
              "enum": [
                "applied",
                "screening",
                "interview",
                "offer",
                "hired",
                "rejected"
              ]
            },
            "example": "interview"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "job",
                              "name",
                              "email",
                              "source",
                              "stage",
                              "offerStatus",
                              "hiredEmployee",
                              "addedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the candidate."
                              },
                              "job": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "title"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List jobs."
                                  },
                                  "title": {
                                    "type": "string",
                                    "description": "The role."
                                  }
                                },
                                "description": "The opening they are a candidate for.",
                                "nullable": true
                              },
                              "name": {
                                "type": "string",
                                "description": "Their name."
                              },
                              "email": {
                                "type": "string",
                                "description": "Their email."
                              },
                              "source": {
                                "type": "string",
                                "description": "Where they came from.",
                                "enum": [
                                  "referral",
                                  "linkedin",
                                  "naukri",
                                  "walk_in",
                                  "agency",
                                  "website",
                                  "other"
                                ]
                              },
                              "stage": {
                                "type": "string",
                                "description": "Where they stand.",
                                "enum": [
                                  "applied",
                                  "screening",
                                  "interview",
                                  "offer",
                                  "hired",
                                  "rejected"
                                ]
                              },
                              "offerStatus": {
                                "type": "string",
                                "description": "Where their offer stands, once one was sent.",
                                "enum": [
                                  "sent",
                                  "accepted",
                                  "declined",
                                  "withdrawn"
                                ],
                                "nullable": true
                              },
                              "hiredEmployee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "The employee they became, once hired. Their id is the one in List employees.",
                                "nullable": true
                              },
                              "addedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When they were added in Soom, in UTC.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b35f6a7b8c9d0e1f2031536",
                        "job": {
                          "id": "6b35f6a7b8c9d0e1f2031425",
                          "title": "Senior Developer"
                        },
                        "name": "Kiran Rao",
                        "email": "kiran.rao@example.com",
                        "source": "referral",
                        "stage": "interview",
                        "offerStatus": null,
                        "hiredEmployee": null,
                        "addedAt": "2026-10-28T09:15:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "add-candidate",
        "tags": [
          "Recruitment"
        ],
        "summary": "Add a candidate",
        "description": "Adds someone who applied for an open job, as HR does in Recruitment: they start at applied, and HR sees they came through the Soom API. Sending the same email for the same job again is refused, so a retry never adds anyone twice. Needs an app approved for Add candidates.",
        "security": [
          {
            "soomApp": [
              "add_candidates"
            ]
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jobId",
                  "name",
                  "email"
                ],
                "additionalProperties": false,
                "properties": {
                  "jobId": {
                    "type": "string",
                    "description": "The job they applied for, the id of an open job from List jobs."
                  },
                  "name": {
                    "type": "string",
                    "description": "Their full name."
                  },
                  "email": {
                    "type": "string",
                    "description": "Their email."
                  },
                  "phone": {
                    "type": "string",
                    "description": "Their phone number, for HR. No list gives it back."
                  },
                  "source": {
                    "type": "string",
                    "description": "Where they came from. website when left out.",
                    "enum": [
                      "referral",
                      "linkedin",
                      "naukri",
                      "walk_in",
                      "agency",
                      "website",
                      "other"
                    ]
                  },
                  "resumeKey": {
                    "type": "string",
                    "description": "Their resume: the resumeKey from Upload a resume, once the file is uploaded."
                  }
                }
              },
              "example": {
                "jobId": "6b35f6a7b8c9d0e1f2031425",
                "name": "Meera Iyer",
                "email": "meera.iyer@example.com",
                "phone": "+91 98480 22338",
                "source": "website",
                "resumeKey": "v2/tenants/665f0a11b7e94d0012a3b001/recruitment/resumes/1762929600000_k3j9x2_meera-iyer-cv.pdf"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "What was made.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "candidate",
                        "resumeAttached"
                      ],
                      "properties": {
                        "candidate": {
                          "type": "object",
                          "required": [
                            "id",
                            "job",
                            "name",
                            "email",
                            "source",
                            "stage",
                            "offerStatus",
                            "hiredEmployee",
                            "addedAt",
                            "updatedAt"
                          ],
                          "properties": {
                            "id": {
                              "type": "string",
                              "description": "Soom’s id for the candidate."
                            },
                            "job": {
                              "type": "object",
                              "required": [
                                "id",
                                "title"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for it, the id in List jobs."
                                },
                                "title": {
                                  "type": "string",
                                  "description": "The role."
                                }
                              },
                              "description": "The opening they are a candidate for.",
                              "nullable": true
                            },
                            "name": {
                              "type": "string",
                              "description": "Their name."
                            },
                            "email": {
                              "type": "string",
                              "description": "Their email."
                            },
                            "source": {
                              "type": "string",
                              "description": "Where they came from.",
                              "enum": [
                                "referral",
                                "linkedin",
                                "naukri",
                                "walk_in",
                                "agency",
                                "website",
                                "other"
                              ]
                            },
                            "stage": {
                              "type": "string",
                              "description": "Where they stand.",
                              "enum": [
                                "applied",
                                "screening",
                                "interview",
                                "offer",
                                "hired",
                                "rejected"
                              ]
                            },
                            "offerStatus": {
                              "type": "string",
                              "description": "Where their offer stands, once one was sent.",
                              "enum": [
                                "sent",
                                "accepted",
                                "declined",
                                "withdrawn"
                              ],
                              "nullable": true
                            },
                            "hiredEmployee": {
                              "type": "object",
                              "required": [
                                "id",
                                "employeeCode",
                                "name"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Soom’s id for the person, the id in List employees."
                                },
                                "employeeCode": {
                                  "type": "string",
                                  "description": "The code your company gave them.",
                                  "nullable": true
                                },
                                "name": {
                                  "type": "string",
                                  "description": "First and last name."
                                }
                              },
                              "description": "The employee they became, once hired. Their id is the one in List employees.",
                              "nullable": true
                            },
                            "addedAt": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When they were added in Soom, in UTC.",
                              "nullable": true
                            },
                            "updatedAt": {
                              "type": "string",
                              "format": "date-time",
                              "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                              "nullable": true
                            }
                          },
                          "description": "The new candidate, as List candidates gives them."
                        },
                        "resumeAttached": {
                          "type": "boolean",
                          "description": "true when their resume was attached."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "candidate": {
                      "id": "6b35f6a7b8c9d0e1f2031647",
                      "job": {
                        "id": "6b35f6a7b8c9d0e1f2031425",
                        "title": "Senior Developer"
                      },
                      "name": "Meera Iyer",
                      "email": "meera.iyer@example.com",
                      "source": "website",
                      "stage": "applied",
                      "offerStatus": null,
                      "hiredEmployee": null,
                      "addedAt": "2026-11-12T06:40:00.000Z",
                      "updatedAt": "2026-11-12T06:40:00.000Z"
                    },
                    "resumeAttached": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/resume-uploads": {
      "post": {
        "operationId": "upload-resume",
        "tags": [
          "Recruitment"
        ],
        "summary": "Upload a resume",
        "description": "Gives a link to upload one candidate’s resume to, before Add a candidate. PUT the file to uploadUrl within expiresIn seconds, with a Content-Type header the same as contentType, then send resumeKey with the candidate. Resumes stay private in Soom: HR opens them there, and no list gives them back. Needs an app approved for Add candidates.",
        "security": [
          {
            "soomApp": [
              "add_candidates"
            ]
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "fileName",
                  "contentType",
                  "size"
                ],
                "additionalProperties": false,
                "properties": {
                  "fileName": {
                    "type": "string",
                    "description": "The file’s name, as HR will see it."
                  },
                  "contentType": {
                    "type": "string",
                    "description": "What kind of file it is: a PDF, a Word file, or a photo of the resume.",
                    "enum": [
                      "application/pdf",
                      "application/msword",
                      "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                      "image/jpeg",
                      "image/png"
                    ]
                  },
                  "size": {
                    "type": "number",
                    "description": "Its size in bytes, up to 15 MB."
                  }
                }
              },
              "example": {
                "fileName": "meera-iyer-cv.pdf",
                "contentType": "application/pdf",
                "size": 248000
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "What was made.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "uploadUrl",
                        "resumeKey",
                        "expiresIn",
                        "maxBytes"
                      ],
                      "properties": {
                        "uploadUrl": {
                          "type": "string",
                          "description": "PUT the file’s bytes here, with the same Content-Type, before expiresIn runs out."
                        },
                        "resumeKey": {
                          "type": "string",
                          "description": "Send this as resumeKey in Add a candidate, once the file is uploaded."
                        },
                        "expiresIn": {
                          "type": "number",
                          "description": "Seconds uploadUrl works for."
                        },
                        "maxBytes": {
                          "type": "number",
                          "description": "The largest file it takes, in bytes."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "uploadUrl": "https://example-bucket.s3.ap-south-1.amazonaws.com/v2/tenants/665f0a11b7e94d0012a3b001/recruitment/resumes/1762929600000_k3j9x2_meera-iyer-cv.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=300&X-Amz-Signature=9f2c7e1b",
                    "resumeKey": "v2/tenants/665f0a11b7e94d0012a3b001/recruitment/resumes/1762929600000_k3j9x2_meera-iyer-cv.pdf",
                    "expiresIn": 300,
                    "maxBytes": 15728640
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/clients": {
      "get": {
        "operationId": "list-clients",
        "tags": [
          "Clients"
        ],
        "summary": "List clients",
        "description": "Every client, by name, with how many of your people work for it now. Needs an app approved for Clients.",
        "security": [
          {
            "soomApp": [
              "clients"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only clients with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "inactive"
              ]
            },
            "example": "active"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "name",
                              "status",
                              "currency",
                              "invoiceCycle",
                              "timezone",
                              "activeEmployees",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the client, the clientId the other client addresses take."
                              },
                              "name": {
                                "type": "string",
                                "description": "Its name."
                              },
                              "status": {
                                "type": "string",
                                "description": "inactive when you no longer work for it.",
                                "enum": [
                                  "active",
                                  "inactive"
                                ]
                              },
                              "currency": {
                                "type": "string",
                                "description": "What it is invoiced in, like INR or AUD."
                              },
                              "invoiceCycle": {
                                "type": "string",
                                "description": "How often it is invoiced.",
                                "enum": [
                                  "monthly",
                                  "fortnightly",
                                  "weekly"
                                ]
                              },
                              "timezone": {
                                "type": "string",
                                "description": "Its time zone, like Australia/Sydney, when set.",
                                "nullable": true
                              },
                              "activeEmployees": {
                                "type": "number",
                                "description": "How many of your people work for it now."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "665f0a11b7e94d0012a3b801",
                        "name": "Northwind Retail",
                        "status": "active",
                        "currency": "AUD",
                        "invoiceCycle": "monthly",
                        "timezone": "Australia/Sydney",
                        "activeEmployees": 6,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/client-assignments": {
      "get": {
        "operationId": "list-client-assignments",
        "tags": [
          "Clients"
        ],
        "summary": "List client assignments",
        "description": "Who of yours works for which client, newest first: their role there and from when to when. Needs an app approved for Clients.",
        "security": [
          {
            "soomApp": [
              "clients"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "active (the default) is who works for a client now, ended is who did, all is both.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "ended",
                "all"
              ]
            },
            "example": "active"
          },
          {
            "name": "clientId",
            "in": "query",
            "required": false,
            "description": "Only this client’s, an id from List clients.",
            "schema": {
              "type": "string"
            },
            "example": "665f0a11b7e94d0012a3b801"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "client",
                              "employee",
                              "role",
                              "engagementType",
                              "startDate",
                              "endDate",
                              "status",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the assignment."
                              },
                              "client": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List clients."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "The client.",
                                "nullable": true
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Who works for it.",
                                "nullable": true
                              },
                              "role": {
                                "type": "string",
                                "description": "Their role at the client, like Backend Developer.",
                                "nullable": true
                              },
                              "engagementType": {
                                "type": "string",
                                "description": "dedicated is full time for that client; contract is for a piece of work.",
                                "enum": [
                                  "dedicated",
                                  "contract"
                                ],
                                "nullable": true
                              },
                              "startDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When they started for the client.",
                                "nullable": true
                              },
                              "endDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When they stopped, or are due to.",
                                "nullable": true
                              },
                              "status": {
                                "type": "string",
                                "description": "active while they work for it.",
                                "enum": [
                                  "active",
                                  "ended"
                                ]
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b46a7b8c9d0e1f203142536",
                        "client": {
                          "id": "665f0a11b7e94d0012a3b801",
                          "name": "Northwind Retail"
                        },
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "role": "Backend Developer",
                        "engagementType": "dedicated",
                        "startDate": "2025-04-01",
                        "endDate": null,
                        "status": "active",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/client-invoices": {
      "get": {
        "operationId": "list-client-invoices",
        "tags": [
          "Clients"
        ],
        "summary": "List client invoices",
        "description": "What you invoiced your clients, latest period first, with the totals. Each person’s line stays in Soom, since it shows their rate. Needs an app approved for Clients.",
        "security": [
          {
            "soomApp": [
              "clients"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only invoices with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "approved",
                "sent",
                "paid",
                "void"
              ]
            },
            "example": "sent"
          },
          {
            "name": "clientId",
            "in": "query",
            "required": false,
            "description": "Only this client’s, an id from List clients.",
            "schema": {
              "type": "string"
            },
            "example": "665f0a11b7e94d0012a3b801"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "invoiceNo",
                              "client",
                              "periodStart",
                              "periodEnd",
                              "status",
                              "currency",
                              "subtotal",
                              "taxPercent",
                              "taxAmount",
                              "total",
                              "issueDate",
                              "dueDate",
                              "paidDate",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the invoice."
                              },
                              "invoiceNo": {
                                "type": "string",
                                "description": "Its number."
                              },
                              "client": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for it, the id in List clients."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Its name."
                                  }
                                },
                                "description": "Who it is for.",
                                "nullable": true
                              },
                              "periodStart": {
                                "type": "string",
                                "format": "date",
                                "description": "First day it bills for."
                              },
                              "periodEnd": {
                                "type": "string",
                                "format": "date",
                                "description": "Last day it bills for."
                              },
                              "status": {
                                "type": "string",
                                "description": "Where it stands. void is cancelled.",
                                "enum": [
                                  "draft",
                                  "approved",
                                  "sent",
                                  "paid",
                                  "void"
                                ]
                              },
                              "currency": {
                                "type": "string",
                                "description": "What it is in, like AUD."
                              },
                              "subtotal": {
                                "type": "number",
                                "description": "Before tax."
                              },
                              "taxPercent": {
                                "type": "number",
                                "description": "The tax rate, like 18."
                              },
                              "taxAmount": {
                                "type": "number",
                                "description": "The tax."
                              },
                              "total": {
                                "type": "number",
                                "description": "What the client pays."
                              },
                              "issueDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it was sent.",
                                "nullable": true
                              },
                              "dueDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it is to be paid by.",
                                "nullable": true
                              },
                              "paidDate": {
                                "type": "string",
                                "format": "date",
                                "description": "When it was paid.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b46a7b8c9d0e1f203142647",
                        "invoiceNo": "INV-2026-0031",
                        "client": {
                          "id": "665f0a11b7e94d0012a3b801",
                          "name": "Northwind Retail"
                        },
                        "periodStart": "2026-10-01",
                        "periodEnd": "2026-10-31",
                        "status": "sent",
                        "currency": "AUD",
                        "subtotal": 42000,
                        "taxPercent": 10,
                        "taxAmount": 4200,
                        "total": 46200,
                        "issueDate": "2026-11-01",
                        "dueDate": "2026-11-15",
                        "paidDate": null,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/payroll-runs": {
      "get": {
        "operationId": "list-payroll-runs",
        "tags": [
          "Payroll"
        ],
        "summary": "List payroll runs",
        "description": "Each month’s payroll, latest first, with its totals and how far it has gone. Its figures are final once it is locked. Needs an app approved for Payroll.",
        "security": [
          {
            "soomApp": [
              "payroll"
            ]
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only runs with this status.",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "computing",
                "computed",
                "locked",
                "failed"
              ]
            },
            "example": "locked"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "month",
                              "status",
                              "employeeCount",
                              "grossPay",
                              "deductions",
                              "employerContributions",
                              "netPay",
                              "paidCount",
                              "sentCount",
                              "computedAt",
                              "lockedAt",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the run."
                              },
                              "month": {
                                "type": "string",
                                "description": "The month it pays, like 2026-10."
                              },
                              "status": {
                                "type": "string",
                                "description": "draft is made but not worked out yet, computing is being worked out now, computed is worked out but can still change, locked is final, and failed is a work-out that stopped part-way and has to be done again in Soom.",
                                "enum": [
                                  "draft",
                                  "computing",
                                  "computed",
                                  "locked",
                                  "failed"
                                ]
                              },
                              "employeeCount": {
                                "type": "number",
                                "description": "How many people it pays, leavers’ final settlements included."
                              },
                              "grossPay": {
                                "type": "number",
                                "description": "Everyone’s pay before anything is taken off."
                              },
                              "deductions": {
                                "type": "number",
                                "description": "Everything taken off it: PF, ESI, professional tax, TDS, loan instalments and the like."
                              },
                              "employerContributions": {
                                "type": "number",
                                "description": "What the company pays on top, like its share of PF and ESI."
                              },
                              "netPay": {
                                "type": "number",
                                "description": "What is taken home: gross pay less deductions."
                              },
                              "paidCount": {
                                "type": "number",
                                "description": "How many of its payslips are paid."
                              },
                              "sentCount": {
                                "type": "number",
                                "description": "How many people can see their payslip in Soom."
                              },
                              "computedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When its figures were last worked out.",
                                "nullable": true
                              },
                              "lockedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was locked.",
                                "nullable": true
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b57b8c9d0e1f20314253647",
                        "month": "2026-10",
                        "status": "locked",
                        "employeeCount": 42,
                        "grossPay": 2184500,
                        "deductions": 196230,
                        "employerContributions": 98750,
                        "netPay": 1988270,
                        "paidCount": 42,
                        "sentCount": 42,
                        "computedAt": "2026-10-29T10:12:00.000Z",
                        "lockedAt": "2026-10-30T06:45:00.000Z",
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/payslips": {
      "get": {
        "operationId": "list-payslips",
        "tags": [
          "Payroll"
        ],
        "summary": "List payslips",
        "description": "Each person’s payslip totals, latest month first, then by employee code. A payslip is here once it is final: when its month is locked, or a leaver’s final settlement once it is settled. Until then its figures can change. Needs an app approved for Payroll.",
        "security": [
          {
            "soomApp": [
              "payroll"
            ]
          }
        ],
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "Only this month’s, like 2026-10.",
            "schema": {
              "type": "string"
            },
            "example": "2026-10"
          },
          {
            "name": "employeeCode",
            "in": "query",
            "required": false,
            "description": "Only this person, by the employee code your company gave them.",
            "schema": {
              "type": "string"
            },
            "example": "EMP0032"
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only what was added or changed at or after this moment, like 2026-11-12T09:30:00Z. The list then comes oldest change first: keep the last updatedAt you got and send it as updatedSince next time. Leave it out the first time to get everything.",
            "schema": {
              "type": "string"
            },
            "example": "2026-11-01T00:00:00Z"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Which page of the list, from 1.",
            "schema": {
              "type": "integer"
            },
            "example": "1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many items a page, up to 200. 25 when left out.",
            "schema": {
              "type": "integer"
            },
            "example": "50"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "total",
                        "page",
                        "limit"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "month",
                              "employee",
                              "kind",
                              "paidDays",
                              "lopDays",
                              "grossPay",
                              "deductions",
                              "employerContributions",
                              "netPay",
                              "paidOn",
                              "sentToEmployee",
                              "updatedAt"
                            ],
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Soom’s id for the payslip."
                              },
                              "month": {
                                "type": "string",
                                "description": "The month it pays, the month of a run in List payroll runs."
                              },
                              "employee": {
                                "type": "object",
                                "required": [
                                  "id",
                                  "employeeCode",
                                  "name"
                                ],
                                "properties": {
                                  "id": {
                                    "type": "string",
                                    "description": "Soom’s id for the person, the id in List employees."
                                  },
                                  "employeeCode": {
                                    "type": "string",
                                    "description": "The code your company gave them.",
                                    "nullable": true
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "First and last name."
                                  }
                                },
                                "description": "Whose it is.",
                                "nullable": true
                              },
                              "kind": {
                                "type": "string",
                                "description": "final_settlement is a leaver’s last payslip, settled on its own.",
                                "enum": [
                                  "monthly",
                                  "final_settlement"
                                ]
                              },
                              "paidDays": {
                                "type": "number",
                                "description": "The days it pays for: the days their salary covered, less loss of pay."
                              },
                              "lopDays": {
                                "type": "number",
                                "description": "Days of loss of pay."
                              },
                              "grossPay": {
                                "type": "number",
                                "description": "Their pay before anything is taken off."
                              },
                              "deductions": {
                                "type": "number",
                                "description": "Everything taken off it: PF, ESI, professional tax, TDS, loan instalments and the like."
                              },
                              "employerContributions": {
                                "type": "number",
                                "description": "What the company pays on top, like its share of PF and ESI."
                              },
                              "netPay": {
                                "type": "number",
                                "description": "What is taken home: gross pay less deductions."
                              },
                              "paidOn": {
                                "type": "string",
                                "format": "date",
                                "description": "The day it was paid.",
                                "nullable": true
                              },
                              "sentToEmployee": {
                                "type": "boolean",
                                "description": "true once they can see it in Soom: when it is sent to them, or for a final settlement once it is paid."
                              },
                              "updatedAt": {
                                "type": "string",
                                "format": "date-time",
                                "description": "When it was last added or changed in Soom, in UTC. Send it back as updatedSince.",
                                "nullable": true
                              }
                            }
                          }
                        },
                        "total": {
                          "type": "integer",
                          "description": "How many items match, on every page together."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "items": [
                      {
                        "id": "6b57b8c9d0e1f20314253758",
                        "month": "2026-10",
                        "employee": {
                          "id": "665f1c2ab7e94d0012a3c4d5",
                          "employeeCode": "EMP0032",
                          "name": "Priya Sharma"
                        },
                        "kind": "monthly",
                        "paidDays": 30,
                        "lopDays": 1,
                        "grossPay": 82258,
                        "deductions": 8466,
                        "employerContributions": 1800,
                        "netPay": 73792,
                        "paidOn": "2026-10-31",
                        "sentToEmployee": true,
                        "updatedAt": "2026-11-12T06:40:00.000Z"
                      }
                    ],
                    "total": 1,
                    "page": 1,
                    "limit": 25
                  }
                }
              }
            }
          },
          "400": {
            "description": "VALIDATION_ERROR: A filter, or a field you sent, is missing or isn’t valid. The message says which.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHORIZED: No access token, or it isn’t in the Authorization header. INVALID_TOKEN: The access token is wrong or was ended, or its app was switched off by the company or stopped by Soom. TOKEN_EXPIRED: The access token has run out: each works for an hour. Get a new one with your client id and secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "SCOPE_MISSING: Your app isn’t approved for this. Ask for it in Settings ▸ Integrations ▸ Soom API, and Soom approves it. API_ACCESS_OFF: The Soom API is switched off for this company. TENANT_UNAVAILABLE: The company’s Soom account isn’t active. FEATURE_OFF: This part of Soom, like overtime, time off, shift changes, assets, expenses, documents, onboarding, daily reports, announcements, projects, performance, recruitment or clients, isn’t switched on for the company, so there is nothing to read or add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "NOT_FOUND: There is no such address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "BALANCES_IN_PAYROLL: The company keeps its leave balances in Xero, so Soom has none to give. Its leave is still in List leave. PAYROLL_IN_XERO: The company runs its payroll in Xero, so Soom has no payroll runs or payslips to give. EMAIL_IN_USE: Someone in Soom already signs in with that email, so nobody was added. Sending the same person twice gets this too. CODE_IN_USE: Someone in the company already has that employee code, so nobody was added. DAY_TAKEN: That day already has times from somewhere else in Soom (clocked in there, typed by HR, regularized or synced), so they weren’t changed. HR can change them in Soom. ON_LEAVE: The person is on approved leave all that day. That day’s leave has to be cancelled in Soom first. PAYROLL_LOCKED: That month’s payroll is locked, so its days can’t change. LEAVE_OVERLAPS: The person already has leave, pending or approved, on some of those days. Sending the same leave twice gets this too. TIMEOFF_OVERLAPS: The person has a request to work from home, or a permission, on those days, and the company doesn’t allow leave on the same days. DAY_WORKED: The person clocked in on a day the leave would cover in full. Ask for half that day, or apply in Soom, where the clock-in can be cancelled. JOB_NOT_OPEN: The job is on hold, closed or filled, so nobody can be added to it. CANDIDATE_EXISTS: Someone with that email is already a candidate for that job, so nobody was added. Sending the same person twice gets this too.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "LEAVE_NOT_ALLOWED: The leave type’s rules don’t allow this leave: who can take it, the notice it needs, the fewest or most days, a document it needs, or it is no longer in use. Or every day is a weekly off or holiday. The message says which, ready to show the person.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "RATE_LIMITED: Too many calls this minute. Wait for the seconds in the Retry-After header, then try again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "soomApp": {
        "type": "oauth2",
        "description": "Your app’s client id and secret, from Settings ▸ Integrations ▸ Soom API once Soom approved it, swapped for an access token sent as Authorization: Bearer <token>.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://api.soom.co.in/api/public/v1/oauth/token",
            "scopes": {
              "employees": "Employees",
              "attendance": "Attendance",
              "leave": "Leave",
              "timeoff": "Time off",
              "company": "Company setup",
              "assets": "Assets",
              "expenses": "Expenses",
              "documents": "Documents",
              "onboarding": "Onboarding",
              "daily_reports": "Daily reports",
              "announcements": "Announcements",
              "projects": "Projects",
              "performance": "Performance",
              "recruitment": "Recruitment",
              "clients": "Clients",
              "payroll": "Payroll",
              "add_employees": "Add employees",
              "record_clock_ins": "Record clock-ins",
              "apply_for_leave": "Apply for leave",
              "add_candidates": "Add candidates"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "VALIDATION_ERROR",
                  "UNAUTHORIZED",
                  "INVALID_TOKEN",
                  "TOKEN_EXPIRED",
                  "SCOPE_MISSING",
                  "API_ACCESS_OFF",
                  "TENANT_UNAVAILABLE",
                  "FEATURE_OFF",
                  "NOT_FOUND",
                  "BALANCES_IN_PAYROLL",
                  "PAYROLL_IN_XERO",
                  "EMAIL_IN_USE",
                  "CODE_IN_USE",
                  "DAY_TAKEN",
                  "ON_LEAVE",
                  "PAYROLL_LOCKED",
                  "LEAVE_OVERLAPS",
                  "TIMEOFF_OVERLAPS",
                  "DAY_WORKED",
                  "JOB_NOT_OPEN",
                  "CANDIDATE_EXISTS",
                  "LEAVE_NOT_ALLOWED",
                  "RATE_LIMITED"
                ]
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object"
              }
            }
          }
        }
      }
    }
  }
}
