> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cadanapay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Onboard Workers

> Create employee and contractor records, configure compensation, and set up payment methods

export const ApiExample = ({method = "GET", path, params, body, reference, tenantKey}) => {
  const baseUrl = "https://api.cadanapay.com";
  const query = params ? "?" + Object.entries(params).map(([k, v]) => `${k}=${v}`).join("&") : "";
  const url = `${baseUrl}${path}${query}`;
  const isPlatformPath = (/^\/(v1\/)?platform(\/|$)/).test(path || "");
  const includeTenantKey = tenantKey === undefined ? !isPlatformPath : tenantKey;
  let curl = `curl -X ${method} '${url}' \\\n  -H 'Authorization: Bearer YOUR_API_KEY'`;
  if (includeTenantKey) {
    curl += ` \\\n  -H 'X-MultiTenantKey: YOUR_BUSINESS_TENANT_KEY'`;
  }
  if (body) {
    const formatted = JSON.stringify(body, null, 2);
    curl += ` \\\n  -H 'Content-Type: application/json' \\\n  -d '${formatted}'`;
  }
  return <div>
      <CodeBlock language="bash" filename="bash" wrap>
        {curl}
      </CodeBlock>
      {reference && <div style={{
    marginTop: "-0.5rem",
    marginBottom: "1rem"
  }}>
          <a href={reference} style={{
    fontSize: "0.875rem"
  }}>
            Try it in the playground →
          </a>
        </div>}
    </div>;
};

Onboarding a worker means creating a **Person** — the HR record that stores their personal details, job information, and compensation. Once a Person exists, you can run payroll, issue contracts, and configure how they get paid.

***

## Prerequisites

