curl --request POST \
--url https://api.getoneprofile.ai/linkedin/agent/heartbeat/ \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"lease_nonce": "<string>",
"checkpoint": true,
"extension_version": "",
"member_urn": "<string>",
"running_action_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"running_claimed_at": "2023-11-07T05:31:56Z",
"supported_kinds": [
"<string>"
],
"timezone": "<string>"
}
'import requests
url = "https://api.getoneprofile.ai/linkedin/agent/heartbeat/"
payload = {
"lease_nonce": "<string>",
"checkpoint": True,
"extension_version": "",
"member_urn": "<string>",
"running_action_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"running_claimed_at": "2023-11-07T05:31:56Z",
"supported_kinds": ["<string>"],
"timezone": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
lease_nonce: '<string>',
checkpoint: true,
extension_version: '',
member_urn: '<string>',
running_action_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
running_claimed_at: '2023-11-07T05:31:56Z',
supported_kinds: ['<string>'],
timezone: '<string>'
})
};
fetch('https://api.getoneprofile.ai/linkedin/agent/heartbeat/', 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.getoneprofile.ai/linkedin/agent/heartbeat/",
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([
'lease_nonce' => '<string>',
'checkpoint' => true,
'extension_version' => '',
'member_urn' => '<string>',
'running_action_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'running_claimed_at' => '2023-11-07T05:31:56Z',
'supported_kinds' => [
'<string>'
],
'timezone' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.getoneprofile.ai/linkedin/agent/heartbeat/"
payload := strings.NewReader("{\n \"lease_nonce\": \"<string>\",\n \"checkpoint\": true,\n \"extension_version\": \"\",\n \"member_urn\": \"<string>\",\n \"running_action_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"running_claimed_at\": \"2023-11-07T05:31:56Z\",\n \"supported_kinds\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.getoneprofile.ai/linkedin/agent/heartbeat/")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"lease_nonce\": \"<string>\",\n \"checkpoint\": true,\n \"extension_version\": \"\",\n \"member_urn\": \"<string>\",\n \"running_action_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"running_claimed_at\": \"2023-11-07T05:31:56Z\",\n \"supported_kinds\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getoneprofile.ai/linkedin/agent/heartbeat/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"lease_nonce\": \"<string>\",\n \"checkpoint\": true,\n \"extension_version\": \"\",\n \"member_urn\": \"<string>\",\n \"running_action_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"running_claimed_at\": \"2023-11-07T05:31:56Z\",\n \"supported_kinds\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"account_mismatch": true,
"checkpoint": true,
"config_version": 123,
"lease_granted": true,
"poll_after_seconds": 123,
"queued_count": 123,
"run_mode": "manual",
"approvals_waiting": 0,
"attempts_enabled": false,
"lease_holder_label": "<string>",
"resume_enabled": false,
"running_claim": "renewed",
"unpaced_waiting": false,
"usage": [],
"usage_resets_at": "2023-11-07T05:31:56Z",
"wait": {
"next_at": "2023-11-07T05:31:56Z",
"reason": "not_connected",
"resets_at": "2023-11-07T05:31:56Z"
}
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>",
"issues": [
{
"input": "<string>",
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>"
}Report liveness and read the authoritative run state
Records that a browser is alive, renews its exclusive lease on the account, and returns the run state the extension must obey, which is how a change made in the web app (the sender’s approval setting, a limit) reaches the browser without a push channel. Also carries the wrong-account guard: if the browser is signed in as somebody other than the bound member, the response says so and the extension must stop. A reported checkpoint is applied only from the browser holding the lease; a browser that does not hold it is told which browser does. While work is queued it also says what the next step waits on and until when, and asks for check-ins at most 15 seconds apart while work is about to run. It says how many of the sender’s steps wait for a person on Tasks, less those a paused sequence or paused contact holds, and whether a step that waits for no gap is ready.
curl --request POST \
--url https://api.getoneprofile.ai/linkedin/agent/heartbeat/ \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"lease_nonce": "<string>",
"checkpoint": true,
"extension_version": "",
"member_urn": "<string>",
"running_action_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"running_claimed_at": "2023-11-07T05:31:56Z",
"supported_kinds": [
"<string>"
],
"timezone": "<string>"
}
'import requests
url = "https://api.getoneprofile.ai/linkedin/agent/heartbeat/"
payload = {
"lease_nonce": "<string>",
"checkpoint": True,
"extension_version": "",
"member_urn": "<string>",
"running_action_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"running_claimed_at": "2023-11-07T05:31:56Z",
"supported_kinds": ["<string>"],
"timezone": "<string>"
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
lease_nonce: '<string>',
checkpoint: true,
extension_version: '',
member_urn: '<string>',
running_action_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
running_claimed_at: '2023-11-07T05:31:56Z',
supported_kinds: ['<string>'],
timezone: '<string>'
})
};
fetch('https://api.getoneprofile.ai/linkedin/agent/heartbeat/', 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.getoneprofile.ai/linkedin/agent/heartbeat/",
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([
'lease_nonce' => '<string>',
'checkpoint' => true,
'extension_version' => '',
'member_urn' => '<string>',
'running_action_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'running_claimed_at' => '2023-11-07T05:31:56Z',
'supported_kinds' => [
'<string>'
],
'timezone' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.getoneprofile.ai/linkedin/agent/heartbeat/"
payload := strings.NewReader("{\n \"lease_nonce\": \"<string>\",\n \"checkpoint\": true,\n \"extension_version\": \"\",\n \"member_urn\": \"<string>\",\n \"running_action_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"running_claimed_at\": \"2023-11-07T05:31:56Z\",\n \"supported_kinds\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
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.getoneprofile.ai/linkedin/agent/heartbeat/")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"lease_nonce\": \"<string>\",\n \"checkpoint\": true,\n \"extension_version\": \"\",\n \"member_urn\": \"<string>\",\n \"running_action_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"running_claimed_at\": \"2023-11-07T05:31:56Z\",\n \"supported_kinds\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.getoneprofile.ai/linkedin/agent/heartbeat/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"lease_nonce\": \"<string>\",\n \"checkpoint\": true,\n \"extension_version\": \"\",\n \"member_urn\": \"<string>\",\n \"running_action_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"running_claimed_at\": \"2023-11-07T05:31:56Z\",\n \"supported_kinds\": [\n \"<string>\"\n ],\n \"timezone\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"account_mismatch": true,
"checkpoint": true,
"config_version": 123,
"lease_granted": true,
"poll_after_seconds": 123,
"queued_count": 123,
"run_mode": "manual",
"approvals_waiting": 0,
"attempts_enabled": false,
"lease_holder_label": "<string>",
"resume_enabled": false,
"running_claim": "renewed",
"unpaced_waiting": false,
"usage": [],
"usage_resets_at": "2023-11-07T05:31:56Z",
"wait": {
"next_at": "2023-11-07T05:31:56Z",
"reason": "not_connected",
"resets_at": "2023-11-07T05:31:56Z"
}
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>",
"issues": [
{
"input": "<string>",
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}{
"detail": "<string>"
}{
"detail": "<string>"
}{
"detail": "<string>"
}Authorizations
Body
This browser's lease identity; only the holder is handed work.
8 - 64True when LinkedIn is challenging the account; no work is handed out while it stands. False clears it; null leaves it untouched.
32Who the browser is currently signed in as, for the mismatch guard.
128The step this browser is running right now, sent on the check-ins it makes while it runs; with running_claimed_at it keeps that step's claim from lapsing under a browser still working on it, including one waking from sleep. Null between steps.
When the running step was claimed, as the claim handed it out.
How far the running step got, from a build that resumes steps (resume:v1). Accepted and not kept: the commit grant, not the phase, says whether anything may have changed on LinkedIn.
claimed, navigated, dispatched, committing, committed The step kinds this build can run, and the capabilities it has beyond them (such as profile_view:read_relationship). Nothing is handed to a browser that it cannot run. Leave it out (an older build) and the browser runs the kinds that existed before builds said. Sent on every check-in: a check-in without it reads as such a build.
641 - 64The browser's IANA timezone (Intl.DateTimeFormat().resolvedOptions().timeZone). It fills the sender's timezone when the sender has none: their daily limits reset at its midnight and sequences send in its hours. A timezone the sender has is never moved by it. Taken only from the browser driving the account.
64Response
Successful Response
The authoritative run state, returned on every heartbeat.
account_mismatch is the hard stop: the browser is signed in as somebody
other than the account we are bound to, and acting would send this customer's
outreach from the wrong identity.
run_mode is the sender's LinkedIn approval setting in force (manual for
a sender who never set one): the side panel shows it and can change it.
Approval happens on Oneprofile's Tasks page before a step is queued, so a
step handed to the browser runs whichever it says.
queued_count counts steps waiting for a browser, not one running in one.
The version of the selector and pacing config this server serves. A browser running any other version, older or newer, fetches the config again.
How long to wait before the next check-in: the account's own time between steps, never more, and never so long the browser stops reading as active. At most 15 seconds while work is about to run (the time between steps is running out, a step may start now, or one is running with more behind it), so a missed wake-up costs seconds rather than a whole interval.
Whether a person approves a sender's LinkedIn steps before they run, or they run on their own.
The sender's own LinkedIn setting, kept on the sender beside their email
modes so the approval queue reads one home for both. The absence of one
(SenderProfileDTO.linkedin_approval_mode is None) reads as MANUAL:
nothing runs on somebody's LinkedIn unattended until they have said so. The
approval queue still tells "never set" apart from "chose manual", which is
the level its settings surfaces name.
manual, auto How many of this sender's LinkedIn steps wait for a person on Oneprofile's Tasks page, less those a paused sequence or paused contact holds; the side panel offers Approve tasks while any do.
Whether a build that reports attempts (attempts:v1) reports a run cut off without an error from LinkedIn to /actions/{id}/attempts/ and runs the step again only on the answer. The same switch as resume_enabled.
When lease_granted is false, what the browser holding the lease calls itself (for example 'Chrome on macOS'); null when that is not known.
Whether a build that resumes steps (resume:v1) may resume one that stopped without an error from LinkedIn. Off, a stopped step fails for a person to retry, as it did before; the grant and the saved results stay on either way.
For a check-in that named a running step: renewed while that claim is still this browser's, lost once it is not (settled, rejected, or lapsed while the browser was gone), and the browser then stops the step before it changes anything more. Null for a check-in that named none.
renewed, lost A step that waits for no gap between steps (one the Oneprofile team fired to test the sender) could be handed out now: ask for it alone (unmetered_only) without waiting out this browser's own gap.
Show child attributes
Show child attributes
When today's counts in usage start over: 00:00 in the sender's timezone. Older servers leave it out, and a client then reads the next UTC midnight.
What the next step is waiting on, and until when, as this browser sees it (another browser holding the lease reads as lease_held_elsewhere); null while nothing is queued.
Show child attributes
Show child attributes
Was this page helpful?