curl --request POST \
--url https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"body": "<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>",
"fileIds": [
"RiHO4e0Ju3DS"
],
"userId": "RiHO4e0Ju3DS",
"userEmail": "jane@acme.com"
}
'import requests
url = "https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments"
payload = {
"body": "<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>",
"fileIds": ["RiHO4e0Ju3DS"],
"userId": "RiHO4e0Ju3DS",
"userEmail": "jane@acme.com"
}
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({
body: JSON.stringify('<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>'),
fileIds: ['RiHO4e0Ju3DS'],
userId: 'RiHO4e0Ju3DS',
userEmail: 'jane@acme.com'
})
};
fetch('https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments', 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.dock.us/{version}/workspace-plan-tasks/{id}/comments",
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([
'body' => '<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>',
'fileIds' => [
'RiHO4e0Ju3DS'
],
'userId' => 'RiHO4e0Ju3DS',
'userEmail' => 'jane@acme.com'
]),
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.dock.us/{version}/workspace-plan-tasks/{id}/comments"
payload := strings.NewReader("{\n \"body\": \"<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>\",\n \"fileIds\": [\n \"RiHO4e0Ju3DS\"\n ],\n \"userId\": \"RiHO4e0Ju3DS\",\n \"userEmail\": \"jane@acme.com\"\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.dock.us/{version}/workspace-plan-tasks/{id}/comments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"body\": \"<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>\",\n \"fileIds\": [\n \"RiHO4e0Ju3DS\"\n ],\n \"userId\": \"RiHO4e0Ju3DS\",\n \"userEmail\": \"jane@acme.com\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments")
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 \"body\": \"<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>\",\n \"fileIds\": [\n \"RiHO4e0Ju3DS\"\n ],\n \"userId\": \"RiHO4e0Ju3DS\",\n \"userEmail\": \"jane@acme.com\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"workspacePlanTaskComment": {
"id": "RiHO4e0Ju3DS",
"updatedAt": "2021-01-01T00:00:00.000Z",
"createdAt": "2021-01-01T00:00:00.000Z",
"object": "workspace-plan-task-comment",
"taskId": "RiHO4e0Ju3DS",
"body": "<p>Uploaded the <span style=\"font-weight:700\">signed</span> contract @Jane Doe</p>",
"author": {
"id": "RiHO4e0Ju3DS",
"updatedAt": "2021-01-01T00:00:00.000Z",
"createdAt": "2021-01-01T00:00:00.000Z",
"object": "user",
"url": "https://api.dock.us/v1/users/RiHO4e0Ju3DS",
"firstName": "John",
"lastName": "Doe",
"avatar": "https://dock.us/avatar.png",
"email": "john.doe@example.com",
"name": "John Doe"
},
"files": [
{
"id": "RiHO4e0Ju3DS",
"updatedAt": "2021-01-01T00:00:00.000Z",
"createdAt": "2021-01-01T00:00:00.000Z",
"object": "file",
"name": "contract.pdf",
"thumbnail": "https://storage.googleapis.com/dock-production-private/thumbnails/contract.png",
"size": 24576,
"url": "https://api.dock.us/v1/files/RiHO4e0Ju3DS",
"downloadUrl": "https://storage.googleapis.com/dock-production-private/signed-url",
"expiresAt": "2026-06-12T12:00:00.000Z",
"uploadStatus": "success",
"mimeType": "application/pdf"
}
]
}
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "The request could not be understood or was missing required parameters"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Access denied. You are not authorized to access this resource"
}
}{
"error": {
"code": "FORBIDDEN",
"message": "Access to this resource is restricted"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found"
}
}{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later"
}
}{
"error": {
"code": "INTERNAL_SERVER_ERROR",
"message": "The server has encountered a situation it does not know how to handle"
}
}Create a workspace plan task comment
Add a comment to a workspace plan task. The comment appears in the task’s comment thread and notifies the thread participants by email, the same as a comment added in Dock.
To attach files, upload each one first with Create a file (PUT the bytes to the returned upload URL), then pass the file IDs in fileIds (up to 5). Supported file types are listed on Create a file.
The comment is authored by the API key’s user unless userId or userEmail is provided. When both are provided, userId is used. An email that does not belong to an existing user creates a client user
curl --request POST \
--url https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"body": "<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>",
"fileIds": [
"RiHO4e0Ju3DS"
],
"userId": "RiHO4e0Ju3DS",
"userEmail": "jane@acme.com"
}
'import requests
url = "https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments"
payload = {
"body": "<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>",
"fileIds": ["RiHO4e0Ju3DS"],
"userId": "RiHO4e0Ju3DS",
"userEmail": "jane@acme.com"
}
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({
body: JSON.stringify('<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>'),
fileIds: ['RiHO4e0Ju3DS'],
userId: 'RiHO4e0Ju3DS',
userEmail: 'jane@acme.com'
})
};
fetch('https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments', 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.dock.us/{version}/workspace-plan-tasks/{id}/comments",
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([
'body' => '<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>',
'fileIds' => [
'RiHO4e0Ju3DS'
],
'userId' => 'RiHO4e0Ju3DS',
'userEmail' => 'jane@acme.com'
]),
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.dock.us/{version}/workspace-plan-tasks/{id}/comments"
payload := strings.NewReader("{\n \"body\": \"<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>\",\n \"fileIds\": [\n \"RiHO4e0Ju3DS\"\n ],\n \"userId\": \"RiHO4e0Ju3DS\",\n \"userEmail\": \"jane@acme.com\"\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.dock.us/{version}/workspace-plan-tasks/{id}/comments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"body\": \"<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>\",\n \"fileIds\": [\n \"RiHO4e0Ju3DS\"\n ],\n \"userId\": \"RiHO4e0Ju3DS\",\n \"userEmail\": \"jane@acme.com\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.dock.us/{version}/workspace-plan-tasks/{id}/comments")
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 \"body\": \"<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>\",\n \"fileIds\": [\n \"RiHO4e0Ju3DS\"\n ],\n \"userId\": \"RiHO4e0Ju3DS\",\n \"userEmail\": \"jane@acme.com\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"workspacePlanTaskComment": {
"id": "RiHO4e0Ju3DS",
"updatedAt": "2021-01-01T00:00:00.000Z",
"createdAt": "2021-01-01T00:00:00.000Z",
"object": "workspace-plan-task-comment",
"taskId": "RiHO4e0Ju3DS",
"body": "<p>Uploaded the <span style=\"font-weight:700\">signed</span> contract @Jane Doe</p>",
"author": {
"id": "RiHO4e0Ju3DS",
"updatedAt": "2021-01-01T00:00:00.000Z",
"createdAt": "2021-01-01T00:00:00.000Z",
"object": "user",
"url": "https://api.dock.us/v1/users/RiHO4e0Ju3DS",
"firstName": "John",
"lastName": "Doe",
"avatar": "https://dock.us/avatar.png",
"email": "john.doe@example.com",
"name": "John Doe"
},
"files": [
{
"id": "RiHO4e0Ju3DS",
"updatedAt": "2021-01-01T00:00:00.000Z",
"createdAt": "2021-01-01T00:00:00.000Z",
"object": "file",
"name": "contract.pdf",
"thumbnail": "https://storage.googleapis.com/dock-production-private/thumbnails/contract.png",
"size": 24576,
"url": "https://api.dock.us/v1/files/RiHO4e0Ju3DS",
"downloadUrl": "https://storage.googleapis.com/dock-production-private/signed-url",
"expiresAt": "2026-06-12T12:00:00.000Z",
"uploadStatus": "success",
"mimeType": "application/pdf"
}
]
}
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "The request could not be understood or was missing required parameters"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Access denied. You are not authorized to access this resource"
}
}{
"error": {
"code": "FORBIDDEN",
"message": "Access to this resource is restricted"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "The requested resource could not be found"
}
}{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later"
}
}{
"error": {
"code": "INTERNAL_SERVER_ERROR",
"message": "The server has encountered a situation it does not know how to handle"
}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Unique identifier
"RiHO4e0Ju3DS"
Query Parameters
Select the comment properties to return. Comments return only id and object unless other properties are requested. Request author.<property> (for example author.email) to include the author, and files.<property> (for example files.downloadUrl) to include the attached files; both nested objects always carry their id, object and url
taskId, body, author.createdAt, author.updatedAt, author.firstName, author.lastName, author.avatar, author.email, author.name, files.name, files.thumbnail, files.size, files.downloadUrl, files.expiresAt, files.uploadStatus, files.mimeType, createdAt, updatedAt Body
Comment text as HTML rich text, the same format body is returned in. Supports paragraphs (<p>, <br>), <strong>/<b>, <em>/<i>, <u>, text color (style="color: …"), links and <ul>/<ol> lists. Other blocks such as tables and code are kept as plain paragraphs. Content outside a <p> (for example Asana's <body>One\nTwo</body> or plain text) is split into one paragraph per line, and blank lines are kept. Inside a <p>, newlines are ordinary whitespace. Required unless fileIds is provided
100000"<p>Uploaded the <strong>signed</strong> contract</p><ul><li>Pages 1–3 initialed</li></ul>"
IDs of files uploaded with Create a file to attach to the comment
5ID of the user to author the comment as. Takes precedence over userEmail
"RiHO4e0Ju3DS"
Email of the user to author the comment as. Creates a client user when no user has this email
"jane@acme.com"
Response
The created workspace plan task comment
Show child attributes
Show child attributes