Using the Staff API

API OAuth Staff Management Staff CRUD Android iOS

Purpose of this guide

This guide covers how to create, retrieve, update, and delete the staff (employees) under a business account using ReceiptRoller's Staff API. It is the entry point for working with staff data — for shift management apps, per-POS-operator sales apps, HR system integrations, and more.

Prerequisites

  • You have obtained an access token via the OAuth 2.0 authorization code flow
  • Your app's scopes include store.staff.read (read) / store.staff.write (create, update, delete)
  • You know the business account ID (UUID) (Listing business accounts, stores, and POS terminals)
  • Base URL: https://receiptroller.io

Endpoints

MethodPathPurposeRequired scope
GET/api/v1/staffList / search staffstore.staff.read
GET/api/v1/staff/{staffId}Detail of one personstore.staff.read
POST/api/v1/staffCreatestore.staff.write
PUT/api/v1/staff/{staffId}Updatestore.staff.write
DELETE/api/v1/staff/{staffId}Delete (soft delete)store.staff.write

1. Retrieve the staff list

GET /api/v1/staff?organizationId={organizationId}
Authorization: Bearer {access_token}

Query parameters (all optional, AND-combined)

  • storeId — only staff assigned to that store (staff assigned to all stores are also included)
  • position — filter by role/title (exact match)
  • employmentType — FullTime / PartTime / Contract / Other
  • status — Active / Inactive / Pending
  • search — partial search by name (including kana), employee number, or reference ID
  • includeDeleted — whether to include deleted records (default false)

Response example

{
  "organizationId": "a04507de-043a-4b47-b0a3-6204562f6e20",
  "staff": [
    {
      "id": "stf-001",
      "organizationId": "a04507de-...",
      "employeeNumber": "E-0001",
      "referenceId": "TM_xyz",
      "userId": "",
      "name": {
        "first": "Taro",
        "last": "Tanaka",
        "firstKana": "タロウ",
        "lastKana": "タナカ",
        "display": "Taro Tanaka"
      },
      "role": {
        "position": "Store manager",
        "employmentType": "FullTime",
        "isOwner": false
      },
      "status": "Active",
      "contact": { "phone": "090-1234-5678", "email": "tanaka@example.com" },
      "hr": { "hireDate": "2024-04-01T00:00:00Z", "dateOfBirth": "1990-05-15T00:00:00Z", "address": "Shibuya-ku, Tokyo..." },
      "pay": {
        "hourlyRate": 1800,
        "isOvertimeExempt": true,
        "tipEligible": true,
        "jobs": [
          {
            "jobTitle": "Store manager",
            "payType": "HOURLY",
            "hourlyRate": 1800,
            "annualRate": 0,
            "weeklyHours": 40,
            "locationIds": ["store-A"]
          },
          {
            "jobTitle": "Cashier",
            "payType": "HOURLY",
            "hourlyRate": 1200,
            "annualRate": 0,
            "weeklyHours": 10,
            "locationIds": ["store-B"]
          }
        ]
      },
      "assignments": {
        "storeIds": ["store-A", "store-B"],
        "allLocations": false
      },
      "emergency": { "name": "Hanako Tanaka", "phone": "090-...", "relation": "Spouse" },
      "integrations": { "squareTeamMemberId": "TM_xyz", "smaregiStaffId": "" },
      "profileImageUrl": "https://...",
      "notes": "",
      "createdAt": "2024-04-01T09:00:00Z",
      "updatedAt": "2026-06-02T10:30:00Z"
    }
  ],
  "totalCount": 1
}

2. Retrieve the detail of one person

GET /api/v1/staff/{staffId}?organizationId={organizationId}
Authorization: Bearer {access_token}

Returns 404 if the staff member does not belong to the specified business account.

3. Create

