Contacts, conversations & leads
Read and create the CRM side.
The CRM half of the API: the people the business talks to, the threads with them, and the deals in progress. Reads are paginated and filterable; writes are idempotent.
Contacts
A contact is a person, with one or more identities - a WhatsApp number, an email address, a Telegram id, an Instagram username. Send to any of them and the platform resolves the contact; create a contact with a phone and an email and both become identities.
curl -X GET "https://communication-api.artofluminaire.com/api/v1/contacts?search=rahul&per_page=25" \
-H "Authorization: Bearer omni_live_YOUR_API_KEY" \
-H "Accept: application/json"// Node.js 18+ (built-in fetch), saved as request.mjs for top-level await. Replace the key with your own.
const response = await fetch("https://communication-api.artofluminaire.com/api/v1/contacts?search=rahul&per_page=25", {
method: "GET",
headers: {
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
},
});
const payload = await response.json();
if (!response.ok) {
// Every error is { error: { code, message, details, request_id } }.
throw new Error(`${payload.error.code}: ${payload.error.message} (request ${payload.error.request_id})`);
}
console.log(payload.data);# pip install requests
import requests
response = requests.get(
"https://communication-api.artofluminaire.com/api/v1/contacts?search=rahul&per_page=25",
headers={
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
},
timeout=30,
)
payload = response.json()
if not response.ok:
# Every error is {"error": {"code", "message", "details", "request_id"}}.
error = payload["error"]
raise RuntimeError(f"{error['code']}: {error['message']} (request {error['request_id']})")
print(payload["data"])<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client(['http_errors' => false, 'timeout' => 30]);
$response = $client->get('https://communication-api.artofluminaire.com/api/v1/contacts?search=rahul&per_page=25', [
'headers' => [
'Authorization' => 'Bearer omni_live_YOUR_API_KEY',
'Accept' => 'application/json',
],
]);
$payload = json_decode((string) $response->getBody(), true);
if ($response->getStatusCode() >= 400) {
// Every error is ['error' => ['code', 'message', 'details', 'request_id']].
throw new RuntimeException(sprintf('%s: %s (request %s)', $payload['error']['code'], $payload['error']['message'], $payload['error']['request_id']));
}
echo json_encode($payload['data'], JSON_PRETTY_PRINT), PHP_EOL;// Java 17+, no dependencies (java.net.http). Parse the JSON with your usual library.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://communication-api.artofluminaire.com/api/v1/contacts?search=rahul&per_page=25"))
.header("Authorization", "Bearer omni_live_YOUR_API_KEY")
.header("Accept", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new RuntimeException("Request failed: " + response.body());
}
System.out.println(response.body());
}
}// .NET 7+ (C# 11 raw string literals). Parse the JSON with System.Text.Json.
using System;
using System.Net.Http;
using System.Text;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, "https://communication-api.artofluminaire.com/api/v1/contacts?search=rahul&per_page=25");
request.Headers.TryAddWithoutValidation("Authorization", "Bearer omni_live_YOUR_API_KEY");
request.Headers.TryAddWithoutValidation("Accept", "application/json");
using var response = await client.SendAsync(request);
var payload = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new Exception($"Request failed: {payload}");
}
Console.WriteLine(payload);// Go 1.20+, standard library only. Decode the JSON with encoding/json.
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://communication-api.artofluminaire.com/api/v1/contacts?search=rahul&per_page=25", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer omni_live_YOUR_API_KEY")
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
payload, _ := io.ReadAll(resp.Body)
if resp.StatusCode >= 400 {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
panic(fmt.Sprintf("request failed: %s", payload))
}
fmt.Println(string(payload))
}Try it - send it and see the response
search matches name, email and phone; lifecycle_stage is one of lead, prospect, customer, churned; tag filters by a tag name; channel by the identities a contact has; created_after by date.
curl -X POST "https://communication-api.artofluminaire.com/api/v1/contacts" \
-H "Authorization: Bearer omni_live_YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: CRM-CUSTOMER-88213" \
-d '{
"first_name": "Rahul",
"last_name": "Verma",
"phone": "919876543210",
"email": "rahul@example.com",
"company": "Verma Traders",
"lifecycle_stage": "customer",
"tags": [
"wholesale",
"delhi"
]
}'// Node.js 18+ (built-in fetch), saved as request.mjs for top-level await. Replace the key with your own.
const response = await fetch("https://communication-api.artofluminaire.com/api/v1/contacts", {
method: "POST",
headers: {
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
"Content-Type": "application/json",
"Idempotency-Key": "CRM-CUSTOMER-88213",
},
body: JSON.stringify({
"first_name": "Rahul",
"last_name": "Verma",
"phone": "919876543210",
"email": "rahul@example.com",
"company": "Verma Traders",
"lifecycle_stage": "customer",
"tags": [
"wholesale",
"delhi"
]
}),
});
const payload = await response.json();
if (!response.ok) {
// Every error is { error: { code, message, details, request_id } }.
throw new Error(`${payload.error.code}: ${payload.error.message} (request ${payload.error.request_id})`);
}
console.log(payload.data);# pip install requests
import requests
response = requests.post(
"https://communication-api.artofluminaire.com/api/v1/contacts",
headers={
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
"Content-Type": "application/json",
"Idempotency-Key": "CRM-CUSTOMER-88213",
},
json={
"first_name": "Rahul",
"last_name": "Verma",
"phone": "919876543210",
"email": "rahul@example.com",
"company": "Verma Traders",
"lifecycle_stage": "customer",
"tags": [
"wholesale",
"delhi",
],
},
timeout=30,
)
payload = response.json()
if not response.ok:
# Every error is {"error": {"code", "message", "details", "request_id"}}.
error = payload["error"]
raise RuntimeError(f"{error['code']}: {error['message']} (request {error['request_id']})")
print(payload["data"])<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client(['http_errors' => false, 'timeout' => 30]);
$response = $client->post('https://communication-api.artofluminaire.com/api/v1/contacts', [
'headers' => [
'Authorization' => 'Bearer omni_live_YOUR_API_KEY',
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Idempotency-Key' => 'CRM-CUSTOMER-88213',
],
'json' => [
'first_name' => 'Rahul',
'last_name' => 'Verma',
'phone' => '919876543210',
'email' => 'rahul@example.com',
'company' => 'Verma Traders',
'lifecycle_stage' => 'customer',
'tags' => [
'wholesale',
'delhi',
],
],
]);
$payload = json_decode((string) $response->getBody(), true);
if ($response->getStatusCode() >= 400) {
// Every error is ['error' => ['code', 'message', 'details', 'request_id']].
throw new RuntimeException(sprintf('%s: %s (request %s)', $payload['error']['code'], $payload['error']['message'], $payload['error']['request_id']));
}
echo json_encode($payload['data'], JSON_PRETTY_PRINT), PHP_EOL;// Java 17+, no dependencies (java.net.http). Parse the JSON with your usual library.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://communication-api.artofluminaire.com/api/v1/contacts"))
.header("Authorization", "Bearer omni_live_YOUR_API_KEY")
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "CRM-CUSTOMER-88213")
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"first_name": "Rahul",
"last_name": "Verma",
"phone": "919876543210",
"email": "rahul@example.com",
"company": "Verma Traders",
"lifecycle_stage": "customer",
"tags": [
"wholesale",
"delhi"
]
}
"""))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new RuntimeException("Request failed: " + response.body());
}
System.out.println(response.body());
}
}// .NET 7+ (C# 11 raw string literals). Parse the JSON with System.Text.Json.
using System;
using System.Net.Http;
using System.Text;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://communication-api.artofluminaire.com/api/v1/contacts");
request.Headers.TryAddWithoutValidation("Authorization", "Bearer omni_live_YOUR_API_KEY");
request.Headers.TryAddWithoutValidation("Accept", "application/json");
request.Headers.TryAddWithoutValidation("Idempotency-Key", "CRM-CUSTOMER-88213");
request.Content = new StringContent("""
{
"first_name": "Rahul",
"last_name": "Verma",
"phone": "919876543210",
"email": "rahul@example.com",
"company": "Verma Traders",
"lifecycle_stage": "customer",
"tags": [
"wholesale",
"delhi"
]
}
""", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
var payload = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new Exception($"Request failed: {payload}");
}
Console.WriteLine(payload);// Go 1.20+, standard library only. Decode the JSON with encoding/json.
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"first_name": "Rahul",
"last_name": "Verma",
"phone": "919876543210",
"email": "rahul@example.com",
"company": "Verma Traders",
"lifecycle_stage": "customer",
"tags": [
"wholesale",
"delhi"
]
}`)
req, err := http.NewRequest("POST", "https://communication-api.artofluminaire.com/api/v1/contacts", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer omni_live_YOUR_API_KEY")
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "CRM-CUSTOMER-88213")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
payload, _ := io.ReadAll(resp.Body)
if resp.StatusCode >= 400 {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
panic(fmt.Sprintf("request failed: %s", payload))
}
fmt.Println(string(payload))
}Try it - send it and see the response
Creating a contact whose phone, email or identity already belongs to another contact is refused with 422 validation_failed and the owning contact's id in details.contact_id - use that id. A handle is never silently moved between contacts: that would move its conversation history, and it is a decision the business makes with a merge, not one an API call makes by accident.
GET /contacts/{id} returns the full record with identities, tags and the custom fields the business has defined.
Conversations
One conversation per contact per channel connection. Your integration reads them to show a customer's history in your own system, or to find the thread a message belongs to.
curl -X GET "https://communication-api.artofluminaire.com/api/v1/conversations?status=open&limit=25" \
-H "Authorization: Bearer omni_live_YOUR_API_KEY" \
-H "Accept: application/json"// Node.js 18+ (built-in fetch), saved as request.mjs for top-level await. Replace the key with your own.
const response = await fetch("https://communication-api.artofluminaire.com/api/v1/conversations?status=open&limit=25", {
method: "GET",
headers: {
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
},
});
const payload = await response.json();
if (!response.ok) {
// Every error is { error: { code, message, details, request_id } }.
throw new Error(`${payload.error.code}: ${payload.error.message} (request ${payload.error.request_id})`);
}
console.log(payload.data);# pip install requests
import requests
response = requests.get(
"https://communication-api.artofluminaire.com/api/v1/conversations?status=open&limit=25",
headers={
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
},
timeout=30,
)
payload = response.json()
if not response.ok:
# Every error is {"error": {"code", "message", "details", "request_id"}}.
error = payload["error"]
raise RuntimeError(f"{error['code']}: {error['message']} (request {error['request_id']})")
print(payload["data"])<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client(['http_errors' => false, 'timeout' => 30]);
$response = $client->get('https://communication-api.artofluminaire.com/api/v1/conversations?status=open&limit=25', [
'headers' => [
'Authorization' => 'Bearer omni_live_YOUR_API_KEY',
'Accept' => 'application/json',
],
]);
$payload = json_decode((string) $response->getBody(), true);
if ($response->getStatusCode() >= 400) {
// Every error is ['error' => ['code', 'message', 'details', 'request_id']].
throw new RuntimeException(sprintf('%s: %s (request %s)', $payload['error']['code'], $payload['error']['message'], $payload['error']['request_id']));
}
echo json_encode($payload['data'], JSON_PRETTY_PRINT), PHP_EOL;// Java 17+, no dependencies (java.net.http). Parse the JSON with your usual library.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://communication-api.artofluminaire.com/api/v1/conversations?status=open&limit=25"))
.header("Authorization", "Bearer omni_live_YOUR_API_KEY")
.header("Accept", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new RuntimeException("Request failed: " + response.body());
}
System.out.println(response.body());
}
}// .NET 7+ (C# 11 raw string literals). Parse the JSON with System.Text.Json.
using System;
using System.Net.Http;
using System.Text;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, "https://communication-api.artofluminaire.com/api/v1/conversations?status=open&limit=25");
request.Headers.TryAddWithoutValidation("Authorization", "Bearer omni_live_YOUR_API_KEY");
request.Headers.TryAddWithoutValidation("Accept", "application/json");
using var response = await client.SendAsync(request);
var payload = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new Exception($"Request failed: {payload}");
}
Console.WriteLine(payload);// Go 1.20+, standard library only. Decode the JSON with encoding/json.
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://communication-api.artofluminaire.com/api/v1/conversations?status=open&limit=25", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer omni_live_YOUR_API_KEY")
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
payload, _ := io.ReadAll(resp.Body)
if resp.StatusCode >= 400 {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
panic(fmt.Sprintf("request failed: %s", payload))
}
fmt.Println(string(payload))
}Try it - send it and see the response
status is open, pending, resolved or closed; contact_id and connection_id narrow the list. Messages in a conversation, newest first, cursor paginated:
curl -X GET "https://communication-api.artofluminaire.com/api/v1/conversations/01997f2a-3c6d-7c1e-9b4a-2f0c9d8e7a11/messages?limit=50" \
-H "Authorization: Bearer omni_live_YOUR_API_KEY" \
-H "Accept: application/json"// Node.js 18+ (built-in fetch), saved as request.mjs for top-level await. Replace the key with your own.
const response = await fetch("https://communication-api.artofluminaire.com/api/v1/conversations/01997f2a-3c6d-7c1e-9b4a-2f0c9d8e7a11/messages?limit=50", {
method: "GET",
headers: {
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
},
});
const payload = await response.json();
if (!response.ok) {
// Every error is { error: { code, message, details, request_id } }.
throw new Error(`${payload.error.code}: ${payload.error.message} (request ${payload.error.request_id})`);
}
console.log(payload.data);# pip install requests
import requests
response = requests.get(
"https://communication-api.artofluminaire.com/api/v1/conversations/01997f2a-3c6d-7c1e-9b4a-2f0c9d8e7a11/messages?limit=50",
headers={
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
},
timeout=30,
)
payload = response.json()
if not response.ok:
# Every error is {"error": {"code", "message", "details", "request_id"}}.
error = payload["error"]
raise RuntimeError(f"{error['code']}: {error['message']} (request {error['request_id']})")
print(payload["data"])<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client(['http_errors' => false, 'timeout' => 30]);
$response = $client->get('https://communication-api.artofluminaire.com/api/v1/conversations/01997f2a-3c6d-7c1e-9b4a-2f0c9d8e7a11/messages?limit=50', [
'headers' => [
'Authorization' => 'Bearer omni_live_YOUR_API_KEY',
'Accept' => 'application/json',
],
]);
$payload = json_decode((string) $response->getBody(), true);
if ($response->getStatusCode() >= 400) {
// Every error is ['error' => ['code', 'message', 'details', 'request_id']].
throw new RuntimeException(sprintf('%s: %s (request %s)', $payload['error']['code'], $payload['error']['message'], $payload['error']['request_id']));
}
echo json_encode($payload['data'], JSON_PRETTY_PRINT), PHP_EOL;// Java 17+, no dependencies (java.net.http). Parse the JSON with your usual library.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://communication-api.artofluminaire.com/api/v1/conversations/01997f2a-3c6d-7c1e-9b4a-2f0c9d8e7a11/messages?limit=50"))
.header("Authorization", "Bearer omni_live_YOUR_API_KEY")
.header("Accept", "application/json")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new RuntimeException("Request failed: " + response.body());
}
System.out.println(response.body());
}
}// .NET 7+ (C# 11 raw string literals). Parse the JSON with System.Text.Json.
using System;
using System.Net.Http;
using System.Text;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, "https://communication-api.artofluminaire.com/api/v1/conversations/01997f2a-3c6d-7c1e-9b4a-2f0c9d8e7a11/messages?limit=50");
request.Headers.TryAddWithoutValidation("Authorization", "Bearer omni_live_YOUR_API_KEY");
request.Headers.TryAddWithoutValidation("Accept", "application/json");
using var response = await client.SendAsync(request);
var payload = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new Exception($"Request failed: {payload}");
}
Console.WriteLine(payload);// Go 1.20+, standard library only. Decode the JSON with encoding/json.
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://communication-api.artofluminaire.com/api/v1/conversations/01997f2a-3c6d-7c1e-9b4a-2f0c9d8e7a11/messages?limit=50", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer omni_live_YOUR_API_KEY")
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
payload, _ := io.ReadAll(resp.Body)
if resp.StatusCode >= 400 {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
panic(fmt.Sprintf("request failed: %s", payload))
}
fmt.Println(string(payload))
}Try it - send it and see the response
The API does not assign, resolve or tag conversations - those are agents' actions in the inbox. Sending a message into one is the API's part.
Leads
A lead is a deal in a pipeline, attached to a contact. A web form, a marketplace enquiry or a booking engine creates one and the sales team picks it up in the dashboard, with the automation engine free to assign it, notify someone, or send a first template.
curl -X POST "https://communication-api.artofluminaire.com/api/v1/leads" \
-H "Authorization: Bearer omni_live_YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: WEBFORM-4471" \
-d '{
"contact_id": "01997f2a-6f90-7f41-8e7d-5c3f20b1ad44",
"title": "Bulk order enquiry from the website",
"value": 125000,
"currency": "INR",
"source_channel": "web"
}'// Node.js 18+ (built-in fetch), saved as request.mjs for top-level await. Replace the key with your own.
const response = await fetch("https://communication-api.artofluminaire.com/api/v1/leads", {
method: "POST",
headers: {
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
"Content-Type": "application/json",
"Idempotency-Key": "WEBFORM-4471",
},
body: JSON.stringify({
"contact_id": "01997f2a-6f90-7f41-8e7d-5c3f20b1ad44",
"title": "Bulk order enquiry from the website",
"value": 125000,
"currency": "INR",
"source_channel": "web"
}),
});
const payload = await response.json();
if (!response.ok) {
// Every error is { error: { code, message, details, request_id } }.
throw new Error(`${payload.error.code}: ${payload.error.message} (request ${payload.error.request_id})`);
}
console.log(payload.data);# pip install requests
import requests
response = requests.post(
"https://communication-api.artofluminaire.com/api/v1/leads",
headers={
"Authorization": "Bearer omni_live_YOUR_API_KEY",
"Accept": "application/json",
"Content-Type": "application/json",
"Idempotency-Key": "WEBFORM-4471",
},
json={
"contact_id": "01997f2a-6f90-7f41-8e7d-5c3f20b1ad44",
"title": "Bulk order enquiry from the website",
"value": 125000,
"currency": "INR",
"source_channel": "web",
},
timeout=30,
)
payload = response.json()
if not response.ok:
# Every error is {"error": {"code", "message", "details", "request_id"}}.
error = payload["error"]
raise RuntimeError(f"{error['code']}: {error['message']} (request {error['request_id']})")
print(payload["data"])<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';
$client = new GuzzleHttp\Client(['http_errors' => false, 'timeout' => 30]);
$response = $client->post('https://communication-api.artofluminaire.com/api/v1/leads', [
'headers' => [
'Authorization' => 'Bearer omni_live_YOUR_API_KEY',
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Idempotency-Key' => 'WEBFORM-4471',
],
'json' => [
'contact_id' => '01997f2a-6f90-7f41-8e7d-5c3f20b1ad44',
'title' => 'Bulk order enquiry from the website',
'value' => 125000,
'currency' => 'INR',
'source_channel' => 'web',
],
]);
$payload = json_decode((string) $response->getBody(), true);
if ($response->getStatusCode() >= 400) {
// Every error is ['error' => ['code', 'message', 'details', 'request_id']].
throw new RuntimeException(sprintf('%s: %s (request %s)', $payload['error']['code'], $payload['error']['message'], $payload['error']['request_id']));
}
echo json_encode($payload['data'], JSON_PRETTY_PRINT), PHP_EOL;// Java 17+, no dependencies (java.net.http). Parse the JSON with your usual library.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://communication-api.artofluminaire.com/api/v1/leads"))
.header("Authorization", "Bearer omni_live_YOUR_API_KEY")
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.header("Idempotency-Key", "WEBFORM-4471")
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"contact_id": "01997f2a-6f90-7f41-8e7d-5c3f20b1ad44",
"title": "Bulk order enquiry from the website",
"value": 125000,
"currency": "INR",
"source_channel": "web"
}
"""))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new RuntimeException("Request failed: " + response.body());
}
System.out.println(response.body());
}
}// .NET 7+ (C# 11 raw string literals). Parse the JSON with System.Text.Json.
using System;
using System.Net.Http;
using System.Text;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://communication-api.artofluminaire.com/api/v1/leads");
request.Headers.TryAddWithoutValidation("Authorization", "Bearer omni_live_YOUR_API_KEY");
request.Headers.TryAddWithoutValidation("Accept", "application/json");
request.Headers.TryAddWithoutValidation("Idempotency-Key", "WEBFORM-4471");
request.Content = new StringContent("""
{
"contact_id": "01997f2a-6f90-7f41-8e7d-5c3f20b1ad44",
"title": "Bulk order enquiry from the website",
"value": 125000,
"currency": "INR",
"source_channel": "web"
}
""", Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
var payload = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
// Every error is {"error": {"code", "message", "details", "request_id"}}.
throw new Exception($"Request failed: {payload}");
}
Console.WriteLine(payload);// Go 1.20+, standard library only. Decode the JSON with encoding/json.
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{
"contact_id": "01997f2a-6f90-7f41-8e7d-5c3f20b1ad44",
"title": "Bulk order enquiry from the website",
"value": 125000,
"currency": "INR",
"source_channel": "web"
}`)
req, err := http.NewRequest("POST", "https://communication-api.artofluminaire.com/api/v1/leads", body)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer omni_live_YOUR_API_KEY")
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", "WEBFORM-4471")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
payload, _ := io.ReadAll(resp.Body)
if resp.StatusCode >= 400 {
// Every error is {"error": {"code", "message", "details", "request_id"}}.
panic(fmt.Sprintf("request failed: %s", payload))
}
fmt.Println(string(payload))
}Try it - send it and see the response
pipeline_id and stage_id are optional: leave them out and the lead lands in the default pipeline's first stage. value is whole currency units. The answer is 201 with the lead, and a lead.created webhook fires for every subscriber.
What is read-only
Pipelines, stages, tags and custom field definitions are managed in the dashboard and read through the resources they appear on. Reading GET /leads needs leads.read; the create needs leads.create, and the two are separate so a form that only submits leads cannot read the pipeline.
https://communication-api.artofluminaire.com
Every response carries X-Request-ID; quote it when you write to support.