cURL
curl --request POST \
--url https://app.revyops.com/api/public/activities/batch/ \
--header 'X-API-KEY: <api-key>'import requests
url = "https://app.revyops.com/api/public/activities/batch/"
headers = {"X-API-KEY": "<api-key>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {'X-API-KEY': '<api-key>'}};
fetch('https://app.revyops.com/api/public/activities/batch/', 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://app.revyops.com/api/public/activities/batch/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.revyops.com/api/public/activities/batch/"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("X-API-KEY", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.revyops.com/api/public/activities/batch/")
.header("X-API-KEY", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.revyops.com/api/public/activities/batch/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
response = http.request(request)
puts response.read_bodyActivities
Log Activities in Bulk
Logs up to 5,000 custom activities in one call. They are stored in the background; check the result with the batch status call.
POST
/
public
/
activities
/
batch
/
cURL
curl --request POST \
--url https://app.revyops.com/api/public/activities/batch/ \
--header 'X-API-KEY: <api-key>'import requests
url = "https://app.revyops.com/api/public/activities/batch/"
headers = {"X-API-KEY": "<api-key>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {'X-API-KEY': '<api-key>'}};
fetch('https://app.revyops.com/api/public/activities/batch/', 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://app.revyops.com/api/public/activities/batch/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.revyops.com/api/public/activities/batch/"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("X-API-KEY", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.revyops.com/api/public/activities/batch/")
.header("X-API-KEY", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.revyops.com/api/public/activities/batch/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
response = http.request(request)
puts response.read_bodySend up to 5,000 custom activities in one request, with the whole request at most 5 MB. The request is checked and answered straight away with a batch id, and the events are stored in the background, usually within seconds. Use Get Batch Result to see what happened to each one.
One batch request counts once against the rate limit, however many events it carries.
Each event needs at least one identifier that the activity type links on: phone, email or LinkedIn URL for contact types, domain for company types. The person or company must already exist. Logging an activity never creates a contact.
400, one or more events are invalid. Nothing from the batch is stored. Fix the listed events and send the whole batch again:
422, the
413, the request is larger than 5 MB. Send fewer events per request.
503, the batch could not be queued. Nothing was stored; send it again.
Request
{
"source": "bigquery",
"events": [
{
"id": "u8821:tapped_search_result:well_88213:2026-10-08",
"activity_key": "26a86703-f134-46f5-9e11-ac4f4d74e656",
"occured_at": "2026-10-08T06:12:40Z",
"phone": "+14057401507",
"properties": {"marker_id": "well_88213", "count": 14}
},
{
"id": "u9020:opened_app:2026-10-08",
"activity_key": "a1c0d3f2-5b7e-4c55-9d1e-0f6b8a2e4c11",
"occured_at": "2026-10-08T07:40:02Z",
"email": "tom@acme.com"
}
]
}
| Field | Required | Notes |
|---|---|---|
source | No | A source added under Activities & Scoring and enabled for every type in the batch. Leave it out to use the default source. |
events[].id | Yes | Your id for the event, up to 128 characters, unique per activity type. An id we already hold for that type and source is skipped, so a batch can be sent again safely. |
events[].activity_key | Yes | A custom activity type id from List Activity Types. |
events[].occured_at | Yes | When it happened, ISO 8601 with a timezone. |
events[].phone | One identifier | E.164 format, for example +14057401507. |
events[].email | One identifier | |
events[].linkedin_url | One identifier | |
events[].domain | Company types | Used for activity types that apply to companies. |
events[].properties | No | Only fields defined on the activity type, up to 2,048 bytes per event. |
Responses
202, the batch is accepted:{
"batch_id": "4e7c9b1e-2f1a-4c8e-9a51-1b7d3c0e6f42",
"received": 1000,
"status_url": "/api/public/activities/batch/4e7c9b1e-2f1a-4c8e-9a51-1b7d3c0e6f42"
}
{
"error": "Validation failed",
"rows": [
{"index": 17, "field": "phone", "message": "Not a valid phone number. Send E.164, for example +14057401507."},
{"index": 418, "field": "id", "message": "Duplicate id for this activity type in this batch."}
],
"row_errors": 2
}
source is unknown or not enabled for one of the activity types.
429, the workspace has reached its daily event limit. The response says when it resets and carries a Retry-After header:
{"error": "Daily event limit reached", "limit": 2000000, "received_today": 1999500, "resets_at": "2026-10-10T00:00:00+00:00"}
Send one or two batches at a time rather than all at once, and back off on a
429. Allow at least 60 seconds for a response: a full batch takes several seconds to check.Authorizations
Response
200
No response body
Was this page helpful?

