> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.crehana.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.crehana.com/_mcp/server.

# Assign Shift

POST https://www.crehana.com/api/v5/rest/org/{organization_slug}/time/attendance/shift-assignments/
Content-Type: application/json

Assigns one shift to one or more people for a period, exactly as an administrator would from Attendance in Crehana. Built for HR and workforce-planning systems that own the schedule and push it to Crehana. Step-by-step guide: [Assign shifts](/documentacion/casos-de-uso/asignar-turnos).

Once assigned, the shift drives the attendance of those days: marks are matched to it, punctuality is classified against it and the daily attendance is recalculated.

- `start_date` and `end_date` are calendar days, inclusive; `end_date` is optional for an open-ended assignment.
- A rotating shift needs `start_cycle_id`, the cycle it starts with on `start_date`. A fixed shift takes no cycle.
- If a person already has a shift that overlaps the new one in that period, the previous assignment is deactivated and the new one takes its place. Once shifts are allowed to coexist on the same day, an overlap is rejected instead: `409` with one conflict per person, and nobody gets the shift (all-or-nothing).
- Sending the same assignment again is safe: people who already have this exact shift in this period are listed in `already_assigned_user_ids`, nothing is duplicated and the answer is `200` when there is nothing new.
- The shift must belong to the organization and be active, and every person must belong to it, otherwise `404` (`detail.code` says which).
- Requires credentials of an administrator of the organization.

Reference: https://developer.crehana.com/api-reference/endpoints/attendance/assign-shift

## Authentication

- `Api-Key` header (required) — API key of the organization. Always sent together with the `Secret-Access` header.

## Servers

- `https://www.crehana.com` (Production, default)
- `https://qa.creha.co` (QA)

## Request

### Path parameters

- `organization_slug` (string, required)

### Body (application/json)

This endpoint expects an AssignShiftInput.

- `shift_id` (string, required) — Id of the shift to assign, as shown in Attendance in Crehana. The shift must belong to the organization and be active.
- `user_ids` (list of integer, required) — Centralized ids of the people who get the shift: `user.id` in `GET /org/{organization_slug}/users/user-organizations/`. Not the learning user id. Between 1 and 100 ids, without repeats. The request is all-or-nothing: if one person cannot take the shift, nobody gets it.
- `start_date` (date, required) — First day of the assignment, `YYYY-MM-DD`.
- `end_date` (date, optional) — Last day of the assignment, `YYYY-MM-DD`, inclusive. Omit it or send `null` for an open-ended assignment.
- `start_cycle_id` (string, optional) — For rotating shifts only: id of the cycle the rotation starts with on `start_date`. Required for a rotating shift, and must be omitted for a fixed one.

## Response

### 200

Everybody already had this shift in this period; nothing new

- `success` (boolean, required) — True when the shift is assigned.
- `message` (string, required) — Human readable result.
- `code` (string, required) — `attendance-003` when at least one assignment was created, `attendance-004` when everybody already had the shift. Not an HTTP status.
- `datetime` (string, required) — Datetime of the API in ISO Format
- `data` (AssignShiftData, required)

### 201

Shift assigned

- `success` (boolean, required) — True when the shift is assigned.
- `message` (string, required) — Human readable result.
- `code` (string, required) — `attendance-003` when at least one assignment was created, `attendance-004` when everybody already had the shift. Not an HTTP status.
- `datetime` (string, required) — Datetime of the API in ISO Format
- `data` (AssignShiftData, required)

## Errors

### 400 Bad Request Error

Unknown organization, or a rotating shift without `start_cycle_id` (or a fixed one with it)

- `detail` (AttendanceErrorDetail, required)

### 401 Unauthorized Error

Missing or invalid credentials

- `any`

### 403 Forbidden Error

The credentials do not administer the organization

- `detail` (AttendanceErrorDetail, required)

### 404 Not Found Error

The shift does not exist in the organization or is inactive (`SHIFT_NOT_FOUND`), or some of the people do not belong to it (`USER_NOT_FOUND`, with `detail.user_ids`)

