curl --request POST \
--url https://allocait.app/api/v1/setup/receipts/{id}/undo \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"dry_run": true
}
'import requests
url = "https://allocait.app/api/v1/setup/receipts/{id}/undo"
payload = { "dry_run": True }
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({dry_run: true})
};
fetch('https://allocait.app/api/v1/setup/receipts/{id}/undo', 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://allocait.app/api/v1/setup/receipts/{id}/undo",
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([
'dry_run' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <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://allocait.app/api/v1/setup/receipts/{id}/undo"
payload := strings.NewReader("{\n \"dry_run\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<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://allocait.app/api/v1/setup/receipts/{id}/undo")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"dry_run\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://allocait.app/api/v1/setup/receipts/{id}/undo")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"dry_run\": true\n}"
response = http.request(request)
puts response.read_body{
"receipt_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"dry_run": true,
"file": {
"name": "<string>",
"author": "<string>",
"revision": 123
},
"counts": {
"removed": 123,
"restored": 123,
"kept": 123,
"already_gone": 123
},
"results": [
{
"kind": "class",
"name": "<string>",
"was": "created",
"outcome": "removed",
"reason": "changed"
}
],
"next": "<string>"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Internal error",
"error_code": "INTERNAL_ERROR",
"request_id": "5b1e7c52-3f4a-4d0e-9a55-2d5cbe6f0a11"
}Undo an applied setup file, or preview the undo
Removes what the import created that the user has not changed or used since and nothing else uses, puts back what it updated, and keeps the rest, naming each kept item and why. Recorded values, holdings, cash and the active scenario are never touched. The receipt is removed once the undo has run.
dry_run defaults to true: with no body, or dry_run: true, nothing is changed and the answer says what
would be removed, restored and kept. Send dry_run: false to undo. Only the newest receipt of a file can be
undone; an older one is 409 IN_USE and names the later one in later_receipt_id.
Requires the write permission, for the preview as well.
curl --request POST \
--url https://allocait.app/api/v1/setup/receipts/{id}/undo \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"dry_run": true
}
'import requests
url = "https://allocait.app/api/v1/setup/receipts/{id}/undo"
payload = { "dry_run": True }
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({dry_run: true})
};
fetch('https://allocait.app/api/v1/setup/receipts/{id}/undo', 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://allocait.app/api/v1/setup/receipts/{id}/undo",
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([
'dry_run' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <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://allocait.app/api/v1/setup/receipts/{id}/undo"
payload := strings.NewReader("{\n \"dry_run\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<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://allocait.app/api/v1/setup/receipts/{id}/undo")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"dry_run\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://allocait.app/api/v1/setup/receipts/{id}/undo")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"dry_run\": true\n}"
response = http.request(request)
puts response.read_body{
"receipt_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"dry_run": true,
"file": {
"name": "<string>",
"author": "<string>",
"revision": 123
},
"counts": {
"removed": 123,
"restored": 123,
"kept": 123,
"already_gone": 123
},
"results": [
{
"kind": "class",
"name": "<string>",
"was": "created",
"outcome": "removed",
"reason": "changed"
}
],
"next": "<string>"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Portfolio not found or access denied",
"error_code": "NOT_FOUND"
}{
"error": "Internal error",
"error_code": "INTERNAL_ERROR",
"request_id": "5b1e7c52-3f4a-4d0e-9a55-2d5cbe6f0a11"
}Authorizations
Raw API key shown once when created in the Allocait app (Settings > API keys). Send it verbatim in this header; the server stores and compares only its SHA-256 hash. Allocait generates every key: alc_ followed by 64 lowercase hex characters. Keys issued before 2026-10-10 are 64 hex characters with no prefix and keep working. A key may carry an expiry (90 days or 1 year, or never). A malformed, unknown, revoked or expired key gets 401 with no further detail, and a malformed one is refused before any lookup. Keys cannot be created through this API.
Path Parameters
receipt_id, from POST /setup/apply or GET /setup/receipts
Body
true (the default, also when the body is empty) shows what would be removed, restored and kept and changes nothing. false undoes the import.
Response
What the undo would do (dry_run true) or did (dry_run false)