POST /api/v1/staff?organizationId={organizationId}
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "displayName": "Hanako Sato",
  "firstName": "Hanako",
  "lastName": "Sato",
  "firstNameKana": "ハナコ",
  "lastNameKana": "サトウ",
  "employeeNumber": "E-0002",
  "position": "Cashier",
  "employmentType": "PartTime",
  "status": "Active",
  "phone": "080-9876-5432",
  "email": "sato@example.com",
  "hourlyRate": 1200,
  "hireDate": "2026-06-01",
  "isOvertimeExempt": false,
  "tipEligible": true,
  "assignedStoreIds": "store-001,store-002",
  "isAssignedToAllLocations": false,
  "jobAssignmentsJson": "[{\"jobTitle\":\"Cashier\",\"payType\":\"HOURLY\",\"hourlyRate\":1200,\"weeklyHours\":20,\"locationIds\":[\"store-001\"]}]"
}

Points

  • Either displayName, or firstName + lastName, is required
  • Even if you include organizationId in the request body, it is ignored. The business account resolved from the token/query is always used
  • If there are multiple jobs, pass an array in jobAssignmentsJson. For a single job, just position + hourlyRate is fine

4. Update

PUT /api/v1/staff/{staffId}?organizationId={organizationId}
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "displayName": "Hanako Sato",
  "phone": "080-9876-5432",
  "hourlyRate": 1300,
  "status": "Active"
}

Overwrites with the fields you send (a full replacement, not a partial update). For fields whose values you want to keep, resend the existing values along with the change.

5. Delete (soft delete)

DELETE /api/v1/staff/{staffId}?organizationId={organizationId}
Authorization: Bearer {access_token}

Points

  • The response is 204 No Content
  • Because it is a soft delete, resolving the staff ID from past shift logs or POS transactions still works
  • Deleted staff are not included in list or search results

Correspondence with Square Team Member

This API's fields are compatible with the Square Team Members API. On a business account where the Square integration is enabled, integrations.squareTeamMemberId is set automatically, and changes on Square are also reflected into ReceiptRoller (planned for implementation in Phase 3, t-e9a2f482).

Fields originating from Square

  • referenceId ⇔ Square reference_id
  • role.isOwner ⇔ Square is_owner
  • status ⇔ Square status (ACTIVE → "Active" / INACTIVE → "Inactive")
  • assignments.allLocations ⇔ Square assignment_type: ALL
  • pay.jobs ⇔ Square wage_setting.job_assignments
  • pay.isOvertimeExempt ⇔ Square is_overtime_exempt
  • pay.tipEligible ⇔ Square tip_eligible

Fields unique to ReceiptRoller (not present in / not synced from Square)

  • Name kana (firstNameKana, lastNameKana)
  • Hire date, date of birth, address
  • Emergency contact (emergency.*)
  • Employment type (FullTime / PartTime / Contract / Other)
  • Profile photo
  • Notes, employee number, Smaregi integration ID

Typical flow (mobile app)

  1. Obtain an access token via OAuth → scopes include store.staff.read and store.staff.write
  2. Select a business account with GET /api/v1/me/organizations
  3. Show GET /api/v1/staff?storeId=... paginated on the staff list screen
  4. Add a new staff member with POST /api/v1/staff
  5. On the edit screen, GET /api/v1/staff/{id} → PUT /api/v1/staff/{id}
  6. For offboarding, DELETE /api/v1/staff/{id} (or PUT with status: "Inactive")

Error responses

StatusMeaningWhat to do
401 UnauthorizedAccess token invalid / expiredRe-obtain with the refresh token
403 ForbiddenMissing the required scope / not a member of the business accountCheck the scope and the selected business account
400 Bad RequestMissing required field (displayName or firstName/lastName)Review the request body
404 Not FoundThe staff ID does not exist in that business accountRe-fetch from the list

Related information

Published: 2026-06-03 Updated: 2026-07-05
About this topic
Developer API
See the feature
Tags
API (22) OAuth (16) Android (11) iOS (9) Webhook (5) App registration (4) POS Integration (4) Reference (4) Troubleshooting (4) api (4)
Related articles