curl --request POST \
--url https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'zivio-tenant-id: <api-key>' \
--data '
{
"response": "Yes, the CMS licence cost is included in the project budget.",
"visibility": "shared",
"job_question_category_id": 123
}
'import requests
url = "https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer"
payload = {
"response": "Yes, the CMS licence cost is included in the project budget.",
"visibility": "shared",
"job_question_category_id": 123
}
headers = {
"Authorization": "Bearer <token>",
"zivio-tenant-id": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
'zivio-tenant-id': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
response: 'Yes, the CMS licence cost is included in the project budget.',
visibility: 'shared',
job_question_category_id: 123
})
};
fetch('https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer', 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.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer",
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([
'response' => 'Yes, the CMS licence cost is included in the project budget.',
'visibility' => 'shared',
'job_question_category_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"zivio-tenant-id: <api-key>"
],
]);
$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.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer"
payload := strings.NewReader("{\n \"response\": \"Yes, the CMS licence cost is included in the project budget.\",\n \"visibility\": \"shared\",\n \"job_question_category_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("zivio-tenant-id", "<api-key>")
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.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"response\": \"Yes, the CMS licence cost is included in the project budget.\",\n \"visibility\": \"shared\",\n \"job_question_category_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["zivio-tenant-id"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"response\": \"Yes, the CMS licence cost is included in the project budget.\",\n \"visibility\": \"shared\",\n \"job_question_category_id\": 123\n}"
response = http.request(request)
puts response.read_body{
"public_id": 4,
"ref": "Q-4",
"status": "responded",
"visibility": "secret",
"response": "Yes, the CMS licence cost is included in the project budget."
}{
"error": "invalid_token",
"error_description": "The access token provided is expired, revoked, malformed, or invalid for other reasons"
}{
"error": "insufficient_scope",
"error_description": "The request requires higher privileges than provided by the access token",
"required_scope": "project_questions:write",
"provided_scopes": [
"welcome:read"
]
}{
"message": "No question Q-4 on project 123"
}{
"error": "validation_failed",
"errors": [
"Response can't be blank"
]
}Answer a supplier clarification question on a project
Records a response to a pending question, mirroring the web UI Q&A flow. The answer then awaits approval (responded) before suppliers can see it — unless the organisation’s job rule skips Q&A approval, in which case answering approves and publishes in one step. Approvers answering directly may also set visibility. question_id is the per-project public question number (the “Q-N” value from GET /projects//questions).
curl --request POST \
--url https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'zivio-tenant-id: <api-key>' \
--data '
{
"response": "Yes, the CMS licence cost is included in the project budget.",
"visibility": "shared",
"job_question_category_id": 123
}
'import requests
url = "https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer"
payload = {
"response": "Yes, the CMS licence cost is included in the project budget.",
"visibility": "shared",
"job_question_category_id": 123
}
headers = {
"Authorization": "Bearer <token>",
"zivio-tenant-id": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
Authorization: 'Bearer <token>',
'zivio-tenant-id': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
response: 'Yes, the CMS licence cost is included in the project budget.',
visibility: 'shared',
job_question_category_id: 123
})
};
fetch('https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer', 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.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer",
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([
'response' => 'Yes, the CMS licence cost is included in the project budget.',
'visibility' => 'shared',
'job_question_category_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"zivio-tenant-id: <api-key>"
],
]);
$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.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer"
payload := strings.NewReader("{\n \"response\": \"Yes, the CMS licence cost is included in the project budget.\",\n \"visibility\": \"shared\",\n \"job_question_category_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("zivio-tenant-id", "<api-key>")
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.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"response\": \"Yes, the CMS licence cost is included in the project budget.\",\n \"visibility\": \"shared\",\n \"job_question_category_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/answer")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["zivio-tenant-id"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"response\": \"Yes, the CMS licence cost is included in the project budget.\",\n \"visibility\": \"shared\",\n \"job_question_category_id\": 123\n}"
response = http.request(request)
puts response.read_body{
"public_id": 4,
"ref": "Q-4",
"status": "responded",
"visibility": "secret",
"response": "Yes, the CMS licence cost is included in the project budget."
}{
"error": "invalid_token",
"error_description": "The access token provided is expired, revoked, malformed, or invalid for other reasons"
}{
"error": "insufficient_scope",
"error_description": "The request requires higher privileges than provided by the access token",
"required_scope": "project_questions:write",
"provided_scopes": [
"welcome:read"
]
}{
"message": "No question Q-4 on project 123"
}{
"error": "validation_failed",
"errors": [
"Response can't be blank"
]
}Authorizations
OAuth 2.0 client credentials. The access token from POST /oauth/token is sent as a bearer token. Request only the scopes you need.
Your Zivio organisation identifier. The regional API endpoints serve every Zivio organisation, so each request must identify yours.
Path Parameters
Project ID
Per-project public question number (the N in "Q-N").
Body
The answer to the supplier's question.
"Yes, the CMS licence cost is included in the project budget."
Only honoured for users who can approve Q&A: secret = only the asking supplier sees the answer; shared = all invited suppliers see it once approved.
secret, shared "shared"
Optional question category id.
Response
The question with its recorded response and resulting status
The response is of type object.

