curl --request POST \
--url https://api.orbit.devotel.io/api/v1/contacts/{id}/consent \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"channel": "sms",
"consent_type": "marketing",
"source": "web_form",
"metadata": {
"form": "summer-promo-signup"
}
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/contacts/{id}/consent"
payload = {
"channel": "sms",
"consent_type": "marketing",
"source": "web_form",
"metadata": { "form": "summer-promo-signup" }
}
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({
channel: 'sms',
consent_type: 'marketing',
source: 'web_form',
metadata: {form: 'summer-promo-signup'}
})
};
fetch('https://api.orbit.devotel.io/api/v1/contacts/{id}/consent', 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/{id}/consent",
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([
'channel' => 'sms',
'consent_type' => 'marketing',
'source' => 'web_form',
'metadata' => [
'form' => 'summer-promo-signup'
]
]),
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/{id}/consent"
payload := strings.NewReader("{\n \"channel\": \"sms\",\n \"consent_type\": \"marketing\",\n \"source\": \"web_form\",\n \"metadata\": {\n \"form\": \"summer-promo-signup\"\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/{id}/consent")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"channel\": \"sms\",\n \"consent_type\": \"marketing\",\n \"source\": \"web_form\",\n \"metadata\": {\n \"form\": \"summer-promo-signup\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/contacts/{id}/consent")
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 \"channel\": \"sms\",\n \"consent_type\": \"marketing\",\n \"source\": \"web_form\",\n \"metadata\": {\n \"form\": \"summer-promo-signup\"\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {},
"meta": {}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "<string>",
"status": 429,
"retry_after": 2
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}Record consent for a contact on a channel
Record a proof-of-consent event for a contact on a single channel. channel is restricted to the engagement channels below; consent_type and source default to marketing and api when omitted. ip_address and metadata capture opt-in evidence for GDPR / TCPA audits. Returns the created consent record; revoke it again with DELETE /contacts/{id}/consent/{channel}.
curl --request POST \
--url https://api.orbit.devotel.io/api/v1/contacts/{id}/consent \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"channel": "sms",
"consent_type": "marketing",
"source": "web_form",
"metadata": {
"form": "summer-promo-signup"
}
}
'import requests
url = "https://api.orbit.devotel.io/api/v1/contacts/{id}/consent"
payload = {
"channel": "sms",
"consent_type": "marketing",
"source": "web_form",
"metadata": { "form": "summer-promo-signup" }
}
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({
channel: 'sms',
consent_type: 'marketing',
source: 'web_form',
metadata: {form: 'summer-promo-signup'}
})
};
fetch('https://api.orbit.devotel.io/api/v1/contacts/{id}/consent', 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/{id}/consent",
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([
'channel' => 'sms',
'consent_type' => 'marketing',
'source' => 'web_form',
'metadata' => [
'form' => 'summer-promo-signup'
]
]),
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/{id}/consent"
payload := strings.NewReader("{\n \"channel\": \"sms\",\n \"consent_type\": \"marketing\",\n \"source\": \"web_form\",\n \"metadata\": {\n \"form\": \"summer-promo-signup\"\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/{id}/consent")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"channel\": \"sms\",\n \"consent_type\": \"marketing\",\n \"source\": \"web_form\",\n \"metadata\": {\n \"form\": \"summer-promo-signup\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.orbit.devotel.io/api/v1/contacts/{id}/consent")
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 \"channel\": \"sms\",\n \"consent_type\": \"marketing\",\n \"source\": \"web_form\",\n \"metadata\": {\n \"form\": \"summer-promo-signup\"\n }\n}"
response = http.request(request)
puts response.read_body{
"data": {},
"meta": {}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "<string>",
"status": 429,
"retry_after": 2
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"status": 123,
"details": {}
},
"meta": {
"request_id": "<string>",
"timestamp": "2023-11-07T05:31:56Z",
"docs_url": "<string>"
}
}Authorizations
Dashboard JWT token from Clerk
Headers
Stripe-style idempotency token. Pass a stable, client-generated value (1-255 chars) to dedupe retries on transient timeouts. The same key+credential+path replays the original response for 24h on 2xx (5min on 4xx, 30s on 5xx). Returns 409 if a concurrent request with the same key is already in flight; replayed responses include the Idempotency-Replay: true response header.
1 - 255Sandbox opt-in for Clerk-session-authenticated requests — see Test mode explained for the full credential-header matrix and worked samples. Set to true to route the call through the test-mode pipeline: no real provider delivery, no credits deducted, response meta.test_mode: true. Ignored for live API keys (dv_live_sk_*) — server-to-server clients must use a test-prefixed key (dv_test_sk_*) to exercise sandbox. Test-prefixed keys unconditionally enable sandbox regardless of this header.
true, false Path Parameters
ID of the contact the consent is recorded for.
Body
Channel the consent applies to.
sms, whatsapp, rcs, viber, email, voice Scope of the consent; defaults to marketing when omitted.
marketing, transactional, all How the opt-in was captured; defaults to api when omitted.
web_form, api, import, opt_in_keyword, verbal IPv4 / IPv6 address captured at opt-in time as proof of consent.
Free-form proof-of-consent evidence (form id, campaign, …); under 8 KB.