Create reviewed invitation staff tasks
Applies the reviewed saved plan using current invitee version, plan revision and hash. Creates canonical donor/event-linked staff tasks only for steps without existing mappings; accepted definition/dates are snapshotted. Does not contact invitees. Requires an event start and accessible active invitee. Requires event setup management; archived event invitation history is read-only (409). Also requires task management permission.
curl --request POST \
--url https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"expected_invitee_version": 1,
"plan_id": 42,
"plan_revision": 1,
"definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"steps": [
{
"step_key": "personal_call",
"enabled": true,
"due_date": "2026-11-01",
"assignee_strategy": "invitee_owner",
"assignee_user_id": 42
}
]
}
'import requests
url = "https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans"
payload = {
"expected_invitee_version": 1,
"plan_id": 42,
"plan_revision": 1,
"definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"steps": [
{
"step_key": "personal_call",
"enabled": True,
"due_date": "2026-11-01",
"assignee_strategy": "invitee_owner",
"assignee_user_id": 42
}
]
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
expected_invitee_version: 1,
plan_id: 42,
plan_revision: 1,
definition_hash: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
steps: [
{
step_key: 'personal_call',
enabled: true,
due_date: '2026-11-01',
assignee_strategy: 'invitee_owner',
assignee_user_id: 42
}
]
})
};
fetch('https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans', 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/admin/events/{eventId}/invitees/{inviteeId}/plans",
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([
'expected_invitee_version' => 1,
'plan_id' => 42,
'plan_revision' => 1,
'definition_hash' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
'steps' => [
[
'step_key' => 'personal_call',
'enabled' => true,
'due_date' => '2026-11-01',
'assignee_strategy' => 'invitee_owner',
'assignee_user_id' => 42
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans"
payload := strings.NewReader("{\n \"expected_invitee_version\": 1,\n \"plan_id\": 42,\n \"plan_revision\": 1,\n \"definition_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"steps\": [\n {\n \"step_key\": \"personal_call\",\n \"enabled\": true,\n \"due_date\": \"2026-11-01\",\n \"assignee_strategy\": \"invitee_owner\",\n \"assignee_user_id\": 42\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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/admin/events/{eventId}/invitees/{inviteeId}/plans")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expected_invitee_version\": 1,\n \"plan_id\": 42,\n \"plan_revision\": 1,\n \"definition_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"steps\": [\n {\n \"step_key\": \"personal_call\",\n \"enabled\": true,\n \"due_date\": \"2026-11-01\",\n \"assignee_strategy\": \"invitee_owner\",\n \"assignee_user_id\": 42\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expected_invitee_version\": 1,\n \"plan_id\": 42,\n \"plan_revision\": 1,\n \"definition_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"steps\": [\n {\n \"step_key\": \"personal_call\",\n \"enabled\": true,\n \"due_date\": \"2026-11-01\",\n \"assignee_strategy\": \"invitee_owner\",\n \"assignee_user_id\": 42\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"application_id": 42,
"plan_id": 42,
"plan_revision": 42,
"definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"created_task_ids": [
42
],
"created_task_count": 42,
"mappings": [
{
"step_key": "personal_call",
"task_id": 42,
"generated_due_date": "2026-11-01"
}
],
"notice": "Staff tasks were created. Invitees were not contacted."
}
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Not Found",
"status": "error"
}{
"message": "Version, idempotency, preview or archived-event conflict.",
"error_code": "event_invitee_conflict",
"details": {
"current_version": 42,
"current_lock_version": 42,
"current_revision": 42,
"current_definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}Authorizations
Passport bearer token authentication for legacy admin sessions.
Headers
Nonblank retry key of at most 255 characters, bound to the actor and operation. Reuse unchanged for the same accepted request.
255"invitation-request-1"
Path Parameters
Record ID in the authenticated organization.
42
Record ID in the authenticated organization.
42
Body
Current invitee version from the list.
x >= 11
Saved plan ID.
42
Reviewed plan revision.
x >= 11
Reviewed definition SHA-256.
64"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
1Show child attributes
Show child attributes
Response
Create reviewed invitation staff tasks completed.
Show child attributes
Show child attributes
curl --request POST \
--url https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"expected_invitee_version": 1,
"plan_id": 42,
"plan_revision": 1,
"definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"steps": [
{
"step_key": "personal_call",
"enabled": true,
"due_date": "2026-11-01",
"assignee_strategy": "invitee_owner",
"assignee_user_id": 42
}
]
}
'import requests
url = "https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans"
payload = {
"expected_invitee_version": 1,
"plan_id": 42,
"plan_revision": 1,
"definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"steps": [
{
"step_key": "personal_call",
"enabled": True,
"due_date": "2026-11-01",
"assignee_strategy": "invitee_owner",
"assignee_user_id": 42
}
]
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
expected_invitee_version: 1,
plan_id: 42,
plan_revision: 1,
definition_hash: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
steps: [
{
step_key: 'personal_call',
enabled: true,
due_date: '2026-11-01',
assignee_strategy: 'invitee_owner',
assignee_user_id: 42
}
]
})
};
fetch('https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans', 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/admin/events/{eventId}/invitees/{inviteeId}/plans",
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([
'expected_invitee_version' => 1,
'plan_id' => 42,
'plan_revision' => 1,
'definition_hash' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
'steps' => [
[
'step_key' => 'personal_call',
'enabled' => true,
'due_date' => '2026-11-01',
'assignee_strategy' => 'invitee_owner',
'assignee_user_id' => 42
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-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.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans"
payload := strings.NewReader("{\n \"expected_invitee_version\": 1,\n \"plan_id\": 42,\n \"plan_revision\": 1,\n \"definition_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"steps\": [\n {\n \"step_key\": \"personal_call\",\n \"enabled\": true,\n \"due_date\": \"2026-11-01\",\n \"assignee_strategy\": \"invitee_owner\",\n \"assignee_user_id\": 42\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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/admin/events/{eventId}/invitees/{inviteeId}/plans")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"expected_invitee_version\": 1,\n \"plan_id\": 42,\n \"plan_revision\": 1,\n \"definition_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"steps\": [\n {\n \"step_key\": \"personal_call\",\n \"enabled\": true,\n \"due_date\": \"2026-11-01\",\n \"assignee_strategy\": \"invitee_owner\",\n \"assignee_user_id\": 42\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/events/{eventId}/invitees/{inviteeId}/plans")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"expected_invitee_version\": 1,\n \"plan_id\": 42,\n \"plan_revision\": 1,\n \"definition_hash\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\n \"steps\": [\n {\n \"step_key\": \"personal_call\",\n \"enabled\": true,\n \"due_date\": \"2026-11-01\",\n \"assignee_strategy\": \"invitee_owner\",\n \"assignee_user_id\": 42\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"application_id": 42,
"plan_id": 42,
"plan_revision": 42,
"definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"created_task_ids": [
42
],
"created_task_count": 42,
"mappings": [
{
"step_key": "personal_call",
"task_id": 42,
"generated_due_date": "2026-11-01"
}
],
"notice": "Staff tasks were created. Invitees were not contacted."
}
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Not Found",
"status": "error"
}{
"message": "Version, idempotency, preview or archived-event conflict.",
"error_code": "event_invitee_conflict",
"details": {
"current_version": 42,
"current_lock_version": 42,
"current_revision": 42,
"current_definition_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}