Enqueue a bulk contact import
curl --request POST \
--url https://api.orbit.devotel.io/api/v1/contacts/imports \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"file_name": "q1-newsletter.csv",
"merge_strategy": "merge",
"rows": [
{
"phone": "+14155552671",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace"
}
]
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/contacts/imports"
payload = {
"file_name": "q1-newsletter.csv",
"merge_strategy": "merge",
"rows": [
{
"phone": "+14155552671",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace"
}
]
}
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({
file_name: 'q1-newsletter.csv',
merge_strategy: 'merge',
rows: [
{
phone: '+14155552671',
email: 'ada@example.com',
first_name: 'Ada',
last_name: 'Lovelace'
}
]
})
};
fetch('https://api.orbit.devotel.io/api/v1/contacts/imports', 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.orbit.devotel.io/api/v1/contacts/imports",
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([
'file_name' => 'q1-newsletter.csv',
'merge_strategy' => 'merge',
'rows' => [
[
'phone' => '+14155552671',
'email' => 'ada@example.com',
'first_name' => 'Ada',
'last_name' => 'Lovelace'
]
]
]),
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.orbit.devotel.io/api/v1/contacts/imports"
payload := strings.NewReader("{\n \"file_name\": \"q1-newsletter.csv\",\n \"merge_strategy\": \"merge\",\n \"rows\": [\n {\n \"phone\": \"+14155552671\",\n \"email\": \"ada@example.com\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Lovelace\"\n }\n ]\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.orbit.devotel.io/api/v1/contacts/imports")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"file_name\": \"q1-newsletter.csv\",\n \"merge_strategy\": \"merge\",\n \"rows\": [\n {\n \"phone\": \"+14155552671\",\n \"email\": \"ada@example.com\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Lovelace\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/contacts/imports")
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 \"file_name\": \"q1-newsletter.csv\",\n \"merge_strategy\": \"merge\",\n \"rows\": [\n {\n \"phone\": \"+14155552671\",\n \"email\": \"ada@example.com\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Lovelace\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"job_id": "import_01HZX9IMPORT",
"total_rows": 5000,
"status": "pending"
},
"meta": {
"request_id": "req_01HZX9ABCDEF",
"timestamp": "2026-02-02T12:00:00.000Z"
}
}Contacts
Enqueue a bulk contact import
Enqueue a large contact import as an asynchronous job. Post the parsed rows (already mapped to field keys such as phone, email, first_name) and the job runs in the background; poll GET /api/v1/contacts/imports/ for progress. Set merge_strategy to merge to update existing contacts, or skip (the default) to leave matches untouched. Returns 503 if the import queue is unavailable so the caller can fall back to the synchronous bulk path.
POST
/
api
/
v1
/
contacts
/
imports
Enqueue a bulk contact import
curl --request POST \
--url https://api.orbit.devotel.io/api/v1/contacts/imports \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"file_name": "q1-newsletter.csv",
"merge_strategy": "merge",
"rows": [
{
"phone": "+14155552671",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace"
}
]
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/contacts/imports"
payload = {
"file_name": "q1-newsletter.csv",
"merge_strategy": "merge",
"rows": [
{
"phone": "+14155552671",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace"
}
]
}
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({
file_name: 'q1-newsletter.csv',
merge_strategy: 'merge',
rows: [
{
phone: '+14155552671',
email: 'ada@example.com',
first_name: 'Ada',
last_name: 'Lovelace'
}
]
})
};
fetch('https://api.orbit.devotel.io/api/v1/contacts/imports', 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.orbit.devotel.io/api/v1/contacts/imports",
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([
'file_name' => 'q1-newsletter.csv',
'merge_strategy' => 'merge',
'rows' => [
[
'phone' => '+14155552671',
'email' => 'ada@example.com',
'first_name' => 'Ada',
'last_name' => 'Lovelace'
]
]
]),
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.orbit.devotel.io/api/v1/contacts/imports"
payload := strings.NewReader("{\n \"file_name\": \"q1-newsletter.csv\",\n \"merge_strategy\": \"merge\",\n \"rows\": [\n {\n \"phone\": \"+14155552671\",\n \"email\": \"ada@example.com\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Lovelace\"\n }\n ]\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.orbit.devotel.io/api/v1/contacts/imports")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"file_name\": \"q1-newsletter.csv\",\n \"merge_strategy\": \"merge\",\n \"rows\": [\n {\n \"phone\": \"+14155552671\",\n \"email\": \"ada@example.com\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Lovelace\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/contacts/imports")
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 \"file_name\": \"q1-newsletter.csv\",\n \"merge_strategy\": \"merge\",\n \"rows\": [\n {\n \"phone\": \"+14155552671\",\n \"email\": \"ada@example.com\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Lovelace\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"data": {
"job_id": "import_01HZX9IMPORT",
"total_rows": 5000,
"status": "pending"
},
"meta": {
"request_id": "req_01HZX9ABCDEF",
"timestamp": "2026-02-02T12:00:00.000Z"
}
}Authorizations
BearerApiKey
Dashboard JWT token from Clerk
Body
application/json
The rows to import, each a map of already-mapped field keys to string values.
Required array length:
1 - 1000000 elementsShow child attributes
Show child attributes
Original upload file name, retained for auditing.
Maximum string length:
255How to handle rows that match an existing contact. skip leaves matches untouched; merge updates them.
Available options:
skip, merge ⌘I