Import contacts
Accepts an HTTPS URL for one CSV file plus an exact header-to-field mapper under contacts:write. A Cloudflare Workflow downloads at most 2 MB and 500 rows, validates every mapped Contact, and imports them durably with tenant-local phone, email, and document identity deduplication. The response only confirms that background processing was queued.
curl --request POST \
--url https://api.getarbol.com/v1/contacts/import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"csvUrl": "https://files.example.com/contacts.csv",
"fieldMapper": {
"email": "email",
"familyName": "last_name",
"givenName": "first_name",
"phone": "phone_number"
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
csvUrl: 'https://files.example.com/contacts.csv',
fieldMapper: {
email: 'email',
familyName: 'last_name',
givenName: 'first_name',
phone: 'phone_number'
}
})
};
fetch('https://api.getarbol.com/v1/contacts/import', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.getarbol.com/v1/contacts/import"
payload = {
"csvUrl": "https://files.example.com/contacts.csv",
"fieldMapper": {
"email": "email",
"familyName": "last_name",
"givenName": "first_name",
"phone": "phone_number"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"importId": "agt_018f47a2-4f4d-7d61-9e2c-1d7b8e9a0c31",
"status": "queued"
}{
"defined": true,
"inferable": true,
"code": "BAD_REQUEST",
"status": 400,
"message": "<string>",
"data": {
"issues": [
{
"code": "custom",
"message": "<string>",
"path": [
"<string>"
]
}
],
"truncated": true
}
}{
"defined": true,
"inferable": true,
"code": "UNAUTHORIZED",
"status": 401,
"message": "<string>",
"data": "<unknown>"
}{
"defined": true,
"inferable": true,
"code": "FORBIDDEN",
"status": 403,
"message": "<string>",
"data": {
"missingPermissions": [
"agents:read"
]
}
}{
"code": "PAYLOAD_TOO_LARGE",
"defined": false,
"inferable": false,
"message": "<string>",
"data": "<unknown>"
}{
"code": "UNSUPPORTED_MEDIA_TYPE",
"defined": false,
"inferable": false,
"message": "<string>",
"data": "<unknown>"
}{
"defined": true,
"inferable": true,
"code": "TOO_MANY_REQUESTS",
"status": 429,
"message": "<string>",
"data": {
"retryAfterSeconds": 123
}
}{
"defined": true,
"inferable": true,
"code": "SERVICE_UNAVAILABLE",
"status": 503,
"message": "<string>",
"data": "<unknown>"
}Authorizations
Organization-scoped Auth0 user access token issued to an approved first-party client or exchanged by a trusted OBO resource server.
Body
Remote CSV import request. Arbol downloads a bounded file, maps its headers, and processes it durably in the background.
HTTPS URL of the CSV source. It must return the file directly without redirects and remain available while the Workflow starts.
2048"https://files.example.com/contacts.csv"
Maps exact CSV headers to Contact fields. Fact keys are active Contact Definition identifiers and their values are CSV headers.
Show child attributes
Show child attributes
{ "email": "email", "familyName": "last_name", "givenName": "first_name", "phone": "phone_number" }
Response
OK
Durable Contact import accepted for background processing. The identifier is safe to retain for support and observability.
Opaque Arbol resource identifier; the endpoint and tenant-scoped lookup determine its resource type.
64^[a-z][a-z0-9]{1,15}_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"agt_018f47a2-4f4d-7d61-9e2c-1d7b8e9a0c31"
"queued"curl --request POST \
--url https://api.getarbol.com/v1/contacts/import \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"csvUrl": "https://files.example.com/contacts.csv",
"fieldMapper": {
"email": "email",
"familyName": "last_name",
"givenName": "first_name",
"phone": "phone_number"
}
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
csvUrl: 'https://files.example.com/contacts.csv',
fieldMapper: {
email: 'email',
familyName: 'last_name',
givenName: 'first_name',
phone: 'phone_number'
}
})
};
fetch('https://api.getarbol.com/v1/contacts/import', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.getarbol.com/v1/contacts/import"
payload = {
"csvUrl": "https://files.example.com/contacts.csv",
"fieldMapper": {
"email": "email",
"familyName": "last_name",
"givenName": "first_name",
"phone": "phone_number"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"importId": "agt_018f47a2-4f4d-7d61-9e2c-1d7b8e9a0c31",
"status": "queued"
}{
"defined": true,
"inferable": true,
"code": "BAD_REQUEST",
"status": 400,
"message": "<string>",
"data": {
"issues": [
{
"code": "custom",
"message": "<string>",
"path": [
"<string>"
]
}
],
"truncated": true
}
}{
"defined": true,
"inferable": true,
"code": "UNAUTHORIZED",
"status": 401,
"message": "<string>",
"data": "<unknown>"
}{
"defined": true,
"inferable": true,
"code": "FORBIDDEN",
"status": 403,
"message": "<string>",
"data": {
"missingPermissions": [
"agents:read"
]
}
}{
"code": "PAYLOAD_TOO_LARGE",
"defined": false,
"inferable": false,
"message": "<string>",
"data": "<unknown>"
}{
"code": "UNSUPPORTED_MEDIA_TYPE",
"defined": false,
"inferable": false,
"message": "<string>",
"data": "<unknown>"
}{
"defined": true,
"inferable": true,
"code": "TOO_MANY_REQUESTS",
"status": 429,
"message": "<string>",
"data": {
"retryAfterSeconds": 123
}
}{
"defined": true,
"inferable": true,
"code": "SERVICE_UNAVAILABLE",
"status": 503,
"message": "<string>",
"data": "<unknown>"
}