- `detail` (AttendanceErrorDetail, required)

### 409 Conflict Error

The shift clashes with a shift one of the people already has; nothing was assigned

- `detail` (ShiftAssignmentBlockedDetail, required)

### 422 Unprocessable Entity Error

The body does not match the schema

- `any`

## Types

### AssignShiftData

- `shift_id` (string, required) — Id of the assigned shift.
- `start_date` (date, required) — First day of the assignment.
- `assignments` (list of ShiftAssignment, required) — One assignment per person that got the shift. A person who already had this exact shift in this period is not repeated here.
- `already_assigned_user_ids` (list of integer, required) — People from `user_ids` who already had this exact shift in this period: nothing new was written for them.
- `end_date` (date, optional) — Last day of the assignment; `null` when open-ended.
- `start_cycle_id` (string, optional) — Starting cycle, for rotating shifts; `null` for fixed ones.

### AttendanceErrorDetail

- `errors` (list of string, required) — Why the request was rejected, for a log or a person.
- `code` (string, optional) — Stable reason to program against, when there is one.
- `user_ids` (list of integer, optional) — Only with `USER_NOT_FOUND` on shift assignments: the ids that do not belong to the organization.
- `shift_id` (string, optional) — Only with `SHIFT_NAME_ALREADY_EXISTS` on shift creation: the id of the active shift that already has that name.

### ShiftAssignmentBlockedDetail

- `errors` (list of string, required) — Why the request was rejected.
- `code` (string, required) — `SHIFT_ASSIGNMENT_BLOCKED`.
- `conflicts` (list of ShiftClashConflict, required) — One entry per person who cannot take the shift.

### ShiftAssignment

- `id` (string, required) — Id of the assignment.
- `user_id` (integer, required) — Centralized id of the person.
- `shift_id` (string, required) — Id of the assigned shift.
- `start_date` (date, required) — First day of the assignment.
- `is_active` (boolean, required) — True while the assignment is in force.
- `end_date` (date, optional) — Last day of the assignment; `null` when open-ended.
- `start_cycle_id` (string, optional) — Starting cycle, for rotating shifts; `null` for fixed ones.
- `created_at` (string, optional) — When the assignment was created, in UTC (no offset).

### ShiftClashConflict

- `user_id` (integer, required) — The person who cannot take the shift.
- `reason` (string, required) — `SHIFT_TIME_OVERLAP` when the new shift overlaps in time with one the person already has, `DAILY_SHIFT_LIMIT_EXCEEDED` when the person would exceed the shifts allowed in one day.
- `resulting_shift_count` (integer, required) — Shifts the person would have on that day.
- `conflict_date` (date, optional) — First day on which the clash happens.
- `conflicting_shift_id` (string, optional) — The shift the person already has that overlaps the new one. `null` for `DAILY_SHIFT_LIMIT_EXCEEDED`.
- `conflicting_shift_name` (string, optional) — Name of that shift.

## Examples

### Example 1

**Request**

```json
{
  "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
  "user_ids": [
    97097,
    97099
  ],
  "start_date": "2026-10-13"
}
```

**Response**

```json
{
  "success": true,
  "message": "Shift assigned.",
  "code": "attendance-003",
  "datetime": "2026-10-07T09:00:03.120394",
  "data": {
    "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
    "start_date": "2026-10-13",
    "assignments": [
      {
        "id": "9f1c2a7e-3b6d-4c2a-8e1f-5a7b9c0d1e2f",
        "user_id": 97097,
        "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
        "start_date": "2026-10-13",
        "is_active": true,
        "end_date": "2026-12-31",
        "start_cycle_id": "string",
        "created_at": "2026-10-07T15:00:03"
      }
    ],
    "already_assigned_user_ids": [],
    "end_date": "2026-12-31",
    "start_cycle_id": "string"
  }
}
```

**SDK Code**