* A Cadana account with API access
* Your API key from the [Dashboard](https://app.cadanapay.com)

***

## Step 1: Create a Person

A Person represents an employee or contractor in your organization.

<Tabs>
  <Tab title="Contractor (Individual)">
    <ApiExample method="POST" path="/v1/persons" body={{ type: "CONTRACTOR", contractorType: "INDIVIDUAL", firstName: "Amara", lastName: "Okafor", email: "amara@example.com", phoneNumber: { countryCode: "234", number: "8012345678" }, address: { line1: "12 Marina Road", city: "Lagos", state: "Lagos", postalCode: "101001", countryCode: "NG" }, compInfo: { type: "net", salary: { amount: 500000, currency: "USD" }, frequency: "monthly" }, jobInfo: { title: "Frontend Developer", department: "Engineering", startDate: "2024-02-01" } }} reference="/api-reference/workforce/persons/create" />
  </Tab>

  <Tab title="Contractor (Business)">
    <ApiExample method="POST" path="/v1/persons" body={{ type: "CONTRACTOR", contractorType: "BUSINESS", businessName: "Example Consulting Ltd", firstName: "Amara", lastName: "Okafor", email: "amara@example.com", address: { line1: "12 Marina Road", city: "Lagos", state: "Lagos", postalCode: "101001", countryCode: "NG" }, compInfo: { type: "net", salary: { amount: 800000, currency: "USD" }, frequency: "monthly" } }} reference="/api-reference/workforce/persons/create" />
  </Tab>

  <Tab title="Employee">
    <ApiExample method="POST" path="/v1/persons" body={{ type: "EMPLOYEE", firstName: "Kwame", lastName: "Mensah", email: "kwame@example.com", phoneNumber: { countryCode: "233", number: "241234567" }, address: { line1: "14 Independence Ave", city: "Accra", state: "Greater Accra", postalCode: "00233", countryCode: "GH" }, compInfo: { type: "salaried", salary: { amount: 600000, currency: "GHS" }, frequency: "monthly" }, jobInfo: { title: "Product Manager", department: "Product", startDate: "2024-02-01", employeeNumber: "EMP-042" } }} reference="/api-reference/workforce/persons/create" />
  </Tab>
</Tabs>

**Response:**

```json theme={null}
{
  "id": "8ef9a712-cdae-4110-b1ea-9ba95abbee6e"
}
```

<Warning>
  Save the `id` — you'll need it to configure payment methods, create a user, and run payroll.
</Warning>

### Required Fields

| Field                   | Description                                                           |
| :---------------------- | :-------------------------------------------------------------------- |
| `type`                  | `EMPLOYEE` or `CONTRACTOR`                                            |
| `firstName`, `lastName` | Contact person's legal name                                           |
| `email`                 | Must be unique per tenant for active persons                          |
| `address.countryCode`   | ISO country code — determines available payment methods and tax rules |
| `compInfo.salary`       | Amount in minor units (cents). `500000` USD = \$5,000.00              |
| `compInfo.currency`     | Compensation currency                                                 |
| `compInfo.frequency`    | `hourly`, `daily`, or `monthly`                                       |
| `compInfo.type`         | `net` (contractor) or `salaried` (employee with tax calculation)      |

<Note>
  Set `compInfo.employmentModel: "eor"` to employ the worker through Cadana's Employer of Record — this changes what payroll collects. See [Employment Models](/workforce/employment-models).
</Note>

<Tip>
  For workers with variable pay, you may set `compInfo.salary` to `0` during onboarding. You'll provide the actual amount when [saving payroll entries](/workforce/pay-workers-via-payroll#step-2-save-entries) during a payroll run.
</Tip>

### Contractor-Specific Fields

| Field            | Description                                                       |
| :--------------- | :---------------------------------------------------------------- |
| `contractorType` | `INDIVIDUAL` or `BUSINESS` — required when `type` is `CONTRACTOR` |
| `businessName`   | Company name — required when contractorType is `BUSINESS`         |

### Optional Fields

| Field                    | Description                                                                                             |
| :----------------------- | :------------------------------------------------------------------------------------------------------ |
| `jobInfo.title`          | Job title                                                                                               |
| `jobInfo.department`     | Department name (must match a department configured on the business)                                    |
| `jobInfo.startDate`      | Employment start date (`YYYY-MM-DD`)                                                                    |
| `jobInfo.employeeNumber` | Your internal employee/contractor ID                                                                    |
| `jobInfo.entityId`       | UUID of the legal entity this person belongs to. See [Entity Management](/workforce/entity-management). |
| `jobInfo.customFields`   | Custom fields configured on the business                                                                |
| `phoneNumber`            | Must be globally unique across all tenants                                                              |
| `metadata`               | Key-value pairs for your own tracking (max 50 entries)                                                  |

***

## Step 2: Configure Payment Method

Payment methods are configured separately after creating the Person. By default, workers are paid via **Cadana Wallet** — the recommended option for most integrations.

### Cadana Wallet (Default)

Workers are paid into a [Cadana Global Wallet](https://cadanapay.com/product/global-wallets), where they can manage their funds, withdraw to a local bank, and access financial features like Virtual Cards.

To set up a wallet, the worker needs a **User account**. See [Set Up Worker Wallets](/wallets/worker-wallets) for the full flow (create User, complete KYC, wallet is provisioned automatically).

<Check>
  **Wallet is set automatically.** When you [create a User](/wallets/worker-wallets) for a Person, the platform automatically sets wallet as the preferred payment method. No separate `PUT /paymentInfo` call is needed.
</Check>

### Direct Payment Methods (Alternative)

<Warning>
  Direct payment methods (bank transfer, mobile money, etc.) require enablement for your business. Contact your account manager to configure direct-to-bank payouts.
</Warning>

If enabled, you can pay workers directly to their bank account or mobile money without creating a User account.

<Tabs>
  <Tab title="Bank Transfer">
    <ApiExample method="PUT" path="/v1/persons/8ef9a712-cdae-4110-b1ea-9ba95abbee6e/paymentInfo" body={{ preferredMethod: "bank", bank: { accountName: "Amara Okafor", accountNumber: "0123456789", bankCode: "058", bankName: "Example Bank", accountType: "Savings", currency: "NGN" } }} reference="/api-reference/workforce/persons/update-payment-information" />
  </Tab>

  <Tab title="Mobile Money">
    <ApiExample method="PUT" path="/v1/persons/8ef9a712-cdae-4110-b1ea-9ba95abbee6e/paymentInfo" body={{ preferredMethod: "momo", momo: { accountName: "Kwame Mensah", provider: "MTN", providerCode: "mtn_gh", phoneNumber: { countryCode: "233", number: "241234567" }, currency: "GHS" } }} reference="/api-reference/workforce/persons/update-payment-information" />
  </Tab>

  <Tab title="ACH (US)">
    <ApiExample method="PUT" path="/v1/persons/8ef9a712-cdae-4110-b1ea-9ba95abbee6e/paymentInfo" body={{ preferredMethod: "ach", ach: { bankName: "Example Bank", accountName: "Amara Okafor", routingNumber: "000000000", accountNumber: "123456789", accountType: "Checking" } }} reference="/api-reference/workforce/persons/update-payment-information" />
  </Tab>

  <Tab title="SWIFT">
    <ApiExample method="PUT" path="/v1/persons/8ef9a712-cdae-4110-b1ea-9ba95abbee6e/paymentInfo" body={{ preferredMethod: "swift", swift: { currency: "GBP", iban: "GB00000000000000000000", accountName: "Amara Okafor", accountNumber: "31926819", bankName: "Example Bank", swiftCode: "EXMPGB2L", address: { line1: "10 High Street", city: "London", countryCode: "GB" } } }} reference="/api-reference/workforce/persons/update-payment-information" />
  </Tab>
</Tabs>

### Payment Methods

| Method        | `preferredMethod` | Use Case                                  | Requires User |
| :------------ | :---------------- | :---------------------------------------- | :------------ |
| Cadana Wallet | `wallet`          | Default — workers manage funds via Cadana | Yes           |
| Bank transfer | `bank`            | Local bank account                        | No            |
| Mobile money  | `momo`            | Mobile money (GH, KE, UG, etc.)           | No            |
| ACH           | `ach`             | US bank accounts                          | No            |
| SWIFT         | `swift`           | International wire transfers              | No            |
| Proxy         | `proxy`           | Proxy-based payments (e.g., Pix)          | No            |

<Note>
  Available payment methods vary by country and currency. The API will return a validation error if the method isn't supported for the worker's country. See [Payment Methods](/api-reference/payments/resources/get-payment-methods) for coverage.
</Note>

### Check Current Payment Info

<ApiExample method="GET" path="/v1/persons/8ef9a712-cdae-4110-b1ea-9ba95abbee6e/paymentInfo" reference="/api-reference/workforce/persons/get-payment-information" />

***

## Step 3: Issue a Contract (Optional)

You can issue a contract to the worker immediately after onboarding. See [Manage Contracts](/workforce/manage-contracts) for the full guide.

<ApiExample method="POST" path="/v1/contracts" body={{ templateId: "c47f3b21-9a8e-4d5c-b6f2-1e0a9d8c7b6a", personId: "8ef9a712-cdae-4110-b1ea-9ba95abbee6e", sender: { name: "HR Department", email: "hr@example.com" } }} reference="/api-reference/workforce/contracts/create" />

***

## Managing Person Records

After onboarding, you can update worker details as needed:

| Operation            | Endpoint                                                                                                  | What it updates                                                                      |
| :------------------- | :-------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------- |
| Get person           | [`GET /v1/persons/{personId}`](/api-reference/workforce/persons/get)                                      | Retrieve full person record                                                          |
| List persons         | [`GET /v1/persons`](/api-reference/workforce/persons/list)                                                | List all persons (filterable by email)                                               |
| Update basic info    | [`PUT /v1/persons/{personId}/basicInfo`](/api-reference/workforce/persons/update-basic-information)       | Name, email, phone, metadata                                                         |
| Update personal info | [`PUT /v1/persons/{personId}/personalInfo`](/api-reference/workforce/persons/update-personal-information) | Date of birth, national ID, tax ID, social security ID, gender, nationality, address |
| Update job info      | [`PUT /v1/persons/{personId}/jobInfo`](/api-reference/workforce/persons/update-job-information)           | Title, department, compensation, start date                                          |
| Update payment info  | [`PUT /v1/persons/{personId}/paymentInfo`](/api-reference/workforce/persons/update-payment-information)   | Preferred payment method and details                                                 |
| Update tax profile   | [`PUT /v1/persons/{personId}/taxProfile`](/api-reference/workforce/persons/update-tax-profile)            | Marital status, number of dependents, and other country-specific tax fields          |

See the [Workforce API Reference](/api-reference/workforce) for full request and response schemas.

<Note>
  Person profile writes (e.g., tax profile, payment info) are applied asynchronously — a read immediately after a write may return the previous state, and approving a payroll immediately after saving it can briefly fail. Retry after a short delay.
</Note>

***

## Change Employment Type

To switch a person between Employee and Contractor without offboarding and re-onboarding, use the **Update Person Type** endpoint. The person must be in **Active** status.

<Tabs>
  <Tab title="Simple (auto-convert comp)">
    <ApiExample method="PUT" path="/v1/persons/{personId}/type" body={{ newType: "CONTRACTOR" }} reference="/api-reference/workforce/persons/update-person-type" />
  </Tab>

  <Tab title="With new compensation">
    <ApiExample method="PUT" path="/v1/persons/{personId}/type" body={{ newType: "EMPLOYEE", compInfo: { type: "salaried", salary: { amount: 600000, currency: "GHS" }, frequency: "monthly" } }} reference="/api-reference/workforce/persons/update-person-type" />
  </Tab>
</Tabs>

A successful request returns **`204 No Content`**.

### Request Fields

| Field                | Type     | Required                   | Description                                                                                  |
| :------------------- | :------- | :------------------------- | :------------------------------------------------------------------------------------------- |
| `newType`            | `string` | Yes                        | Target employment type: `EMPLOYEE` or `CONTRACTOR`                                           |
| `compInfo`           | `object` | No                         | Compensation for the new type. If omitted, incompatible compensation is auto-converted.      |
| `compInfo.type`      | `string` | Yes (if compInfo provided) | Compensation type: `net`, `salaried`, `gross`, or `fixed`                                    |
| `compInfo.salary`    | `object` | Yes (if compInfo provided) | Amount in minor units with currency (e.g., `{ "amount": 600000, "currency": "GHS" }`)        |
| `compInfo.frequency` | `string` | No                         | Pay frequency: `monthly`, `daily`, `weekly`, `biweekly`, or `hourly`. Defaults to `monthly`. |

### Auto-Conversion Rules

When `compInfo` is omitted, the API automatically converts incompatible compensation types:

| Current comp type | Target person type | Result                                                                            |
| :---------------- | :----------------- | :-------------------------------------------------------------------------------- |
| `salaried`        | Contractor         | Auto-converted to `net` — same amount and frequency                               |
| `fixed`           | Employee           | Auto-converted to `net` — same amount, frequency defaults to `monthly` if not set |
| `net` or `gross`  | Either             | No conversion needed — left unchanged                                             |

<Note>
  Auto-conversion only changes the compensation **type**. All other compensation fields (allowances, deductions, tax reliefs, employer contributions, pension settings) are preserved. The tax engine interprets these fields based on the person's type at payroll calculation time.
</Note>

### Compensation Type Compatibility

When providing `compInfo`, the compensation type must be compatible with the target person type:

| Comp type  | Employee | Contractor |
| :--------- | :------- | :--------- |
| `salaried` | Yes      | No         |
| `gross`    | Yes      | Yes        |
| `net`      | Yes      | Yes        |
| `fixed`    | No       | Yes        |

<Tip>
  Pass `compInfo` when you want to set a specific compensation structure for the new type — for example, switching a contractor to a salaried employee with tax calculation, or changing the pay amount alongside the type switch.
</Tip>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Set Up Worker Wallets" icon="wallet" href="/wallets/worker-wallets">
    Create a User account and provision a Cadana wallet
  </Card>

  <Card title="Pay Workers via Payroll" icon="rocket" href="/workforce/pay-workers-via-payroll">
    Pay your onboarded workers
  </Card>

  <Card title="Manage Contracts" icon="file-signature" href="/workforce/manage-contracts">
    Issue employment or contractor agreements
  </Card>

  <Card title="Admin Management" icon="user-shield" href="/workforce/admin-management">
    Add and manage business administrators
  </Card>
</CardGroup>
