curl --request POST \
--url https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'zivio-tenant-id: <api-key>' \
--data '
{
"duplicate_of": 3
}
'import requests
url = "https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate"
payload = { "duplicate_of": 3 }
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({duplicate_of: 3})
};
fetch('https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate', 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}/link_duplicate",
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([
'duplicate_of' => 3
]),
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}/link_duplicate"
payload := strings.NewReader("{\n \"duplicate_of\": 3\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}/link_duplicate")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"duplicate_of\": 3\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate")
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 \"duplicate_of\": 3\n}"
response = http.request(request)
puts response.read_body{
"public_id": 2,
"ref": "Q-2",
"status": "responded",
"duplicate_of": "Q-3",
"response": "Google Analytics 4, migrated in 2024."
}{
"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-3 on project 123 to mark as duplicate of"
}{
"error": "validation_failed",
"errors": [
"Duplicate of cannot create a chain — duplicates can only point at a canonical question"
]
}Mark a supplier question as a duplicate of another question
Marks the addressed question as a duplicate of the canonical question given in duplicate_of (both are per-project public “Q-N” numbers). The duplicate immediately inherits the canonical’s response and approval state, and future responses to the canonical propagate to it — so the asking supplier still gets their answer. Duplicates cannot chain: duplicate_of must reference a canonical (non-duplicate) question on the same project.
curl --request POST \
--url https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'zivio-tenant-id: <api-key>' \
--data '
{
"duplicate_of": 3
}
'import requests
url = "https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate"
payload = { "duplicate_of": 3 }
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({duplicate_of: 3})
};
fetch('https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate', 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}/link_duplicate",
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([
'duplicate_of' => 3
]),
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}/link_duplicate"
payload := strings.NewReader("{\n \"duplicate_of\": 3\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}/link_duplicate")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"duplicate_of\": 3\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/projects/{id}/questions/{question_id}/link_duplicate")
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 \"duplicate_of\": 3\n}"
response = http.request(request)
puts response.read_body{
"public_id": 2,
"ref": "Q-2",
"status": "responded",
"duplicate_of": "Q-3",
"response": "Google Analytics 4, migrated in 2024."
}{
"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-3 on project 123 to mark as duplicate of"
}{
"error": "validation_failed",
"errors": [
"Duplicate of cannot create a chain — duplicates can only point at a canonical question"
]
}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
Public question number of the DUPLICATE (the N in "Q-N").
Body
Public question number of the CANONICAL question this one duplicates.
3
Response
The question, now linked and carrying any inherited response/approval state
The response is of type object.

