Upload Workforce Trainings CSV
const options = {
method: 'POST',
headers: {
'x-api-key': '<x-api-key>',
'x-organization-id': '<x-organization-id>',
'Content-Type': 'application/json'
},
body: JSON.stringify({file_name: '<string>'})
};
fetch('https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv"
payload = { "file_name": "<string>" }
headers = {
"x-api-key": "<x-api-key>",
"x-organization-id": "<x-organization-id>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)curl --request POST \
--url https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--header 'x-organization-id: <x-organization-id>' \
--data '
{
"file_name": "<string>"
}
'{
"upload_url": "<string>",
"file_id": "<string>",
"destination_file_key": "<string>",
"file_name": "<string>",
"organization_id": "<string>",
"message": "<string>"
}Upload Workforce Trainings CSV
Request a presigned S3 URL to upload a trainings CSV for asynchronous ingestion
POST
/
v1
/
own_workforce_trainings
/
bulk
/
csv
Upload Workforce Trainings CSV
const options = {
method: 'POST',
headers: {
'x-api-key': '<x-api-key>',
'x-organization-id': '<x-organization-id>',
'Content-Type': 'application/json'
},
body: JSON.stringify({file_name: '<string>'})
};
fetch('https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv"
payload = { "file_name": "<string>" }
headers = {
"x-api-key": "<x-api-key>",
"x-organization-id": "<x-organization-id>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)curl --request POST \
--url https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--header 'x-organization-id: <x-organization-id>' \
--data '
{
"file_name": "<string>"
}
'{
"upload_url": "<string>",
"file_id": "<string>",
"destination_file_key": "<string>",
"file_name": "<string>",
"organization_id": "<string>",
"message": "<string>"
}← Own Workforce API
Mint a presigned S3 URL and upload a trainings CSV to it. The call ingests nothing by itself: it returns a URL, and the file is parsed asynchronously once it lands.
Trainings attach to employees by
Prefer the Imports API for new integrations — template
own_workforce_trainings, documented in Own Workforce Import Templates. It validates each row before submission and reports per-row errors; this path has no validation step, so a malformed file fails after the upload rather than at request time.external_employee_id, so the employees must already exist before you upload their trainings.
How it works
1
Ask for a URL
POST here with the file name. You get back upload_url, a file_id and the destination key.2
PUT the file
Upload the CSV bytes to
upload_url. That request goes to S3 and carries no Dcycle headers.3
Wait for ingestion
Poll List Workforce Trainings Paginated filtering on the
file_id you were given, and read each row’s status.Request
Headers
string
required
Your API key for authenticationExample:
sk_live_1234567890abcdefstring
required
Your organization UUIDExample:
a8315ef3-dd50-43f8-b7ce-d839e68d51faBody
string
required
Name of the file you are about to uploadExample:
trainings_2026.csvResponse
201 Created.
string
Presigned S3 URL.
PUT the file bytes here. Short-lived — request it immediately before uploading.string
Id of the file record, to follow ingestion and later to delete everything from this upload
string
Object key the file will be stored under
string
Echo of the name you sent
string
Organization the upload is attributed to
string
Human-readable confirmation
Example
curl -X POST "https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv" \
-H "x-api-key: ${DCYCLE_API_KEY}" \
-H "x-organization-id: ${DCYCLE_ORG_ID}" \
-H "Content-Type: application/json" \
-d '{"file_name": "trainings_2026.csv"}'
curl -X PUT "${UPLOAD_URL}" --upload-file trainings_2026.csv
import os
import requests
headers = {
"x-api-key": os.getenv("DCYCLE_API_KEY"),
"x-organization-id": os.getenv("DCYCLE_ORG_ID"),
}
presigned = requests.post(
"https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv",
headers=headers,
json={"file_name": "trainings_2026.csv"},
).json()
with open("trainings_2026.csv", "rb") as handle:
requests.put(presigned["upload_url"], data=handle).raise_for_status()
print("ingesting under file_id", presigned["file_id"])
const axios = require('axios');
const fs = require('fs');
const headers = {
'x-api-key': process.env.DCYCLE_API_KEY,
'x-organization-id': process.env.DCYCLE_ORG_ID
};
axios.post('https://api.dcycle.io/v1/own_workforce_trainings/bulk/csv',
{ file_name: 'trainings_2026.csv' }, { headers })
.then(({ data }) =>
axios.put(data.upload_url, fs.createReadStream('trainings_2026.csv'))
.then(() => console.log('ingesting under file_id', data.file_id))
)
.catch(error => console.error(error));
Successful Response
{
"upload_url": "https://dcycle-uploads.s3.eu-west-1.amazonaws.com/...",
"file_id": "aa11bb22-cc33-4d44-8e55-ff6677889900",
"destination_file_key": "dcycle/a8315ef3-dd50-43f8-b7ce-d839e68d51fa/own_workforce_trainings/trainings_2026.csv",
"file_name": "trainings_2026.csv",
"organization_id": "a8315ef3-dd50-43f8-b7ce-d839e68d51fa",
"message": "Presigned URL created successfully"
}
Common Errors
401 Unauthorized
Cause: the key is invalid, or it does not belong to the organization inx-organization-id — the two are looked up as a pair. A request carrying no credentials at all answers AUTH_REQUIRED instead.
{
"detail": "Invalid API key for organization",
"code": "INVALID_API_KEY"
}
403 Forbidden
Cause: the key’s owner is not an enabled member of the organization, or their role cannot write.{
"detail": "Logged User is not Member of Organization",
"code": "LOGGED_USER_NOT_MEMBER"
}
422 Unprocessable Entity
Cause:file_name missing from the body.
{
"detail": [
{
"type": "missing",
"loc": ["body", "file_name"],
"msg": "Field required"
}
]
}
Related Endpoints
Own workforce import templates
The seven columns this CSV must carry
Create an import session
The recommended write path
Was this page helpful?