Approve a historical QuickBooks preview
Approves the exact snapshot_hash for a backfill or correction preview in the same connected QuickBooks company. Rechecks stored-plan integrity and every source fingerprint. Repeated approval reuses the existing execution. Captures/queues checkpoints and returns202; provider completion must be checked from the run. Requires a connected QuickBooks company for mutations. Current user/group permissions must include manage_settings, access_account_settings or group_all in addition to route access. Requires the integration platform global/configured client feature gate (normally integration_platform_foundation). Requires permission: one of access_account_settings.
curl --request POST \
--url https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"snapshot_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
'import requests
url = "https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve"
payload = { "snapshot_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
snapshot_hash: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
})
};
fetch('https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve', 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.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve",
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([
'snapshot_hash' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve"
payload := strings.NewReader("{\n \"snapshot_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"snapshot_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"snapshot_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"id": 42,
"run_type": "dry_run",
"status": "Example",
"object_types": [
"customer"
],
"counters": {
"total": 2,
"create": 2,
"update": 2,
"link": 2,
"skip": 2,
"conflict": 2,
"pending": 2,
"queued": 2,
"processing": 2,
"failed": 2,
"needs_review": 2,
"skipped": 2,
"processed": 2
},
"summary": {
"snapshot_hash": "Example",
"record_count": 2,
"zero_provider_writes": true,
"requires_approval": true,
"checkpointed": true,
"resumable": true,
"provider_complete": true,
"reviewable_count": 2
},
"context": {
"purpose": "Example",
"filters": {
"program_ids": [
42
],
"object_types": [
"<string>"
],
"date_from": "2023-12-25",
"date_to": "2023-12-25",
"source_run_id": 42
},
"plan_version": 2,
"cursor": {
"strategy": "frozen_plan_v1",
"record_count": 2,
"objects": {}
},
"realm_key": "Example",
"zero_provider_writes": true,
"snapshot_hash": "Example",
"preview_run_id": 42,
"source_run_id": 42,
"approved_by": 42,
"approved_at": "2026-10-20T12:00:00Z",
"requires_approval": true
},
"created_at": "2026-10-20T12:00:00Z",
"started_at": "2026-10-20T12:00:00Z",
"finished_at": "2026-10-20T12:00:00Z",
"events": [
{
"id": 42,
"status": "Example",
"hys_object_type": "Example",
"hys_object_id": 42,
"provider_object_type": "Example",
"retryable": true,
"error_code": "Example",
"plan": {
"hys_object_type": "donor",
"hys_object_id": 42,
"provider_object_type": "customer",
"action": "create",
"reason_code": "Example",
"source_fingerprint": "Example",
"accounting_projection": {},
"destructive_or_corrective": true
},
"outbox_event_id": 42
}
]
}
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Not Found",
"status": "error"
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}Authorizations
Passport bearer token authentication for legacy admin sessions.
Path Parameters
Connection id in the current organization.
Run id in the current organization.
Body
Validated request fields for this operation.
Snapshot hash. Validation: required, string, size:64.
64"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
curl --request POST \
--url https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"snapshot_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
'import requests
url = "https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve"
payload = { "snapshot_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
snapshot_hash: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
})
};
fetch('https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve', 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.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve",
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([
'snapshot_hash' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve"
payload := strings.NewReader("{\n \"snapshot_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"snapshot_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/integrations/hub/connections/{connection_id}/quickbooks/historical/previews/{run_id}/approve")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"snapshot_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"id": 42,
"run_type": "dry_run",
"status": "Example",
"object_types": [
"customer"
],
"counters": {
"total": 2,
"create": 2,
"update": 2,
"link": 2,
"skip": 2,
"conflict": 2,
"pending": 2,
"queued": 2,
"processing": 2,
"failed": 2,
"needs_review": 2,
"skipped": 2,
"processed": 2
},
"summary": {
"snapshot_hash": "Example",
"record_count": 2,
"zero_provider_writes": true,
"requires_approval": true,
"checkpointed": true,
"resumable": true,
"provider_complete": true,
"reviewable_count": 2
},
"context": {
"purpose": "Example",
"filters": {
"program_ids": [
42
],
"object_types": [
"<string>"
],
"date_from": "2023-12-25",
"date_to": "2023-12-25",
"source_run_id": 42
},
"plan_version": 2,
"cursor": {
"strategy": "frozen_plan_v1",
"record_count": 2,
"objects": {}
},
"realm_key": "Example",
"zero_provider_writes": true,
"snapshot_hash": "Example",
"preview_run_id": 42,
"source_run_id": 42,
"approved_by": 42,
"approved_at": "2026-10-20T12:00:00Z",
"requires_approval": true
},
"created_at": "2026-10-20T12:00:00Z",
"started_at": "2026-10-20T12:00:00Z",
"finished_at": "2026-10-20T12:00:00Z",
"events": [
{
"id": 42,
"status": "Example",
"hys_object_type": "Example",
"hys_object_id": 42,
"provider_object_type": "Example",
"retryable": true,
"error_code": "Example",
"plan": {
"hys_object_type": "donor",
"hys_object_id": 42,
"provider_object_type": "customer",
"action": "create",
"reason_code": "Example",
"source_fingerprint": "Example",
"accounting_projection": {},
"destructive_or_corrective": true
},
"outbox_event_id": 42
}
]
}
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Not Found",
"status": "error"
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}