```python
import requests

url = "https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/"

payload = {
    "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
    "user_ids": [97097, 97099],
    "start_date": "2026-10-13"
}
headers = {
    "Secret-Access": "Secret-Access",
    "Api-Key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/';
const options = {
  method: 'POST',
  headers: {
    'Secret-Access': 'Secret-Access',
    'Api-Key': '<apiKey>',
    'Content-Type': 'application/json'
  },
  body: '{"shift_id":"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1","user_ids":[97097,97099],"start_date":"2026-10-13"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/"

	payload := strings.NewReader("{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Secret-Access", "Secret-Access")
	req.Header.Add("Api-Key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Secret-Access"] = 'Secret-Access'
request["Api-Key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/")
  .header("Secret-Access", "Secret-Access")
  .header("Api-Key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/', [
  'body' => '{
  "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
  "user_ids": [
    97097,
    97099
  ],
  "start_date": "2026-10-13"
}',
  'headers' => [
    'Api-Key' => '<apiKey>',
    'Content-Type' => 'application/json',
    'Secret-Access' => 'Secret-Access',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/");
var request = new RestRequest(Method.POST);
request.AddHeader("Secret-Access", "Secret-Access");
request.AddHeader("Api-Key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Secret-Access": "Secret-Access",
  "Api-Key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
  "user_ids": [97097, 97099],
  "start_date": "2026-10-13"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Example 2

**Request**

```json
{
  "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
  "user_ids": [
    97097,
    97099
  ],
  "start_date": "2026-10-13"
}
```

**Response**

```json
{
  "success": true,
  "message": "Shift assigned.",
  "code": "attendance-003",
  "datetime": "2026-10-07T09:00:03.120394",
  "data": {
    "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
    "start_date": "2026-10-13",
    "assignments": [
      {
        "id": "9f1c2a7e-3b6d-4c2a-8e1f-5a7b9c0d1e2f",
        "user_id": 97097,
        "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
        "start_date": "2026-10-13",
        "is_active": true,
        "end_date": "2026-12-31",
        "start_cycle_id": "string",
        "created_at": "2026-10-07T15:00:03"
      }
    ],
    "already_assigned_user_ids": [],
    "end_date": "2026-12-31",
    "start_cycle_id": "string"
  }
}
```

**SDK Code**

```python
import requests

url = "https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/"

payload = {
    "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
    "user_ids": [97097, 97099],
    "start_date": "2026-10-13"
}
headers = {
    "Secret-Access": "Secret-Access",
    "Api-Key": "<apiKey>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/';
const options = {
  method: 'POST',
  headers: {
    'Secret-Access': 'Secret-Access',
    'Api-Key': '<apiKey>',
    'Content-Type': 'application/json'
  },
  body: '{"shift_id":"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1","user_ids":[97097,97099],"start_date":"2026-10-13"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/"

	payload := strings.NewReader("{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Secret-Access", "Secret-Access")
	req.Header.Add("Api-Key", "<apiKey>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Secret-Access"] = 'Secret-Access'
request["Api-Key"] = '<apiKey>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/")
  .header("Secret-Access", "Secret-Access")
  .header("Api-Key", "<apiKey>")
  .header("Content-Type", "application/json")
  .body("{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/', [
  'body' => '{
  "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
  "user_ids": [
    97097,
    97099
  ],
  "start_date": "2026-10-13"
}',
  'headers' => [
    'Api-Key' => '<apiKey>',
    'Content-Type' => 'application/json',
    'Secret-Access' => 'Secret-Access',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/");
var request = new RestRequest(Method.POST);
request.AddHeader("Secret-Access", "Secret-Access");
request.AddHeader("Api-Key", "<apiKey>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"shift_id\": \"4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1\",\n  \"user_ids\": [\n    97097,\n    97099\n  ],\n  \"start_date\": \"2026-10-13\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Secret-Access": "Secret-Access",
  "Api-Key": "<apiKey>",
  "Content-Type": "application/json"
]
let parameters = [
  "shift_id": "4ed0f6c7-a2a7-4de7-90cd-ae8cf26aabb1",
  "user_ids": [97097, 97099],
  "start_date": "2026-10-13"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://www.crehana.com/api/v5/rest/org/organization_slug/time/attendance/shift-assignments/")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```