curl --request POST \
--url https://api.getkroo.com/api/v3/schedule_files \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'name=October Baseline' \
--form file='@example-file' \
--form file_type=xer \
--form is_baseline=false \
--form customer_project_id=123import requests
url = "https://api.getkroo.com/api/v3/schedule_files"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"name": "October Baseline",
"file_type": "xer",
"is_baseline": "false",
"customer_project_id": "123"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('name', 'October Baseline');
form.append('file', '<string>');
form.append('file_type', 'xer');
form.append('is_baseline', 'false');
form.append('customer_project_id', '123');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.getkroo.com/api/v3/schedule_files', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.getkroo.com/api/v3/schedule_files",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.getkroo.com/api/v3/schedule_files"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.getkroo.com/api/v3/schedule_files")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getkroo.com/api/v3/schedule_files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": 482,
"name": "October 2026 Baseline",
"is_baseline": false,
"company_id": 1042,
"customer_project": {
"id": 123,
"name": "<string>",
"source": "<string>",
"customer_project_id": "<string>"
},
"created_at": "2026-04-27T15:30:00Z",
"file_type": "xer",
"partner_token_id": 123
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}Upload a schedule file
Uploads a schedule file (P6 XER/XML, Phoenix PPX, or Microsoft Project MPP) and enqueues a sync job to parse and ingest it.
Required scope: write:schedule_files
Constraints:
filemust be a multipart/form-data upload.file_typemust be one ofxer,xml,ppx,mpp.- Within the same partner family (XER/XML share a family; PPX and MPP
are each their own), the most recent file’s
file_typecannot change between uploads. Switching formats inside a partner returns 422file_type_mismatch. PPX after XER is allowed because they belong to different partners. customer_project_id, if provided, must reference a customer project owned by the authenticated company.
422 error codes:
invalid_request— missing required parameter (name,file, orfile_type) orfileis not a multipart upload.file_type_mismatch— the most recent file in the same partner family uses a differentfile_type.validation_error— the underlying record failed model-level validation (including unknownfile_typevalues).
curl --request POST \
--url https://api.getkroo.com/api/v3/schedule_files \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form 'name=October Baseline' \
--form file='@example-file' \
--form file_type=xer \
--form is_baseline=false \
--form customer_project_id=123import requests
url = "https://api.getkroo.com/api/v3/schedule_files"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"name": "October Baseline",
"file_type": "xer",
"is_baseline": "false",
"customer_project_id": "123"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('name', 'October Baseline');
form.append('file', '<string>');
form.append('file_type', 'xer');
form.append('is_baseline', 'false');
form.append('customer_project_id', '123');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.getkroo.com/api/v3/schedule_files', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.getkroo.com/api/v3/schedule_files",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.getkroo.com/api/v3/schedule_files"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.getkroo.com/api/v3/schedule_files")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getkroo.com/api/v3/schedule_files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nOctober Baseline\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file_type\"\r\n\r\nxer\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"is_baseline\"\r\n\r\nfalse\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"customer_project_id\"\r\n\r\n123\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": 482,
"name": "October 2026 Baseline",
"is_baseline": false,
"company_id": 1042,
"customer_project": {
"id": 123,
"name": "<string>",
"source": "<string>",
"customer_project_id": "<string>"
},
"created_at": "2026-04-27T15:30:00Z",
"file_type": "xer",
"partner_token_id": 123
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}{
"error": "<string>",
"error_description": "<string>"
}Authorizations
Bearer token obtained from POST /oauth/token. Send as Authorization: Bearer <token>. Tokens expire after 1 hour; refresh by requesting a new one with the same client credentials.
Body
"October Baseline"
The schedule file to upload.
xer, xml, ppx, mpp "xer"
Optional. Associate the file with a customer project owned by the authenticated company.
Response
File uploaded; sync job enqueued
Unique identifier for the schedule file.
482
Human-readable name supplied when the file was uploaded.
"October 2026 Baseline"
True if the file was marked as a baseline at upload time; baselines are preserved for variance reporting.
false
ID of the company that owns this file. Always equal to the authenticated client's company.
1042
Project association if one was provided on upload. null for unassociated files.
Show child attributes
Show child attributes
ISO 8601 timestamp of when the upload was accepted.
"2026-04-27T15:30:00Z"
Format the file was uploaded as, which also determines the scheduling integration it belongs to.
xer, xml, ppx, mpp "xer"
The scheduling integration the file was uploaded under. Null for files uploaded before that link existed, or whose integration was disconnected.
Was this page helpful?