Set Pay Rates
The "Set Pay Rates" endpoint creates or updates pay rates for one or more users in a single bulk request.
Endpoint
PUT https://api.connecteam.com/pay-rates/v1/pay-rates
Authentication
- API Key or OAuth 2.0
- OAuth Scope:
pay_rates.write
Upsert Behavior
This endpoint uses upsert semantics: if a pay rate already exists for the same user and effective date, it is fully replaced. Otherwise, a new entry is added to the user's pay rate history. There is no separate "create" vs "update" endpoint.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
payRatesByUsers | array | Yes | Array of user pay rate objects (max 500) |
payRatesByUsers[].userId | integer | Yes | The user ID |
payRatesByUsers[].payRate.effectiveDate | string | Yes | Effective date (YYYY-MM-DD) |
payRatesByUsers[].payRate.rateType | string | Yes | hourly, monthly, or yearly |
payRatesByUsers[].payRate.isDefaultRateEnabled | boolean | No | Enable default rate (default: true) |
payRatesByUsers[].payRate.defaultRate | number | Conditional | Required when isDefaultRateEnabled is true. Must be > 0 |
payRatesByUsers[].payRate.isResourceRateEnabled | boolean | No | Enable resource-specific rates (default: false) |
payRatesByUsers[].payRate.isApplyDefaultRateToNewResource | boolean | No | Auto-apply default rate to newly assigned resources (default: true) |
payRatesByUsers[].payRate.resourcesRates | array | No | Resource rate configurations |
Validation Rules
defaultRateis required whenisDefaultRateEnabledistrue. Omitting it returns 400.defaultRatecan be omitted whenisDefaultRateEnabledisfalse— the response will not include the field.- All rate values must be > 0 — zero and negative values are rejected (400). This applies to
defaultRate, resourcerate, and sub-resourcerate. effectiveDatemust be in YYYY-MM-DD format — other formats like DD-MM-YYYY are rejected.rateTypemust be one ofhourly,monthly, oryearly— invalid values (e.g.weekly) are rejected.- User IDs must exist in your company — non-existent user IDs return 400 with the invalid IDs listed.
- Locked days check — if any user has approved/locked timesheet days on or after the effective date, the entire request is rejected with 409
HAS_LOCKED_DAYS.
Resource Rate Configuration
When isResourceRateEnabled is true, you can configure per-resource (job) rates:
| Field | Type | Required | Description |
|---|---|---|---|
resourcesRates[].resourceId | string | Yes | Resource (job) ID |
resourcesRates[].rate | number | Conditional | Rate amount (> 0). Not required when useDefaultRate is true |
resourcesRates[].useDefaultRate | boolean | No | Inherit the user's default rate (default: false) |
resourcesRates[].subResourcesRates | array | No | Sub-resource rate configurations |
subResourcesRates[].subResourceId | string | Yes | Sub-resource ID |
subResourcesRates[].rate | number | Conditional | Rate amount (> 0). Not required when useParentRate is true |
subResourcesRates[].useParentRate | boolean | No | Inherit parent resource's rate (default: false) |
Important: Include ALL resourcesThe
resourcesRatesarray should include all resources that need custom rates. Resources not included will not have a resource-specific rate configured.
Rate InheritanceWhen
useDefaultRateis true on a resource, theratefield is omitted from both the request and response — the resource inherits the user's default rate. The same applies to sub-resources withuseParentRateset to true.
Request Example
{
"payRatesByUsers": [
{
"userId": 12345,
"payRate": {
"effectiveDate": "2025-03-01",
"rateType": "hourly",
"isDefaultRateEnabled": true,
"defaultRate": 30.00,
"isResourceRateEnabled": true,
"isApplyDefaultRateToNewResource": true,
"resourcesRates": [
{
"resourceId": "job_001",
"rate": 35.00,
"useDefaultRate": false,
"subResourcesRates": []
},
{
"resourceId": "job_002",
"useDefaultRate": true,
"subResourcesRates": [
{
"subResourceId": "sub_001",
"useParentRate": true
}
]
}
]
}
}
]
}Response
The response mirrors the GET response structure, returning the created/updated pay rates for each user:
{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"payRatesByUsers": [
{
"userId": 12345,
"payRate": {
"effectiveDate": "2025-03-01",
"rateType": "hourly",
"isDefaultRateEnabled": true,
"defaultRate": 30.00,
"isResourceRateEnabled": true,
"isApplyDefaultRateToNewResource": true,
"resourcesRates": [...],
"createdBy": 99999,
"createdAt": 1709251200
}
}
]
}
}Error Codes
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | 1002 | Invalid request body — bad rate value (0 or negative), missing required field, invalid date format, invalid rate type |
| 400 | 1004 | User validation failed — one or more user IDs don't exist in the company |
| 401 | — | Missing authentication |
| 403 | — | Invalid API key or insufficient OAuth scope |
| 409 | HAS_LOCKED_DAYS | Effective date conflicts with approved or locked timesheet days |
Updated about 18 hours ago
