Validate a manual-interaction import mapping
Requires manual_interactions and current interaction/record authority. Body visibility can restrict read/edit/delete even when timeline metadata is visible. Shared visibility requires a valid organization shared_group_id. Event invitation participants and related tasks require access and current version boundaries. Also requires manual_interactions_import. Donors must resolve by ID/email; ID disambiguates duplicate email matches. Required type/occurred_at mappings and valid row content determine readiness. Historical backfill defaults source_system to generic_csv, duplicate mode to skip and disables AI summary/title generation.
curl --request POST \
--url https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"mappings": {
"type": 1,
"occurred_at": 1,
"donor_id": 1,
"donor_email": 1,
"assigned_to_user_id": 1,
"subject": 1,
"body_plain": 1,
"direction": 1,
"outcome": 1,
"duration_minutes": 1,
"follow_up_at": 1,
"body_visibility": 1,
"shared_group_id": 1,
"counts_as_touch": 1,
"external_reference": 1,
"idempotency_key": 1
},
"header_offset": 50,
"has_header": true,
"generate_ai_summaries": true,
"use_ai_summary_as_title": true,
"default_shared_group_id": 123,
"counts_as_touch": true,
"historical_backfill": true,
"source_system": "<string>"
}
'import requests
url = "https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate"
payload = {
"mappings": {
"type": 1,
"occurred_at": 1,
"donor_id": 1,
"donor_email": 1,
"assigned_to_user_id": 1,
"subject": 1,
"body_plain": 1,
"direction": 1,
"outcome": 1,
"duration_minutes": 1,
"follow_up_at": 1,
"body_visibility": 1,
"shared_group_id": 1,
"counts_as_touch": 1,
"external_reference": 1,
"idempotency_key": 1
},
"header_offset": 50,
"has_header": True,
"generate_ai_summaries": True,
"use_ai_summary_as_title": True,
"default_shared_group_id": 123,
"counts_as_touch": True,
"historical_backfill": True,
"source_system": "<string>"
}
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({
mappings: {
type: 1,
occurred_at: 1,
donor_id: 1,
donor_email: 1,
assigned_to_user_id: 1,
subject: 1,
body_plain: 1,
direction: 1,
outcome: 1,
duration_minutes: 1,
follow_up_at: 1,
body_visibility: 1,
shared_group_id: 1,
counts_as_touch: 1,
external_reference: 1,
idempotency_key: 1
},
header_offset: 50,
has_header: true,
generate_ai_summaries: true,
use_ai_summary_as_title: true,
default_shared_group_id: 123,
counts_as_touch: true,
historical_backfill: true,
source_system: '<string>'
})
};
fetch('https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate', 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/interactions/manual/imports/{import_id}/validate",
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([
'mappings' => [
'type' => 1,
'occurred_at' => 1,
'donor_id' => 1,
'donor_email' => 1,
'assigned_to_user_id' => 1,
'subject' => 1,
'body_plain' => 1,
'direction' => 1,
'outcome' => 1,
'duration_minutes' => 1,
'follow_up_at' => 1,
'body_visibility' => 1,
'shared_group_id' => 1,
'counts_as_touch' => 1,
'external_reference' => 1,
'idempotency_key' => 1
],
'header_offset' => 50,
'has_header' => true,
'generate_ai_summaries' => true,
'use_ai_summary_as_title' => true,
'default_shared_group_id' => 123,
'counts_as_touch' => true,
'historical_backfill' => true,
'source_system' => '<string>'
]),
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/interactions/manual/imports/{import_id}/validate"
payload := strings.NewReader("{\n \"mappings\": {\n \"type\": 1,\n \"occurred_at\": 1,\n \"donor_id\": 1,\n \"donor_email\": 1,\n \"assigned_to_user_id\": 1,\n \"subject\": 1,\n \"body_plain\": 1,\n \"direction\": 1,\n \"outcome\": 1,\n \"duration_minutes\": 1,\n \"follow_up_at\": 1,\n \"body_visibility\": 1,\n \"shared_group_id\": 1,\n \"counts_as_touch\": 1,\n \"external_reference\": 1,\n \"idempotency_key\": 1\n },\n \"header_offset\": 50,\n \"has_header\": true,\n \"generate_ai_summaries\": true,\n \"use_ai_summary_as_title\": true,\n \"default_shared_group_id\": 123,\n \"counts_as_touch\": true,\n \"historical_backfill\": true,\n \"source_system\": \"<string>\"\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/interactions/manual/imports/{import_id}/validate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"mappings\": {\n \"type\": 1,\n \"occurred_at\": 1,\n \"donor_id\": 1,\n \"donor_email\": 1,\n \"assigned_to_user_id\": 1,\n \"subject\": 1,\n \"body_plain\": 1,\n \"direction\": 1,\n \"outcome\": 1,\n \"duration_minutes\": 1,\n \"follow_up_at\": 1,\n \"body_visibility\": 1,\n \"shared_group_id\": 1,\n \"counts_as_touch\": 1,\n \"external_reference\": 1,\n \"idempotency_key\": 1\n },\n \"header_offset\": 50,\n \"has_header\": true,\n \"generate_ai_summaries\": true,\n \"use_ai_summary_as_title\": true,\n \"default_shared_group_id\": 123,\n \"counts_as_touch\": true,\n \"historical_backfill\": true,\n \"source_system\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate")
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 \"mappings\": {\n \"type\": 1,\n \"occurred_at\": 1,\n \"donor_id\": 1,\n \"donor_email\": 1,\n \"assigned_to_user_id\": 1,\n \"subject\": 1,\n \"body_plain\": 1,\n \"direction\": 1,\n \"outcome\": 1,\n \"duration_minutes\": 1,\n \"follow_up_at\": 1,\n \"body_visibility\": 1,\n \"shared_group_id\": 1,\n \"counts_as_touch\": 1,\n \"external_reference\": 1,\n \"idempotency_key\": 1\n },\n \"header_offset\": 50,\n \"has_header\": true,\n \"generate_ai_summaries\": true,\n \"use_ai_summary_as_title\": true,\n \"default_shared_group_id\": 123,\n \"counts_as_touch\": true,\n \"historical_backfill\": true,\n \"source_system\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"import_id": 123,
"total_rows": 123,
"valid_rows": 123,
"update_count": 123,
"duplicate_count": 123,
"error_rows": 123,
"errors": [
{
"row": 123,
"errors": [
"<string>"
]
}
],
"warnings": [
"<string>"
],
"can_process": true
}
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"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
Import id.
Body
Request fields accepted by this operation. Omitted optional properties retain the behavior described above.
Show child attributes
Show child attributes
Validation: nullable|integer|min:0|max:100.
0 <= x <= 100Validation: nullable|boolean.
Validation: nullable|boolean.
Validation: nullable|boolean.
Validation: nullable|in:skip,update,create_new.
skip, update, create_new, null Validation: nullable|in:private,metadata,shared,team.
private, metadata, shared, team, null Validation: nullable|integer.
Validation: nullable|boolean.
Validation: nullable|boolean.
Validation: nullable|string|max:64.
64Response
Validate a manual-interaction import mapping response.
Show child attributes
Show child attributes
curl --request POST \
--url https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"mappings": {
"type": 1,
"occurred_at": 1,
"donor_id": 1,
"donor_email": 1,
"assigned_to_user_id": 1,
"subject": 1,
"body_plain": 1,
"direction": 1,
"outcome": 1,
"duration_minutes": 1,
"follow_up_at": 1,
"body_visibility": 1,
"shared_group_id": 1,
"counts_as_touch": 1,
"external_reference": 1,
"idempotency_key": 1
},
"header_offset": 50,
"has_header": true,
"generate_ai_summaries": true,
"use_ai_summary_as_title": true,
"default_shared_group_id": 123,
"counts_as_touch": true,
"historical_backfill": true,
"source_system": "<string>"
}
'import requests
url = "https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate"
payload = {
"mappings": {
"type": 1,
"occurred_at": 1,
"donor_id": 1,
"donor_email": 1,
"assigned_to_user_id": 1,
"subject": 1,
"body_plain": 1,
"direction": 1,
"outcome": 1,
"duration_minutes": 1,
"follow_up_at": 1,
"body_visibility": 1,
"shared_group_id": 1,
"counts_as_touch": 1,
"external_reference": 1,
"idempotency_key": 1
},
"header_offset": 50,
"has_header": True,
"generate_ai_summaries": True,
"use_ai_summary_as_title": True,
"default_shared_group_id": 123,
"counts_as_touch": True,
"historical_backfill": True,
"source_system": "<string>"
}
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({
mappings: {
type: 1,
occurred_at: 1,
donor_id: 1,
donor_email: 1,
assigned_to_user_id: 1,
subject: 1,
body_plain: 1,
direction: 1,
outcome: 1,
duration_minutes: 1,
follow_up_at: 1,
body_visibility: 1,
shared_group_id: 1,
counts_as_touch: 1,
external_reference: 1,
idempotency_key: 1
},
header_offset: 50,
has_header: true,
generate_ai_summaries: true,
use_ai_summary_as_title: true,
default_shared_group_id: 123,
counts_as_touch: true,
historical_backfill: true,
source_system: '<string>'
})
};
fetch('https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate', 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/interactions/manual/imports/{import_id}/validate",
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([
'mappings' => [
'type' => 1,
'occurred_at' => 1,
'donor_id' => 1,
'donor_email' => 1,
'assigned_to_user_id' => 1,
'subject' => 1,
'body_plain' => 1,
'direction' => 1,
'outcome' => 1,
'duration_minutes' => 1,
'follow_up_at' => 1,
'body_visibility' => 1,
'shared_group_id' => 1,
'counts_as_touch' => 1,
'external_reference' => 1,
'idempotency_key' => 1
],
'header_offset' => 50,
'has_header' => true,
'generate_ai_summaries' => true,
'use_ai_summary_as_title' => true,
'default_shared_group_id' => 123,
'counts_as_touch' => true,
'historical_backfill' => true,
'source_system' => '<string>'
]),
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/interactions/manual/imports/{import_id}/validate"
payload := strings.NewReader("{\n \"mappings\": {\n \"type\": 1,\n \"occurred_at\": 1,\n \"donor_id\": 1,\n \"donor_email\": 1,\n \"assigned_to_user_id\": 1,\n \"subject\": 1,\n \"body_plain\": 1,\n \"direction\": 1,\n \"outcome\": 1,\n \"duration_minutes\": 1,\n \"follow_up_at\": 1,\n \"body_visibility\": 1,\n \"shared_group_id\": 1,\n \"counts_as_touch\": 1,\n \"external_reference\": 1,\n \"idempotency_key\": 1\n },\n \"header_offset\": 50,\n \"has_header\": true,\n \"generate_ai_summaries\": true,\n \"use_ai_summary_as_title\": true,\n \"default_shared_group_id\": 123,\n \"counts_as_touch\": true,\n \"historical_backfill\": true,\n \"source_system\": \"<string>\"\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/interactions/manual/imports/{import_id}/validate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"mappings\": {\n \"type\": 1,\n \"occurred_at\": 1,\n \"donor_id\": 1,\n \"donor_email\": 1,\n \"assigned_to_user_id\": 1,\n \"subject\": 1,\n \"body_plain\": 1,\n \"direction\": 1,\n \"outcome\": 1,\n \"duration_minutes\": 1,\n \"follow_up_at\": 1,\n \"body_visibility\": 1,\n \"shared_group_id\": 1,\n \"counts_as_touch\": 1,\n \"external_reference\": 1,\n \"idempotency_key\": 1\n },\n \"header_offset\": 50,\n \"has_header\": true,\n \"generate_ai_summaries\": true,\n \"use_ai_summary_as_title\": true,\n \"default_shared_group_id\": 123,\n \"counts_as_touch\": true,\n \"historical_backfill\": true,\n \"source_system\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/interactions/manual/imports/{import_id}/validate")
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 \"mappings\": {\n \"type\": 1,\n \"occurred_at\": 1,\n \"donor_id\": 1,\n \"donor_email\": 1,\n \"assigned_to_user_id\": 1,\n \"subject\": 1,\n \"body_plain\": 1,\n \"direction\": 1,\n \"outcome\": 1,\n \"duration_minutes\": 1,\n \"follow_up_at\": 1,\n \"body_visibility\": 1,\n \"shared_group_id\": 1,\n \"counts_as_touch\": 1,\n \"external_reference\": 1,\n \"idempotency_key\": 1\n },\n \"header_offset\": 50,\n \"has_header\": true,\n \"generate_ai_summaries\": true,\n \"use_ai_summary_as_title\": true,\n \"default_shared_group_id\": 123,\n \"counts_as_touch\": true,\n \"historical_backfill\": true,\n \"source_system\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"import_id": 123,
"total_rows": 123,
"valid_rows": 123,
"update_count": 123,
"duplicate_count": 123,
"error_rows": 123,
"errors": [
{
"row": 123,
"errors": [
"<string>"
]
}
],
"warnings": [
"<string>"
],
"can_process": true
}
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Something went wrong. Please try again.",
"status": "error",
"error": "invalid_request",
"code": "DONOR_NOT_FOUND"
}{
"message": "Not Found",
"status": "error"
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}