curl --request POST \
--url https://api.parley.so/v1/files \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"uploadId": "<string>",
"projectId": "<string>",
"accountId": "<string>",
"contactId": "<string>",
"intakeId": "<string>",
"library": true,
"folderId": "<string>"
}
'import requests
url = "https://api.parley.so/v1/files"
payload = {
"uploadId": "<string>",
"projectId": "<string>",
"accountId": "<string>",
"contactId": "<string>",
"intakeId": "<string>",
"library": True,
"folderId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
uploadId: '<string>',
projectId: '<string>',
accountId: '<string>',
contactId: '<string>',
intakeId: '<string>',
library: true,
folderId: '<string>'
})
};
fetch('https://api.parley.so/v1/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.parley.so/v1/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 => json_encode([
'uploadId' => '<string>',
'projectId' => '<string>',
'accountId' => '<string>',
'contactId' => '<string>',
'intakeId' => '<string>',
'library' => true,
'folderId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.parley.so/v1/files"
payload := strings.NewReader("{\n \"uploadId\": \"<string>\",\n \"projectId\": \"<string>\",\n \"accountId\": \"<string>\",\n \"contactId\": \"<string>\",\n \"intakeId\": \"<string>\",\n \"library\": true,\n \"folderId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
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.parley.so/v1/files")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"uploadId\": \"<string>\",\n \"projectId\": \"<string>\",\n \"accountId\": \"<string>\",\n \"contactId\": \"<string>\",\n \"intakeId\": \"<string>\",\n \"library\": true,\n \"folderId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parley.so/v1/files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"uploadId\": \"<string>\",\n \"projectId\": \"<string>\",\n \"accountId\": \"<string>\",\n \"contactId\": \"<string>\",\n \"intakeId\": \"<string>\",\n \"library\": true,\n \"folderId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"type": "file",
"id": "cmf2y1a2b0003abcd",
"name": "engagement-letter.pdf",
"location": {
"type": "project",
"id": "cmf2x8k0q0001abcd",
"name": "Acme Corp H-1B petition"
},
"folder": {
"type": "folder",
"id": "cmf2y0z9x0004abcd",
"name": "Evidence"
},
"mediaType": "application/pdf",
"status": "ready",
"createdAt": "2026-10-03T12:00:00.000Z",
"updatedAt": "2026-10-03T12:01:30.000Z"
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "The request is invalid.",
"details": {
"issues": [
{
"path": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing or invalid credentials."
}
}{
"error": {
"code": "FORBIDDEN",
"message": "You don't have permission to do this."
}
}{
"error": {
"code": "UPLOAD_ALREADY_ADDED",
"message": "This upload was already added somewhere else."
}
}{
"error": {
"code": "TOO_MANY_REQUESTS",
"message": "Too many requests."
}
}Add a file
Add an uploaded file to a project, account, contact, intake, or the Library: pass exactly one of projectId, accountId, contactId, intakeId, or library. Create the upload with POST /uploads and PUT the file’s bytes to its url first. Parley then extracts the file’s text in the background, and the file can be read once its status is ready. Adding the same upload again returns the same file; adding it anywhere else returns 409 UPLOAD_ALREADY_ADDED.
curl --request POST \
--url https://api.parley.so/v1/files \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"uploadId": "<string>",
"projectId": "<string>",
"accountId": "<string>",
"contactId": "<string>",
"intakeId": "<string>",
"library": true,
"folderId": "<string>"
}
'import requests
url = "https://api.parley.so/v1/files"
payload = {
"uploadId": "<string>",
"projectId": "<string>",
"accountId": "<string>",
"contactId": "<string>",
"intakeId": "<string>",
"library": True,
"folderId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
uploadId: '<string>',
projectId: '<string>',
accountId: '<string>',
contactId: '<string>',
intakeId: '<string>',
library: true,
folderId: '<string>'
})
};
fetch('https://api.parley.so/v1/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.parley.so/v1/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 => json_encode([
'uploadId' => '<string>',
'projectId' => '<string>',
'accountId' => '<string>',
'contactId' => '<string>',
'intakeId' => '<string>',
'library' => true,
'folderId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.parley.so/v1/files"
payload := strings.NewReader("{\n \"uploadId\": \"<string>\",\n \"projectId\": \"<string>\",\n \"accountId\": \"<string>\",\n \"contactId\": \"<string>\",\n \"intakeId\": \"<string>\",\n \"library\": true,\n \"folderId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
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.parley.so/v1/files")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"uploadId\": \"<string>\",\n \"projectId\": \"<string>\",\n \"accountId\": \"<string>\",\n \"contactId\": \"<string>\",\n \"intakeId\": \"<string>\",\n \"library\": true,\n \"folderId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.parley.so/v1/files")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"uploadId\": \"<string>\",\n \"projectId\": \"<string>\",\n \"accountId\": \"<string>\",\n \"contactId\": \"<string>\",\n \"intakeId\": \"<string>\",\n \"library\": true,\n \"folderId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"type": "file",
"id": "cmf2y1a2b0003abcd",
"name": "engagement-letter.pdf",
"location": {
"type": "project",
"id": "cmf2x8k0q0001abcd",
"name": "Acme Corp H-1B petition"
},
"folder": {
"type": "folder",
"id": "cmf2y0z9x0004abcd",
"name": "Evidence"
},
"mediaType": "application/pdf",
"status": "ready",
"createdAt": "2026-10-03T12:00:00.000Z",
"updatedAt": "2026-10-03T12:01:30.000Z"
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "The request is invalid.",
"details": {
"issues": [
{
"path": "<string>",
"message": "<string>"
}
]
}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Missing or invalid credentials."
}
}{
"error": {
"code": "FORBIDDEN",
"message": "You don't have permission to do this."
}
}{
"error": {
"code": "UPLOAD_ALREADY_ADDED",
"message": "This upload was already added somewhere else."
}
}{
"error": {
"code": "TOO_MANY_REQUESTS",
"message": "Too many requests."
}
}Authorizations
A Parley API key.
Body
The id of an upload, once its bytes have been PUT to its url, holding the file to add. It keeps its file name. Adding the same upload again returns the same file.
1Add it to this project's files. Pass exactly one of projectId, accountId, contactId, intakeId, or library.
1Add it to this account's files. Pass exactly one of projectId, accountId, contactId, intakeId, or library.
1Add it to this contact's files. Pass exactly one of projectId, accountId, contactId, intakeId, or library.
1Add it to this intake's files. Pass exactly one of projectId, accountId, contactId, intakeId, or library.
1true for the organization's Library. Pass exactly one of projectId, accountId, contactId, intakeId, or library.
Put it inside this folder. Omit for the top level.
1Response
Created.
- Option 1
- Option 2
A file or a folder, told apart by type.
The file or folder ID.
1The name, including any file extension.
Whose files these are: a project's, an account's, a contact's, or an intake's, or the organization's Library.
- Option 1
- Option 2
- Option 3
Show child attributes
Show child attributes
The folder it is in, or null at the top level.
Show child attributes
Show child attributes
When it was added.
When it was last updated, including processing, renames, and moves.
The file's media type, such as application/pdf, from its extension, or null when the extension isn't recognized.
Whether Parley has extracted the file's text: pending (queued), processing, ready (its text can be read), or failed (download it instead).
pending, processing, ready, failed Was this page helpful?
