curl --request POST \
--url https://api.teamfollowup.ai/api/native-calendar/events \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"calendarId": "cal_6b1f2a7c90",
"startTime": "2026-09-23T13:00:00.000Z",
"endTime": "2026-09-23T14:00:00.000Z",
"title": "Team meeting",
"notes": "Hold the hour, no bookings."
}'import requests
url = "https://api.teamfollowup.ai/api/native-calendar/events"
payload = {
"calendarId": "cal_6b1f2a7c90",
"startTime": "2026-09-23T13:00:00.000Z",
"endTime": "2026-09-23T14:00:00.000Z"
}
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({
calendarId: 'cal_6b1f2a7c90',
startTime: '2026-09-23T13:00:00.000Z',
endTime: '2026-09-23T14:00:00.000Z'
})
};
fetch('https://api.teamfollowup.ai/api/native-calendar/events', 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.teamfollowup.ai/api/native-calendar/events",
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([
'calendarId' => 'cal_6b1f2a7c90',
'startTime' => '2026-09-23T13:00:00.000Z',
'endTime' => '2026-09-23T14:00:00.000Z'
]),
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.teamfollowup.ai/api/native-calendar/events"
payload := strings.NewReader("{\n \"calendarId\": \"cal_6b1f2a7c90\",\n \"startTime\": \"2026-09-23T13:00:00.000Z\",\n \"endTime\": \"2026-09-23T14:00:00.000Z\"\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.teamfollowup.ai/api/native-calendar/events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"calendarId\": \"cal_6b1f2a7c90\",\n \"startTime\": \"2026-09-23T13:00:00.000Z\",\n \"endTime\": \"2026-09-23T14:00:00.000Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.teamfollowup.ai/api/native-calendar/events")
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 \"calendarId\": \"cal_6b1f2a7c90\",\n \"startTime\": \"2026-09-23T13:00:00.000Z\",\n \"endTime\": \"2026-09-23T14:00:00.000Z\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"ok": true,
"appointmentId": "apt_1c93f7ab20",
"status": "confirmed"
}
}{
"success": false,
"error": "timezone is required"
}{
"success": false,
"error": "Unauthorized"
}{
"success": false,
"error": "calendar does not belong to this project"
}{
"success": false,
"error": "calendar not found"
}{
"success": false,
"error": "slot rejected: slot_full"
}{
"success": false,
"error": "TooManyRequests"
}{
"success": false,
"error": "Calendar request failed."
}{
"success": false,
"error": "Calendar service is unreachable."
}Add an event
Puts something on the calendar that is not a lead: a meeting, a reminder, time held back.
It carries no contact, starts no confirmation campaign and sends nobody anything. What it does do is occupy the seats it covers, so the agent stops offering that time.
Give it startTime and endTime; title, location and notes are for the people reading the diary.
Cookie-auth callers must send the x-csrf-token header.
Required API key scope: projects:write.
curl --request POST \
--url https://api.teamfollowup.ai/api/native-calendar/events \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"calendarId": "cal_6b1f2a7c90",
"startTime": "2026-09-23T13:00:00.000Z",
"endTime": "2026-09-23T14:00:00.000Z",
"title": "Team meeting",
"notes": "Hold the hour, no bookings."
}'import requests
url = "https://api.teamfollowup.ai/api/native-calendar/events"
payload = {
"calendarId": "cal_6b1f2a7c90",
"startTime": "2026-09-23T13:00:00.000Z",
"endTime": "2026-09-23T14:00:00.000Z"
}
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({
calendarId: 'cal_6b1f2a7c90',
startTime: '2026-09-23T13:00:00.000Z',
endTime: '2026-09-23T14:00:00.000Z'
})
};
fetch('https://api.teamfollowup.ai/api/native-calendar/events', 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.teamfollowup.ai/api/native-calendar/events",
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([
'calendarId' => 'cal_6b1f2a7c90',
'startTime' => '2026-09-23T13:00:00.000Z',
'endTime' => '2026-09-23T14:00:00.000Z'
]),
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.teamfollowup.ai/api/native-calendar/events"
payload := strings.NewReader("{\n \"calendarId\": \"cal_6b1f2a7c90\",\n \"startTime\": \"2026-09-23T13:00:00.000Z\",\n \"endTime\": \"2026-09-23T14:00:00.000Z\"\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.teamfollowup.ai/api/native-calendar/events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"calendarId\": \"cal_6b1f2a7c90\",\n \"startTime\": \"2026-09-23T13:00:00.000Z\",\n \"endTime\": \"2026-09-23T14:00:00.000Z\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.teamfollowup.ai/api/native-calendar/events")
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 \"calendarId\": \"cal_6b1f2a7c90\",\n \"startTime\": \"2026-09-23T13:00:00.000Z\",\n \"endTime\": \"2026-09-23T14:00:00.000Z\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"ok": true,
"appointmentId": "apt_1c93f7ab20",
"status": "confirmed"
}
}{
"success": false,
"error": "timezone is required"
}{
"success": false,
"error": "Unauthorized"
}{
"success": false,
"error": "calendar does not belong to this project"
}{
"success": false,
"error": "calendar not found"
}{
"success": false,
"error": "slot rejected: slot_full"
}{
"success": false,
"error": "TooManyRequests"
}{
"success": false,
"error": "Calendar request failed."
}{
"success": false,
"error": "Calendar service is unreachable."
}Authorizations
Send your API key as Authorization: Bearer YOUR_API_KEY.
Query Parameters
The sub-account this calendar belongs to. It is the only thing that identifies the tenant here, and access is re-checked against it on every call.
Body
The entry.
"cal_6b1f2a7c90"
"2026-09-23T13:00:00.000Z"
"2026-09-23T14:00:00.000Z"
"Team meeting"
What it is, for the diary: a meeting, a reminder, time held.
