curl -X POST "https://api.dcycle.io/v2/own-workforce/trainings" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 5e4d3c2b-1a09-4f8e-9d7c-6b5a49382716" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
"client_row_id": "LMS-8841"
}
]
}'
import os
import uuid
import requests
response = requests.post(
"https://api.dcycle.io/v2/own-workforce/trainings",
headers={
"x-api-key": os.environ["DCYCLE_API_KEY"],
"x-organization-id": os.environ["DCYCLE_ORG_ID"],
"Idempotency-Key": str(uuid.uuid4()), # keep it to retry this same batch
},
json={
"records": [
{
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
}
]
},
timeout=60,
)
response.raise_for_status()
print([item["training"]["id"] for item in response.json()["items"]])
{
"items": [
{
"source_row_index": 0,
"client_row_id": "LMS-8841",
"training": {
"id": "3b2a1908-7f6e-4d5c-8b4a-392817160504",
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
"created_at": "2026-10-19T09:12:44.031Z"
}
}
]
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Entity",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "LMS-8841",
"error_code": "REFERENCE_NOT_FOUND",
"error_params": { "field": "own_workforce_id", "value": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 1, "valid": 1 }
Create Workforce Trainings (v2)
Create up to 1,000 trainings of your employees in one request
POST
/
v2
/
own-workforce
/
trainings
curl -X POST "https://api.dcycle.io/v2/own-workforce/trainings" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 5e4d3c2b-1a09-4f8e-9d7c-6b5a49382716" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
"client_row_id": "LMS-8841"
}
]
}'
import os
import uuid
import requests
response = requests.post(
"https://api.dcycle.io/v2/own-workforce/trainings",
headers={
"x-api-key": os.environ["DCYCLE_API_KEY"],
"x-organization-id": os.environ["DCYCLE_ORG_ID"],
"Idempotency-Key": str(uuid.uuid4()), # keep it to retry this same batch
},
json={
"records": [
{
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
}
]
},
timeout=60,
)
response.raise_for_status()
print([item["training"]["id"] for item in response.json()["items"]])
{
"items": [
{
"source_row_index": 0,
"client_row_id": "LMS-8841",
"training": {
"id": "3b2a1908-7f6e-4d5c-8b4a-392817160504",
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
"created_at": "2026-10-19T09:12:44.031Z"
}
}
]
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Entity",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "LMS-8841",
"error_code": "REFERENCE_NOT_FOUND",
"error_params": { "field": "own_workforce_id", "value": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 1, "valid": 1 }
← Own Workforce API
Record the trainings your employees received: what, when and for how many hours. Each training belongs to an
employee, by the
Request-level errors:
id that Create Workforce Employees (v2)
answers. The request answers 201 Created with the trainings; nothing is calculated, so there is no job to follow.
Beta. Part of the bulk ingest API, currently in beta. The contract may still change before general availability.
curl -X POST "https://api.dcycle.io/v2/own-workforce/trainings" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Idempotency-Key: 5e4d3c2b-1a09-4f8e-9d7c-6b5a49382716" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
"client_row_id": "LMS-8841"
}
]
}'
import os
import uuid
import requests
response = requests.post(
"https://api.dcycle.io/v2/own-workforce/trainings",
headers={
"x-api-key": os.environ["DCYCLE_API_KEY"],
"x-organization-id": os.environ["DCYCLE_ORG_ID"],
"Idempotency-Key": str(uuid.uuid4()), # keep it to retry this same batch
},
json={
"records": [
{
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
}
]
},
timeout=60,
)
response.raise_for_status()
print([item["training"]["id"] for item in response.json()["items"]])
{
"items": [
{
"source_row_index": 0,
"client_row_id": "LMS-8841",
"training": {
"id": "3b2a1908-7f6e-4d5c-8b4a-392817160504",
"own_workforce_id": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817",
"description": "Forklift safety",
"type": "safety",
"start_date": "2026-03-04",
"end_date": "2026-03-05",
"hours": 12.5,
"created_at": "2026-10-19T09:12:44.031Z"
}
}
]
}
{
"type": "https://code.dcycle.io/api-reference/errors#BULK_RECORDS_REJECTED",
"title": "Unprocessable Entity",
"status": 422,
"code": "BULK_RECORDS_REJECTED",
"detail": "1 of the submitted records are invalid; nothing was written.",
"errors": [
{
"source_row_index": 0,
"client_row_id": "LMS-8841",
"error_code": "REFERENCE_NOT_FOUND",
"error_params": { "field": "own_workforce_id", "value": "6f5e4d3c-2b1a-4f09-8e7d-6c5b4a392817" }
}
],
"rejected": 1,
"request_id": "b2248a31-0f1b-4a7d-83ce-b29bd5977b4c"
}
{ "dry_run": true, "submitted": 1, "valid": 1 }
How it works
Every record is checked. If any is invalid the whole request is rejected with422 and nothing is written; the
answer lists every invalid record, so you can fix them all at once. Otherwise the trainings are created at once.
A training is not matched against the ones already stored: sending the same training twice creates it twice. To
retry a request safely, repeat it with the same Idempotency-Key.
Request
Headers
string
required
Your API key (see Authentication).
string
required
Your organization. Its employees, and those of the organizations under it that you can write to, can take
trainings; each training belongs to its employee’s organization.
string
required
1 to 255 characters, unique per batch. A retry with the same key and body answers the same trainings (with
Idempotent-Replayed: true) instead of creating them again; the same key with another body is
422 IDEMPOTENCY_KEY_REUSED, and while the first request is still being processed 409 IDEMPOTENCY_KEY_IN_PROGRESS.Query Parameters
boolean
default:"false"
Check only: the same
422 for invalid records, nothing written; 200 with
{"dry_run": true, "submitted": n, "valid": n} when every record is valid.Body Parameters
array[object]
required
The trainings to create, 1 to 1,000. A field not listed here is rejected (
SCHEMA_INVALID).Show record
Show record
uuid
required
The employee trained: an
id of Create Workforce Employees (v2)
or List Workforce Employees.string
required
What the training was, up to 255 characters.
string
required
Your category for the training, as free text, up to 255 characters (
safety, technical, languages…).date
required
First day of the training,
YYYY-MM-DD, from 1970 to next year.date
required
Last day of the training, on or after
start_date.number
required
Hours of training the employee received: over 0, with up to 1 decimal.
string
Your own reference for the record, up to 255 characters, echoed in errors and in the answer.
Response
201 Created with items: one per record, in the order sent, with its source_row_index, client_row_id and the
created training. Its id is the one Delete Workforce Trainings (v2)
takes.
Errors
Problem details. Per-record codes inerrors[].error_code of a 422 BULK_RECORDS_REJECTED:
error_code | Cause |
|---|---|
SCHEMA_INVALID | The record does not match the schema: a missing or unknown field (e.g. organization_id), an empty description or type, hours not over 0 or with more than 1 decimal, a date out of range, end_date before start_date… error_params.errors says where. |
REFERENCE_NOT_FOUND | own_workforce_id does not exist or is outside your organization’s perimeter (both answer the same). |
401 for a missing or invalid API key, 403 LOGGED_USER_NOT_MEMBER when the key’s user is not a
member of the organization, 422 REQUEST_VALIDATION_FAILED for a malformed body (no records, more than 1,000, no
Idempotency-Key), 422 IDEMPOTENCY_KEY_REUSED, 409 IDEMPOTENCY_KEY_IN_PROGRESS, and 429 beyond the
rate limits.
Limits
| Limit | Value |
|---|---|
| Records per request | 1 to 1,000 |
Related Endpoints
Delete Workforce Trainings (v2)
Delete trainings by id
List Workforce Employees
The employees, and their ids
List Workforce Trainings
The trainings stored
Was this page helpful?