curl --request POST \
--url https://api.zivio.net/api/v4/bids/{id}/scores \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'zivio-tenant-id: <api-key>' \
--data '
{
"scores": [
{
"criterion_id": 11,
"criterion": "Technical Approach",
"score": 8,
"notes": "Strong discovery phase and a credible test strategy."
}
],
"criterion_id": 123,
"criterion": "<string>",
"score": 123,
"notes": "<string>"
}
'import requests
url = "https://api.zivio.net/api/v4/bids/{id}/scores"
payload = {
"scores": [
{
"criterion_id": 11,
"criterion": "Technical Approach",
"score": 8,
"notes": "Strong discovery phase and a credible test strategy."
}
],
"criterion_id": 123,
"criterion": "<string>",
"score": 123,
"notes": "<string>"
}
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({
scores: [
{
criterion_id: 11,
criterion: 'Technical Approach',
score: 8,
notes: 'Strong discovery phase and a credible test strategy.'
}
],
criterion_id: 123,
criterion: '<string>',
score: 123,
notes: '<string>'
})
};
fetch('https://api.zivio.net/api/v4/bids/{id}/scores', 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/bids/{id}/scores",
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([
'scores' => [
[
'criterion_id' => 11,
'criterion' => 'Technical Approach',
'score' => 8,
'notes' => 'Strong discovery phase and a credible test strategy.'
]
],
'criterion_id' => 123,
'criterion' => '<string>',
'score' => 123,
'notes' => '<string>'
]),
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/bids/{id}/scores"
payload := strings.NewReader("{\n \"scores\": [\n {\n \"criterion_id\": 11,\n \"criterion\": \"Technical Approach\",\n \"score\": 8,\n \"notes\": \"Strong discovery phase and a credible test strategy.\"\n }\n ],\n \"criterion_id\": 123,\n \"criterion\": \"<string>\",\n \"score\": 123,\n \"notes\": \"<string>\"\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/bids/{id}/scores")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"scores\": [\n {\n \"criterion_id\": 11,\n \"criterion\": \"Technical Approach\",\n \"score\": 8,\n \"notes\": \"Strong discovery phase and a credible test strategy.\"\n }\n ],\n \"criterion_id\": 123,\n \"criterion\": \"<string>\",\n \"score\": 123,\n \"notes\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/bids/{id}/scores")
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 \"scores\": [\n {\n \"criterion_id\": 11,\n \"criterion\": \"Technical Approach\",\n \"score\": 8,\n \"notes\": \"Strong discovery phase and a credible test strategy.\"\n }\n ],\n \"criterion_id\": 123,\n \"criterion\": \"<string>\",\n \"score\": 123,\n \"notes\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "Recorded 2 scores for proposal 9",
"project_id": 123,
"proposal": {
"bid_id": 9,
"total_score_percentage": 84,
"scores": [
{
"criterion_id": 11,
"criterion": "Technical Approach",
"score": 8,
"notes": "Strong discovery phase.",
"weighted_score": 80
}
],
"unscored_criteria": []
}
}{
"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": "bid_evaluations:write",
"provided_scopes": [
"welcome:read"
]
}{
"error": "validation_failed",
"errors": [
"score must be a whole number between 0 and 10 (got \"eight\")"
],
"available_criteria": [
{
"id": 11,
"description": "Technical Approach"
}
]
}Score a proposal against the project's quality criteria (create or update an evaluation)
Records reviewer scores out of 10, each with justification notes, against the project’s evaluation criteria — mirroring the web UI’s evaluation form. Send several criteria in one call via scores, or a single criterion at the top level. Re-scoring a criterion overwrites the previous score and notes, so the same call creates or updates an evaluation. Identify each criterion by criterion_id (from GET /projects//evaluations) or by its exact criterion name. Notes are required. The whole batch is applied together, and the project’s proposal scores are recalculated afterwards, exactly as the UI does.
curl --request POST \
--url https://api.zivio.net/api/v4/bids/{id}/scores \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'zivio-tenant-id: <api-key>' \
--data '
{
"scores": [
{
"criterion_id": 11,
"criterion": "Technical Approach",
"score": 8,
"notes": "Strong discovery phase and a credible test strategy."
}
],
"criterion_id": 123,
"criterion": "<string>",
"score": 123,
"notes": "<string>"
}
'import requests
url = "https://api.zivio.net/api/v4/bids/{id}/scores"
payload = {
"scores": [
{
"criterion_id": 11,
"criterion": "Technical Approach",
"score": 8,
"notes": "Strong discovery phase and a credible test strategy."
}
],
"criterion_id": 123,
"criterion": "<string>",
"score": 123,
"notes": "<string>"
}
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({
scores: [
{
criterion_id: 11,
criterion: 'Technical Approach',
score: 8,
notes: 'Strong discovery phase and a credible test strategy.'
}
],
criterion_id: 123,
criterion: '<string>',
score: 123,
notes: '<string>'
})
};
fetch('https://api.zivio.net/api/v4/bids/{id}/scores', 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/bids/{id}/scores",
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([
'scores' => [
[
'criterion_id' => 11,
'criterion' => 'Technical Approach',
'score' => 8,
'notes' => 'Strong discovery phase and a credible test strategy.'
]
],
'criterion_id' => 123,
'criterion' => '<string>',
'score' => 123,
'notes' => '<string>'
]),
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/bids/{id}/scores"
payload := strings.NewReader("{\n \"scores\": [\n {\n \"criterion_id\": 11,\n \"criterion\": \"Technical Approach\",\n \"score\": 8,\n \"notes\": \"Strong discovery phase and a credible test strategy.\"\n }\n ],\n \"criterion_id\": 123,\n \"criterion\": \"<string>\",\n \"score\": 123,\n \"notes\": \"<string>\"\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/bids/{id}/scores")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"scores\": [\n {\n \"criterion_id\": 11,\n \"criterion\": \"Technical Approach\",\n \"score\": 8,\n \"notes\": \"Strong discovery phase and a credible test strategy.\"\n }\n ],\n \"criterion_id\": 123,\n \"criterion\": \"<string>\",\n \"score\": 123,\n \"notes\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/bids/{id}/scores")
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 \"scores\": [\n {\n \"criterion_id\": 11,\n \"criterion\": \"Technical Approach\",\n \"score\": 8,\n \"notes\": \"Strong discovery phase and a credible test strategy.\"\n }\n ],\n \"criterion_id\": 123,\n \"criterion\": \"<string>\",\n \"score\": 123,\n \"notes\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"message": "Recorded 2 scores for proposal 9",
"project_id": 123,
"proposal": {
"bid_id": 9,
"total_score_percentage": 84,
"scores": [
{
"criterion_id": 11,
"criterion": "Technical Approach",
"score": 8,
"notes": "Strong discovery phase.",
"weighted_score": 80
}
],
"unscored_criteria": []
}
}{
"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": "bid_evaluations:write",
"provided_scopes": [
"welcome:read"
]
}{
"error": "validation_failed",
"errors": [
"score must be a whole number between 0 and 10 (got \"eight\")"
],
"available_criteria": [
{
"id": 11,
"description": "Technical Approach"
}
]
}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
Bid ID
Body
One entry per criterion: { criterion_id or criterion, score (0-10), notes }.
Show child attributes
Show child attributes
Single-score form: the criterion id.
Single-score form: the criterion name.
Single-score form: whole number from 0 to 10.
Single-score form: justification (required).
Response
Scores recorded; the proposal's recalculated scorecard is returned
The response is of type object.

