pcall POST "/api/v1/partner/events/pull" '{
"ack": [
"evt_9c2e4a6b8d0f1234567890abcdef1234"
],
"status": "unacked",
"limit": 100
}'const res = await call("POST", "/api/v1/partner/events/pull", {
"ack": [
"evt_9c2e4a6b8d0f1234567890abcdef1234"
],
"status": "unacked",
"limit": 100
});
const { data } = await res.json();res = call("POST", "/api/v1/partner/events/pull", {
"ack": [
"evt_9c2e4a6b8d0f1234567890abcdef1234"
],
"status": "unacked",
"limit": 100
})
data = res.json()["data"]<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-bc.userecord.io/api/v1/partner/events/pull",
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([
'ack' => [
'evt_9c2e4a6b8d0f1234567890abcdef1234'
],
'status' => 'unacked',
'limit' => 100
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>",
"x-secret-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-bc.userecord.io/api/v1/partner/events/pull"
payload := strings.NewReader("{\n \"ack\": [\n \"evt_9c2e4a6b8d0f1234567890abcdef1234\"\n ],\n \"status\": \"unacked\",\n \"limit\": 100\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("x-secret-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-bc.userecord.io/api/v1/partner/events/pull")
.header("x-api-key", "<api-key>")
.header("x-secret-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ack\": [\n \"evt_9c2e4a6b8d0f1234567890abcdef1234\"\n ],\n \"status\": \"unacked\",\n \"limit\": 100\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-bc.userecord.io/api/v1/partner/events/pull")
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["x-secret-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ack\": [\n \"evt_9c2e4a6b8d0f1234567890abcdef1234\"\n ],\n \"status\": \"unacked\",\n \"limit\": 100\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"items": [
{
"event_id": "evt_9c2e4a6b8d0f1234567890abcdef1234",
"type": "candidate.result",
"api_version": "2026-10-01",
"created_at": "2026-10-05T12:41:11.000Z",
"mode": "test",
"version": 1,
"sequence": 482913,
"acknowledged": false,
"data": {
"candidate_id": "a3f1c9d2-7b44-4e0a-9c1d-5e6f7a8b9c01",
"external_id": "cand-88231",
"campaign_id": "asmnt_9f2c41d7a8b3e65f",
"mandate_id": "JM_261009101612456H3N8W2L5C9V1Z4",
"job_id": "job-10452",
"workflow_id": "WF_BG_261009101530123K7M2P9Q4X7R5T8",
"name": "Ravi Kumar",
"status": "completed",
"reason": null,
"attempts": 3,
"language": "tamil",
"location_name": "Coimbatore",
"metadata": {
"ats_application_id": "app_991"
},
"started_at": "2026-10-05T09:30:00.000Z",
"completed_at": "2026-10-05T12:41:10.000Z",
"updated_at": "2026-10-05T12:41:10.000Z",
"output": {
"enrichment": {
"qualified": true,
"answers": {
"Do you have a valid driving licence?": "yes",
"Why do you want this job?": "I want a stable job near home"
}
},
"skill_verification": {
"verdict": "Good Fit",
"total_score": 78,
"is_partial": false,
"answered": 3,
"total": 3,
"skills": [
{
"name": "Forklift Basic Operation",
"rating": "Strong"
}
],
"call_recording_url": null,
"answers": [
{
"skill": "Forklift Basic Operation",
"question": "What do you check before lifting a load?",
"answer": "I check the load weight against the forklift rating and that the forks are level.",
"answer_native": null,
"rating": "Strong",
"summary": "Mentions weight limit and fork position.",
"video_url": "https://storage.googleapis.com/record-interviews/sess_91c2/q1.mp4"
}
]
},
"interest_collection": {
"current_role": "Forklift Operator",
"other_roles": [
{
"role": "Store Keeper",
"years": "1 to 2 years"
}
]
}
}
}
}
],
"count": 1,
"acknowledged": 1,
"pending": 1,
"next_cursor": null,
"has_more": false
}
}{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"details": [
{
"path": "<string>",
"message": "<string>"
}
],
"request_id": "<string>"
}
}Pull and confirm events
One call does both jobs. Send the ack ids of the events you already processed, and get the next events back. An event keeps coming back until you put its id in ack. Use it when you cannot expose a URL, and as a safety net next to the webhook.
Scope: events:read
pcall POST "/api/v1/partner/events/pull" '{
"ack": [
"evt_9c2e4a6b8d0f1234567890abcdef1234"
],
"status": "unacked",
"limit": 100
}'const res = await call("POST", "/api/v1/partner/events/pull", {
"ack": [
"evt_9c2e4a6b8d0f1234567890abcdef1234"
],
"status": "unacked",
"limit": 100
});
const { data } = await res.json();res = call("POST", "/api/v1/partner/events/pull", {
"ack": [
"evt_9c2e4a6b8d0f1234567890abcdef1234"
],
"status": "unacked",
"limit": 100
})
data = res.json()["data"]<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-bc.userecord.io/api/v1/partner/events/pull",
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([
'ack' => [
'evt_9c2e4a6b8d0f1234567890abcdef1234'
],
'status' => 'unacked',
'limit' => 100
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>",
"x-secret-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-bc.userecord.io/api/v1/partner/events/pull"
payload := strings.NewReader("{\n \"ack\": [\n \"evt_9c2e4a6b8d0f1234567890abcdef1234\"\n ],\n \"status\": \"unacked\",\n \"limit\": 100\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("x-secret-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-bc.userecord.io/api/v1/partner/events/pull")
.header("x-api-key", "<api-key>")
.header("x-secret-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ack\": [\n \"evt_9c2e4a6b8d0f1234567890abcdef1234\"\n ],\n \"status\": \"unacked\",\n \"limit\": 100\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-bc.userecord.io/api/v1/partner/events/pull")
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["x-secret-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ack\": [\n \"evt_9c2e4a6b8d0f1234567890abcdef1234\"\n ],\n \"status\": \"unacked\",\n \"limit\": 100\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"items": [
{
"event_id": "evt_9c2e4a6b8d0f1234567890abcdef1234",
"type": "candidate.result",
"api_version": "2026-10-01",
"created_at": "2026-10-05T12:41:11.000Z",
"mode": "test",
"version": 1,
"sequence": 482913,
"acknowledged": false,
"data": {
"candidate_id": "a3f1c9d2-7b44-4e0a-9c1d-5e6f7a8b9c01",
"external_id": "cand-88231",
"campaign_id": "asmnt_9f2c41d7a8b3e65f",
"mandate_id": "JM_261009101612456H3N8W2L5C9V1Z4",
"job_id": "job-10452",
"workflow_id": "WF_BG_261009101530123K7M2P9Q4X7R5T8",
"name": "Ravi Kumar",
"status": "completed",
"reason": null,
"attempts": 3,
"language": "tamil",
"location_name": "Coimbatore",
"metadata": {
"ats_application_id": "app_991"
},
"started_at": "2026-10-05T09:30:00.000Z",
"completed_at": "2026-10-05T12:41:10.000Z",
"updated_at": "2026-10-05T12:41:10.000Z",
"output": {
"enrichment": {
"qualified": true,
"answers": {
"Do you have a valid driving licence?": "yes",
"Why do you want this job?": "I want a stable job near home"
}
},
"skill_verification": {
"verdict": "Good Fit",
"total_score": 78,
"is_partial": false,
"answered": 3,
"total": 3,
"skills": [
{
"name": "Forklift Basic Operation",
"rating": "Strong"
}
],
"call_recording_url": null,
"answers": [
{
"skill": "Forklift Basic Operation",
"question": "What do you check before lifting a load?",
"answer": "I check the load weight against the forklift rating and that the forks are level.",
"answer_native": null,
"rating": "Strong",
"summary": "Mentions weight limit and fork position.",
"video_url": "https://storage.googleapis.com/record-interviews/sess_91c2/q1.mp4"
}
]
},
"interest_collection": {
"current_role": "Forklift Operator",
"other_roles": [
{
"role": "Store Keeper",
"years": "1 to 2 years"
}
]
}
}
}
}
],
"count": 1,
"acknowledged": 1,
"pending": 1,
"next_cursor": null,
"has_more": false
}
}{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"details": [
{
"path": "<string>",
"message": "<string>"
}
],
"request_id": "<string>"
}
}Authorizations
Your key id, VFN_TEST_… or VFN_LIVE_…. Sent on every request.
Your secret, VFN_SK_…. Not a real header, and never sent to the API. It is only a form field for Try it, which uses it to sign your request in your browser. In your own code you sign each request with the secret and send x-api-key, x-timestamp and x-signature (see Authentication).
Body
Up to 100 ids of events you processed. They are acknowledged before the page is read, so they do not come back
100^evt_[a-f0-9]{32}$unacked (default) gives only events you have not confirmed. all replays history (use it with from).
unacked, all Only this event type.
candidate.result Only events created at or after this time (replay)
Only events with a higher sequence than this
x >= 01 to 100, default 100
1 <= x <= 100
