curl --request POST \
--url https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form file=@example-file \
--form 'notes=<string>' \
--form hit_policy=first \
--form 'sheet=<string>'import requests
url = "https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"notes": "<string>",
"hit_policy": "first",
"sheet": "<string>"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('file', '<string>');
form.append('notes', '<string>');
form.append('hit_policy', 'first');
form.append('sheet', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet', 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.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"workspace": "<string>",
"key": "<string>",
"version": 123,
"content_sha": "<string>",
"status": "draft",
"created_by": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"content": "<string>",
"notes": "<string>",
"submitted_by": "<string>",
"submitted_at": "2023-11-07T05:31:56Z",
"approved_by": "<string>",
"approved_at": "2023-11-07T05:31:56Z",
"source_instance": "<string>",
"source_version": 123,
"edited_in_place": false
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}Create a draft version from a rule spreadsheet
Import a workbook as a new draft version.
A file with any unreadable cell is refused outright — the rows that did parse are not imported. A rule table silently missing three of its forty rows still evaluates and still passes review, so a partial read is never a partial import. Parse the file first to see every problem at once.
The draft records which file it came from, so the approver can see at the gate what produced it. Importing changes nothing that runs: the version arrives as a draft and goes through the same submit and approve steps as any other.
Required roles: author or workspace_admin
curl --request POST \
--url https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form file=@example-file \
--form 'notes=<string>' \
--form hit_policy=first \
--form 'sheet=<string>'import requests
url = "https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"notes": "<string>",
"hit_policy": "first",
"sheet": "<string>"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('file', '<string>');
form.append('notes', '<string>');
form.append('hit_policy', 'first');
form.append('sheet', '<string>');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet', 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.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/decisions/{workspace}/{key}/versions/from-spreadsheet")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"notes\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"hit_policy\"\r\n\r\nfirst\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"sheet\"\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"workspace": "<string>",
"key": "<string>",
"version": 123,
"content_sha": "<string>",
"status": "draft",
"created_by": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"content": "<string>",
"notes": "<string>",
"submitted_by": "<string>",
"submitted_at": "2023-11-07T05:31:56Z",
"approved_by": "<string>",
"approved_at": "2023-11-07T05:31:56Z",
"source_instance": "<string>",
"source_version": 123,
"edited_in_place": false
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}{
"error": "<string>",
"code": 500
}Authorizations
The access token received from the authorization server in the OAuth 2.0 flow.
Path Parameters
Workspace slug.
64^[a-z0-9][a-z0-9-]{0,63}$Decision key — a flat slug, never a path.
64^[a-z0-9][a-z0-9-]{0,63}$Body
Response
Successful Response
Lifecycle state of a single version.
draft → submitted → approved, with reject returning a
submitted version to draft and retire taking an approved
version out of circulation.
draft, submitted, approved, retired Raw JDM JSON, byte-exact.
True when an existing draft was rewritten rather than a new version added.
Was this page helpful?

