Version 1.0.0
Droomwork FLOW ENTERPRISE
Sourcing and screened leads across Nigerian hiring channels.
https://sandbox.droomwork.ioDroomwork-Api-Key: dw_test_… or Authorization: Bearer dw_test_…FLOW gets one vacancy in front of candidates: send us a requisition, we broadcast it to every channel you've configured, and you get back leads who have already answered your knockout questions.
What you should know before you start
This is not a job board. There is no destination candidates visit. Your requisition goes out into other people's channels, and the Droomwork talent pool is one of those channels, not a special case.
Nothing broadcasts on a guess. Where a field was inferred rather than stated, it comes back for you to confirm. Compensation, headcount, location and start date never go out on inference alone, and publishing is refused while any of the four is unconfirmed.
Channel copy cannot invent a fact. Pay figures, employer legal names, statutory claims and requirements in your channel copy are compared against the requisition, exactly. A mismatch fails the render and is logged. Nothing reaches a channel saying something the requisition did not.
Screening is a conversation. The outcome is a rule. Candidates answer your knockout questions conversationally, but pass and fail come from versioned deterministic rules. The screening record shows what was extracted from each answer and what the rules decided as two separate things, so you can see which one you disagree with.
A spend ceiling blocks before anything is computed. When a broadcast would exceed a ceiling, it is refused, and no charge is calculated or debited.
A requisition is versioned, and every lead remembers which version made it. An edit after first broadcast creates a new version. A lead stays bound to the version that produced it, so you can reproduce a shortlist.
Getting started
Create a requisition. Confirm anything that was inferred. Publish it. Read the leads.
Every operation below has two samples: Direct HTTP, with nothing but your language's own client, and Client library, with ours. Same request, same answer; the switch above each sample picks one and remembers it. Which should I use?
/v1/sourcing/requisitions#List requisitions
sourcing.requisitions.list
Returns your requisitions, newest first.
Query parameters
limit
integer
optionalHow many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.
starting_after
string
optionalThe id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.
status
string
optionalOnly requisitions in one state: draft, pending_confirmation (an inferred field awaits confirmation), under_review (a contested case, with a reviewer), quarantined, published or closed. Leave it out to get every state.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedReturns
A page of requisitions.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of Requisition
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
16 fields of Requisition
id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/requisitions (or in requisition_ids on a bulk upload) and pass it as requisition_id on every call about it.
object
always "requisition"
requiredAlways requisition. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredA requisition sits in pending_confirmation while an inferred pay figure, headcount, location or start date is unconfirmed. It cannot leave that state until you confirm.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedversion
integer · minimum 1
requiredAn edit after first broadcast makes a new version. Leads stay on theirs.
job_title
string
requiredThe title of the role as you gave it. The occupation code is inferred from it when you don't send one, so a local or colloquial title is fine.
occupation_code
string
optionalThe occupation this role maps to in the taxonomy, such as ng-7412. Inferred from the title when you didn't send one, and listed in inferred_fields until you confirm it.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date · nullable
optionalThe date the role starts, as YYYY-MM-DD, or null when none is set. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
inferred_fields
array of string
optionalFields that were inferred rather than read from what you sent. Each has to be confirmed, and compensation, headcount, location and start date can never broadcast while they are here.
quarantine
one of
optionalWhy the requisition was held: the rule it tripped, the rule pack version, the detail and the offending text. null when nothing held it; fix what it names before you publish.
QuarantineFindingorcreated_at
string · date-time
optionalWhen the record was created, as an RFC 3339 timestamp in UTC.
has_more
boolean
requiredtrue when there are more records after this page. Pass the last record's id as starting_after to get the next page.
Other responses
Errors it can return
# query parameters: limit (optional), starting_after (optional), status (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/requisitions?limit=25&status=pending_confirmation" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: limit (optional), starting_after (optional), status (optional)
const result = await api.sourcingRequisitionsList({ limit: 25, status: 'pending_confirmation' });// query parameters: limit (optional), starting_after (optional), status (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions?limit=25&status=pending_confirmation', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: limit (optional), starting_after (optional), status (optional)
result = api.sourcing_requisitions_list(limit=25, status='pending_confirmation')import os
import requests
# query parameters: limit (optional), starting_after (optional), status (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/requisitions?limit=25&status=pending_confirmation',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: limit (optional), starting_after (optional), status (optional)
$result = $api->sourcingRequisitionsList(limit: 25, status: 'pending_confirmation');<?php
// query parameters: limit (optional), starting_after (optional), status (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions?limit=25&status=pending_confirmation');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
import com.droomwork.sdk.model.*;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: limit (optional), starting_after (optional), status (optional)
var result = api.sourcingRequisitionsList(25, null, FlowRequisitionStatus.fromValue("pending_confirmation"));// query parameters: limit (optional), starting_after (optional), status (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions?limit=25&status=pending_confirmation"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: limit (optional), starting_after (optional), status (optional)
var result = api.SourcingRequisitionsList(limit: 25, status: FlowRequisitionStatus.PendingConfirmation);// query parameters: limit (optional), starting_after (optional), status (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/requisitions?limit=25&status=pending_confirmation");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: limit (optional), starting_after (optional), status (optional)
result, _, err := client.FLOWAPI.SourcingRequisitionsList(ctx).Limit(25).Status(droomwork.FlowRequisitionStatus("pending_confirmation")).Execute()// query parameters: limit (optional), starting_after (optional), status (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/requisitions?limit=25&status=pending_confirmation", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition",
"livemode": true,
"mocked": true,
"status": "pending_confirmation",
"version": 1,
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"inferred_fields": [
"example"
],
"quarantine": {
"rule_code": "discriminatory_criteria",
"rule_pack_version": "2026.08.1",
"detail": "The payee has no verified destination, so this line cannot be paid.",
"contested": true,
"offending_text": "example"
},
"created_at": "2026-09-01T09:00:00Z"
}
],
"has_more": true
}
/v1/sourcing/requisitions#Create a requisition
sourcing.requisitions.create
You get back the same requisition object whether you create it here, in the dashboard or by bulk upload, and it behaves the same however it arrived.
The job title, occupation code, employment type, headcount, compensation, location, geo-fence radius, start date and knockout criteria are each resolved from what you sent. Anything that had to be inferred is listed on the response for you to confirm.
A requisition carrying discriminatory criteria, unlawful terms or an advance fee pattern is rejected or quarantined. A contested case goes to a person rather than through.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Body
job_title
string
requiredThe title of the role. Any title people use locally works: it is mapped to an occupation code, and the code comes back for you to confirm if you didn't send one.
occupation_code
string
optionalOmit and it is inferred from the title, then returned for confirmation.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. One of the four fields that never broadcast on inference alone.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date
optionalThe date the role starts, as YYYY-MM-DD. If it has to be inferred it comes back in inferred_fields, and it can't broadcast until you confirm it.
knockout_criteria
array of KnockoutRuleInput
optionalThe questions every candidate must answer and the rule that decides pass or fail for each. Asked conversationally; judged by the rule exactly as you wrote it.
2 fields of KnockoutRuleInput
question
string
requiredWhat the candidate is asked. It may be phrased differently in the conversation.
rule
string
requiredThe deterministic test applied to the extracted answer.
description
string
optionalThe role in your own words: duties, requirements, anything a candidate should know. Channel copy is drawn from it, and no copy may claim what the requisition doesn't.
Returns
The requisition, awaiting confirmation of anything inferred.
id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/requisitions (or in requisition_ids on a bulk upload) and pass it as requisition_id on every call about it.
object
always "requisition"
requiredAlways requisition. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredA requisition sits in pending_confirmation while an inferred pay figure, headcount, location or start date is unconfirmed. It cannot leave that state until you confirm.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedversion
integer · minimum 1
requiredAn edit after first broadcast makes a new version. Leads stay on theirs.
job_title
string
requiredThe title of the role as you gave it. The occupation code is inferred from it when you don't send one, so a local or colloquial title is fine.
occupation_code
string
optionalThe occupation this role maps to in the taxonomy, such as ng-7412. Inferred from the title when you didn't send one, and listed in inferred_fields until you confirm it.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date · nullable
optionalThe date the role starts, as YYYY-MM-DD, or null when none is set. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
inferred_fields
array of string
optionalFields that were inferred rather than read from what you sent. Each has to be confirmed, and compensation, headcount, location and start date can never broadcast while they are here.
quarantine
one of
optionalWhy the requisition was held: the rule it tripped, the rule pack version, the detail and the offending text. null when nothing held it; fix what it names before you publish.
QuarantineFindingorcreated_at
string · date-time
optionalWhen the record was created, as an RFC 3339 timestamp in UTC.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/requisitions" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"job_title":"example","headcount":1,"occupation_code":"ng-7412","employment_type":"permanent","compensation":{"amount":{"amount":1234567,"currency":"NGN"},"period":"monthly","negotiable":true},"location":{"description":"example","state":"example","geofence_radius_metres":1},"starts_on":"2026-09-01","knockout_criteria":[{"question":"example","rule":"years_experience >= 3"}],"description":"example"}'import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingRequisitionsCreate({
idempotencyKey: crypto.randomUUID(),
flowRequisitionCreateRequest: {"jobTitle":"example","headcount":1,"occupationCode":"ng-7412","employmentType":"permanent","compensation":{"amount":{"amount":1234567,"currency":"NGN"},"period":"monthly","negotiable":true},"location":{"description":"example","state":"example","geofenceRadiusMetres":1},"startsOn":"2026-09-01","knockoutCriteria":[{"question":"example","rule":"years_experience >= 3"}],"description":"example"},
});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"knockout_criteria": [
{
"question": "example",
"rule": "years_experience >= 3"
}
],
"description": "example"
}),
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_requisitions_create(body={"job_title": "example", "headcount": 1, "occupation_code": "ng-7412", "employment_type": "permanent", "compensation": {"amount": {"amount": 1234567, "currency": "NGN"}, "period": "monthly", "negotiable": True}, "location": {"description": "example", "state": "example", "geofence_radius_metres": 1}, "starts_on": "2026-09-01", "knockout_criteria": [{"question": "example", "rule": "years_experience >= 3"}], "description": "example"})import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/requisitions',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={"job_title": "example", "headcount": 1, "occupation_code": "ng-7412", "employment_type": "permanent", "compensation": {"amount": {"amount": 1234567, "currency": "NGN"}, "period": "monthly", "negotiable": True}, "location": {"description": "example", "state": "example", "geofence_radius_metres": 1}, "starts_on": "2026-09-01", "knockout_criteria": [{"question": "example", "rule": "years_experience >= 3"}], "description": "example"},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingRequisitionsCreate($idempotencyKey, json_decode('{"job_title":"example","headcount":1,"occupation_code":"ng-7412","employment_type":"permanent","compensation":{"amount":{"amount":1234567,"currency":"NGN"},"period":"monthly","negotiable":true},"location":{"description":"example","state":"example","geofence_radius_metres":1},"starts_on":"2026-09-01","knockout_criteria":[{"question":"example","rule":"years_experience >= 3"}],"description":"example"}', true));<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => '{"job_title":"example","headcount":1,"occupation_code":"ng-7412","employment_type":"permanent","compensation":{"amount":{"amount":1234567,"currency":"NGN"},"period":"monthly","negotiable":true},"location":{"description":"example","state":"example","geofence_radius_metres":1},"starts_on":"2026-09-01","knockout_criteria":[{"question":"example","rule":"years_experience >= 3"}],"description":"example"}',
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingRequisitionsCreate(idempotencyKey, body);var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"knockout_criteria": [
{
"question": "example",
"rule": "years_experience >= 3"
}
],
"description": "example"
}
"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingRequisitionsCreate(idempotencyKey, body);using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/requisitions");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
{
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"knockout_criteria": [
{
"question": "example",
"rule": "years_experience >= 3"
}
],
"description": "example"
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingRequisitionsCreate(ctx).IdempotencyKey(key).FlowRequisitionCreateRequest(body).Execute()body := strings.NewReader(`{
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"knockout_criteria": [
{
"question": "example",
"rule": "years_experience >= 3"
}
],
"description": "example"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/requisitions", body)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition",
"livemode": true,
"mocked": true,
"status": "pending_confirmation",
"version": 1,
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"inferred_fields": [
"example"
],
"quarantine": {
"rule_code": "discriminatory_criteria",
"rule_pack_version": "2026.08.1",
"detail": "The payee has no verified destination, so this line cannot be paid.",
"contested": true,
"offending_text": "example"
},
"created_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/requisitions/{requisition_id}#Retrieve a requisition
sourcing.requisitions.retrieve
Returns the requisition at its current version. Pass version to read an earlier one; that's how you read a lead bound to version 2 after version 3 exists.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Query parameters
version
integer
optionalWhich version of the requisition to read, from 1 upward. Leave it out for the current one; pass a lead's requisition_version (from GET /v1/sourcing/leads/{lead_id}) or a broadcast's to read the version that produced it.
Returns
The requisition.
id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/requisitions (or in requisition_ids on a bulk upload) and pass it as requisition_id on every call about it.
object
always "requisition"
requiredAlways requisition. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredA requisition sits in pending_confirmation while an inferred pay figure, headcount, location or start date is unconfirmed. It cannot leave that state until you confirm.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedversion
integer · minimum 1
requiredAn edit after first broadcast makes a new version. Leads stay on theirs.
job_title
string
requiredThe title of the role as you gave it. The occupation code is inferred from it when you don't send one, so a local or colloquial title is fine.
occupation_code
string
optionalThe occupation this role maps to in the taxonomy, such as ng-7412. Inferred from the title when you didn't send one, and listed in inferred_fields until you confirm it.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date · nullable
optionalThe date the role starts, as YYYY-MM-DD, or null when none is set. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
inferred_fields
array of string
optionalFields that were inferred rather than read from what you sent. Each has to be confirmed, and compensation, headcount, location and start date can never broadcast while they are here.
quarantine
one of
optionalWhy the requisition was held: the rule it tripped, the rule pack version, the detail and the offending text. null when nothing held it; fix what it names before you publish.
QuarantineFindingorcreated_at
string · date-time
optionalWhen the record was created, as an RFC 3339 timestamp in UTC.
Other responses
Errors it can return
# query parameters: version (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z?version=1" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: version (optional)
const result = await api.sourcingRequisitionsRetrieve({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', version: 1 });// query parameters: version (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z?version=1', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: version (optional)
result = api.sourcing_requisitions_retrieve(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', version=1)import os
import requests
# query parameters: version (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z?version=1',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: version (optional)
$result = $api->sourcingRequisitionsRetrieve(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', version: 1);<?php
// query parameters: version (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z?version=1');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: version (optional)
var result = api.sourcingRequisitionsRetrieve("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", 1);// query parameters: version (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z?version=1"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: version (optional)
var result = api.SourcingRequisitionsRetrieve(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", version: 1);// query parameters: version (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z?version=1");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: version (optional)
result, _, err := client.FLOWAPI.SourcingRequisitionsRetrieve(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Version(1).Execute()// query parameters: version (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z?version=1", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition",
"livemode": true,
"mocked": true,
"status": "pending_confirmation",
"version": 1,
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"inferred_fields": [
"example"
],
"quarantine": {
"rule_code": "discriminatory_criteria",
"rule_pack_version": "2026.08.1",
"detail": "The payee has no verified destination, so this line cannot be paid.",
"contested": true,
"offending_text": "example"
},
"created_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/requisitions/{requisition_id}/confirm_inferences#Confirm the fields that were inferred
sourcing.requisitions.confirm_inferences
You must do this before you publish. Compensation, headcount, location and start date never broadcast on inference alone, and publish is refused while any inferred field is unconfirmed.
Confirming doesn't mean accepting. If an inference was wrong, send the corrected value here.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Body
confirmations
array of object
requiredOne entry for each field you are confirming: the field's name, whether you accept the inferred value, and the corrected value when you don't. At least one entry.
3 fields
field
string
requiredThe name of the inferred field you are answering for, exactly as it appears in the requisition's inferred_fields.
accepted
boolean
requiredtrue to accept the inferred value as it stands, false to reject it. When you reject, send the right value in corrected_value.
corrected_value
string
optionalSupply this when the inference was wrong.
Returns
The requisition, ready to publish.
id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/requisitions (or in requisition_ids on a bulk upload) and pass it as requisition_id on every call about it.
object
always "requisition"
requiredAlways requisition. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredA requisition sits in pending_confirmation while an inferred pay figure, headcount, location or start date is unconfirmed. It cannot leave that state until you confirm.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedversion
integer · minimum 1
requiredAn edit after first broadcast makes a new version. Leads stay on theirs.
job_title
string
requiredThe title of the role as you gave it. The occupation code is inferred from it when you don't send one, so a local or colloquial title is fine.
occupation_code
string
optionalThe occupation this role maps to in the taxonomy, such as ng-7412. Inferred from the title when you didn't send one, and listed in inferred_fields until you confirm it.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date · nullable
optionalThe date the role starts, as YYYY-MM-DD, or null when none is set. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
inferred_fields
array of string
optionalFields that were inferred rather than read from what you sent. Each has to be confirmed, and compensation, headcount, location and start date can never broadcast while they are here.
quarantine
one of
optionalWhy the requisition was held: the rule it tripped, the rule pack version, the detail and the offending text. null when nothing held it; fix what it names before you publish.
QuarantineFindingorcreated_at
string · date-time
optionalWhen the record was created, as an RFC 3339 timestamp in UTC.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/confirm_inferences" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"confirmations":[{"field":"gross.amount","accepted":true,"corrected_value":"example"}]}'import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingRequisitionsConfirmInferences({
requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
idempotencyKey: crypto.randomUUID(),
flowConfirmInferencesRequest: {"confirmations":[{"field":"gross.amount","accepted":true,"correctedValue":"example"}]},
});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/confirm_inferences', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"confirmations": [
{
"field": "gross.amount",
"accepted": true,
"corrected_value": "example"
}
]
}),
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_requisitions_confirm_inferences(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', body={"confirmations": [{"field": "gross.amount", "accepted": True, "corrected_value": "example"}]})import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/confirm_inferences',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={"confirmations": [{"field": "gross.amount", "accepted": True, "corrected_value": "example"}]},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingRequisitionsConfirmInferences($idempotencyKey, json_decode('{"confirmations":[{"field":"gross.amount","accepted":true,"corrected_value":"example"}]}', true));<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/confirm_inferences');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => '{"confirmations":[{"field":"gross.amount","accepted":true,"corrected_value":"example"}]}',
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingRequisitionsConfirmInferences("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", idempotencyKey, body);var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/confirm_inferences"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"confirmations": [
{
"field": "gross.amount",
"accepted": true,
"corrected_value": "example"
}
]
}
"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingRequisitionsConfirmInferences(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", idempotencyKey, body);using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/confirm_inferences");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
{
"confirmations": [
{
"field": "gross.amount",
"accepted": true,
"corrected_value": "example"
}
]
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingRequisitionsConfirmInferences(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").IdempotencyKey(key).FlowConfirmInferencesRequest(body).Execute()body := strings.NewReader(`{
"confirmations": [
{
"field": "gross.amount",
"accepted": true,
"corrected_value": "example"
}
]
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/confirm_inferences", body)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition",
"livemode": true,
"mocked": true,
"status": "pending_confirmation",
"version": 1,
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"inferred_fields": [
"example"
],
"quarantine": {
"rule_code": "discriminatory_criteria",
"rule_pack_version": "2026.08.1",
"detail": "The payee has no verified destination, so this line cannot be paid.",
"contested": true,
"offending_text": "example"
},
"created_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/requisitions/{requisition_id}/publish#Publish a requisition
sourcing.requisitions.publish
Refused while any inferred field is unconfirmed, and refused while the requisition is quarantined.
Publish again after a first broadcast and you get a new version. Leads you've already captured stay bound to the version that produced them.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Returns
The published requisition.
id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/requisitions (or in requisition_ids on a bulk upload) and pass it as requisition_id on every call about it.
object
always "requisition"
requiredAlways requisition. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredA requisition sits in pending_confirmation while an inferred pay figure, headcount, location or start date is unconfirmed. It cannot leave that state until you confirm.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedversion
integer · minimum 1
requiredAn edit after first broadcast makes a new version. Leads stay on theirs.
job_title
string
requiredThe title of the role as you gave it. The occupation code is inferred from it when you don't send one, so a local or colloquial title is fine.
occupation_code
string
optionalThe occupation this role maps to in the taxonomy, such as ng-7412. Inferred from the title when you didn't send one, and listed in inferred_fields until you confirm it.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date · nullable
optionalThe date the role starts, as YYYY-MM-DD, or null when none is set. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
inferred_fields
array of string
optionalFields that were inferred rather than read from what you sent. Each has to be confirmed, and compensation, headcount, location and start date can never broadcast while they are here.
quarantine
one of
optionalWhy the requisition was held: the rule it tripped, the rule pack version, the detail and the offending text. null when nothing held it; fix what it names before you publish.
QuarantineFindingorcreated_at
string · date-time
optionalWhen the record was created, as an RFC 3339 timestamp in UTC.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/publish" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingRequisitionsPublish({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/publish', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Idempotency-Key': crypto.randomUUID(),
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_requisitions_publish(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/publish',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingRequisitionsPublish(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/publish');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingRequisitionsPublish("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/publish"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingRequisitionsPublish(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/publish");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingRequisitionsPublish(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/publish", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition",
"livemode": true,
"mocked": true,
"status": "pending_confirmation",
"version": 1,
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"inferred_fields": [
"example"
],
"quarantine": {
"rule_code": "discriminatory_criteria",
"rule_pack_version": "2026.08.1",
"detail": "The payee has no verified destination, so this line cannot be paid.",
"contested": true,
"offending_text": "example"
},
"created_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/requisitions/{requisition_id}/close#Close a requisition
sourcing.requisitions.close
Stops further capture. Leads you've already taken stay readable.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Returns
The closed requisition.
id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/requisitions (or in requisition_ids on a bulk upload) and pass it as requisition_id on every call about it.
object
always "requisition"
requiredAlways requisition. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredA requisition sits in pending_confirmation while an inferred pay figure, headcount, location or start date is unconfirmed. It cannot leave that state until you confirm.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedversion
integer · minimum 1
requiredAn edit after first broadcast makes a new version. Leads stay on theirs.
job_title
string
requiredThe title of the role as you gave it. The occupation code is inferred from it when you don't send one, so a local or colloquial title is fine.
occupation_code
string
optionalThe occupation this role maps to in the taxonomy, such as ng-7412. Inferred from the title when you didn't send one, and listed in inferred_fields until you confirm it.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date · nullable
optionalThe date the role starts, as YYYY-MM-DD, or null when none is set. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
inferred_fields
array of string
optionalFields that were inferred rather than read from what you sent. Each has to be confirmed, and compensation, headcount, location and start date can never broadcast while they are here.
quarantine
one of
optionalWhy the requisition was held: the rule it tripped, the rule pack version, the detail and the offending text. null when nothing held it; fix what it names before you publish.
QuarantineFindingorcreated_at
string · date-time
optionalWhen the record was created, as an RFC 3339 timestamp in UTC.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/close" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingRequisitionsClose({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/close', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Idempotency-Key': crypto.randomUUID(),
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_requisitions_close(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/close',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingRequisitionsClose(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/close');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingRequisitionsClose("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/close"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingRequisitionsClose(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/close");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingRequisitionsClose(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/close", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition",
"livemode": true,
"mocked": true,
"status": "pending_confirmation",
"version": 1,
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"inferred_fields": [
"example"
],
"quarantine": {
"rule_code": "discriminatory_criteria",
"rule_pack_version": "2026.08.1",
"detail": "The payee has no verified destination, so this line cannot be paid.",
"contested": true,
"offending_text": "example"
},
"created_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/imports#Upload requisitions in bulk
sourcing.imports.create
Upload a file of requisitions and get the same requisition objects you'd get creating them one at a time. You get a report naming every bad row, not a stop at the first.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Returns
The import, with its validation report.
id
string
requiredThe upload's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/imports and pass it as import_id to read the upload back; the requisitions it created are in requisition_ids.
object
always "requisition_import"
requiredAlways requisition_import. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredWhere the upload is: validating while its rows are checked, pending_acceptance once the report is ready for you, then accepted or rejected as the outcome. Read validation_report for every row that failed and why.
validatingpending_acceptanceacceptedrejectedrequisition_ids
array of string
optionalThe identifier of every requisition the upload created. Each behaves like one you created on its own, and reads at GET /v1/sourcing/requisitions/{requisition_id}.
validation_report
ValidationReport
requiredThe result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.
4 fields of ValidationReport
entry_count
integer · minimum 0
requiredHow many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.
error_count
integer · minimum 0
requiredHow many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.
warning_count
integer · minimum 0
requiredHow many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.
entries
array of object
optionalOne item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.
4 fields
index
integer · minimum 1
requiredThe row in a file, or the line in an instruction set.
severity
string
requirederror means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.
errorwarningcode
string
requiredWhy the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.
detail
string
requiredWhat was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/imports" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingImportsCreate({});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/imports', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Idempotency-Key': crypto.randomUUID(),
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_imports_create()import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/imports',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingImportsCreate();<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/imports');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingImportsCreate();var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/imports"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingImportsCreate();using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/imports");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingImportsCreate(ctx).Execute()req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/imports", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition_import",
"livemode": true,
"mocked": true,
"status": "validating",
"validation_report": {
"entry_count": 0,
"error_count": 0,
"warning_count": 0,
"entries": [
{
"index": 1,
"severity": "error",
"code": "no_payee_destination",
"detail": "The payee has no verified destination, so this line cannot be paid."
}
]
},
"requisition_ids": [
"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
]
}
/v1/sourcing/imports/{import_id}#Retrieve a bulk upload
sourcing.imports.retrieve
Returns your upload with the report naming every row that failed and why.
Path parameters
import_id
string
requiredThe upload's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/imports when you uploaded the file.
Returns
The import.
id
string
requiredThe upload's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/imports and pass it as import_id to read the upload back; the requisitions it created are in requisition_ids.
object
always "requisition_import"
requiredAlways requisition_import. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredWhere the upload is: validating while its rows are checked, pending_acceptance once the report is ready for you, then accepted or rejected as the outcome. Read validation_report for every row that failed and why.
validatingpending_acceptanceacceptedrejectedrequisition_ids
array of string
optionalThe identifier of every requisition the upload created. Each behaves like one you created on its own, and reads at GET /v1/sourcing/requisitions/{requisition_id}.
validation_report
ValidationReport
requiredThe result of checking a submission before anything is committed. Names every failing entry rather than stopping at the first, so one submission tells you everything to fix. The same shape wherever the platform ingests, validates and reports, which is every bulk intake in every module.
4 fields of ValidationReport
entry_count
integer · minimum 0
requiredHow many entries the submission held: every row in the file or line in the instruction set, whether it passed or not.
error_count
integer · minimum 0
requiredHow many entries failed with an error. Each is named in entries with its position and why, so one submission tells you everything to fix.
warning_count
integer · minimum 0
requiredHow many entries passed with a warning, each named in entries. A warning does not fail the entry; it points at something to confirm before you go ahead.
entries
array of object
optionalOne item per error or warning found, with the row or line it sits on, its severity, a code and what was wrong. Empty or absent when every entry passed clean.
4 fields
index
integer · minimum 1
requiredThe row in a file, or the line in an instruction set.
severity
string
requirederror means the entry failed and must be fixed. warning means it passed, but points at something you should confirm before you go ahead.
errorwarningcode
string
requiredWhy the entry was flagged, as a code you can branch on. detail says the same in words and may change; the code does not.
detail
string
requiredWhat was wrong with the entry, in plain words. Show it beside the row; it may change, so branch on code.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/imports/%7Bimport_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingImportsRetrieve({ importId: '{import_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/imports/%7Bimport_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_imports_retrieve(import_id='{import_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/imports/%7Bimport_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingImportsRetrieve(import_id: '{import_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/imports/%7Bimport_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingImportsRetrieve("{import_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/imports/%7Bimport_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingImportsRetrieve(importId: "{import_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/imports/%7Bimport_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingImportsRetrieve(ctx, "{import_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/imports/%7Bimport_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition_import",
"livemode": true,
"mocked": true,
"status": "validating",
"validation_report": {
"entry_count": 0,
"error_count": 0,
"warning_count": 0,
"entries": [
{
"index": 1,
"severity": "error",
"code": "no_payee_destination",
"detail": "The payee has no verified destination, so this line cannot be paid."
}
]
},
"requisition_ids": [
"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
]
}
/v1/sourcing/taxonomies/{taxonomy_id}#Retrieve an occupation taxonomy
sourcing.taxonomies.retrieve
Read how local and colloquial job titles map to occupation codes, so a requisition for a gateman and one for a security officer reach the same people.
The taxonomy is versioned. What a title means changes, and your requisition keeps meaning what it meant.
Path parameters
taxonomy_id
string
requiredThe taxonomy's identifier, starting with flow_enterprise_requisition_: the id on the taxonomy at GET /v1/sourcing/taxonomies/{taxonomy_id}, where your requisitions' occupation codes, such as ng-7412, come from. No call lists taxonomies.
Returns
The taxonomy.
id
string
requiredThe taxonomy's identifier, starting with flow_enterprise_requisition_; it never changes. Pass it as taxonomy_id at GET /v1/sourcing/taxonomies/{taxonomy_id} to read this taxonomy again; version says which version of it you are reading.
object
always "occupation_taxonomy"
requiredAlways occupation_taxonomy. Tells you which kind of record you are looking at, so one handler can read any response.
version
string
requiredWhich version of the taxonomy this is, such as 2026.08.1. What a title means changes between versions, and your requisition keeps meaning what it meant.
entries
array of object
requiredOne entry per occupation: its code, such as ng-7412, the canonical title, and the local and colloquial titles that mean the same thing. This is how a job title becomes an occupation code.
3 fields
occupation_code
string
requiredThe occupation's code, such as ng-7412. Send it as occupation_code on a requisition and you reach the people who know the role by any title in aliases.
canonical_title
string
requiredThe one standard title for this occupation, which every alias resolves to. Use it where you need a single name for a role candidates call many things.
aliases
array of string
requiredLocal and colloquial titles that mean this occupation.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/taxonomies/%7Btaxonomy_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingTaxonomiesRetrieve({ taxonomyId: '{taxonomy_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/taxonomies/%7Btaxonomy_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_taxonomies_retrieve(taxonomy_id='{taxonomy_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/taxonomies/%7Btaxonomy_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingTaxonomiesRetrieve(taxonomy_id: '{taxonomy_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/taxonomies/%7Btaxonomy_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingTaxonomiesRetrieve("{taxonomy_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/taxonomies/%7Btaxonomy_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingTaxonomiesRetrieve(taxonomyId: "{taxonomy_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/taxonomies/%7Btaxonomy_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingTaxonomiesRetrieve(ctx, "{taxonomy_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/taxonomies/%7Btaxonomy_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "occupation_taxonomy",
"version": "2026.08.1",
"entries": [
{
"occupation_code": "ng-7412",
"canonical_title": "example",
"aliases": [
"example"
]
}
]
}
/v1/sourcing/channels#List the channels available to you
sourcing.channels.list
Formal boards, professional networks, alumni portals, campus nodes and the Droomwork talent pool, which is a channel like any other.
Each entry tells you the category, the cost model and your own rolling yield. It does not name the operator behind a channel.
Query parameters
limit
integer
optionalHow many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.
category
string
optionalOnly channels of one category: formal_board, professional_network, alumni_portal, campus_node or talent_pool (the Droomwork talent pool); the category, never the operator behind it. Leave it out to get every category.
formal_boardprofessional_networkalumni_portalcampus_nodetalent_poolpaid
boolean
optionalPass true to list only channels that charge and count against your spend ceilings, false to list only free ones. Leave it out to get both.
Returns
A page of channels.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of Channel
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
10 fields of Channel
id
string
requiredThe channel's identifier, starting with flow_enterprise_broadcast_; it never changes. You get it from GET /v1/sourcing/channels, and it is what you pass as channel_id and name in channel_ids when you broadcast.
object
always "channel"
requiredAlways channel. Tells you which kind of record you are looking at, so one handler can read any response.
category
string
requiredThe category, not the operator. Which platforms sit behind a category is not disclosed.
formal_boardprofessional_networkalumni_portalcampus_nodetalent_poollabel
string
optionalA name for your own reporting. Not the operator behind the channel.
paid
boolean
requiredtrue when posting here is charged and counts against your spend ceilings, false when it is free. cost_model says how it charges.
cost_model
object
optionalHow this channel charges, so a spend ceiling can be reasoned about.
2 fields
basis
string
optionalWhat you are charged for: per_post (each posting), per_click (each click), per_qualified_lead (each lead that passes your knockout rules) or free on a channel that never charges. indicative_unit_cost is roughly what one costs.
per_postper_clickper_qualified_leadfreeindicative_unit_cost
Money
optional2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
quota
object
requiredHow many posts this channel takes from you in a day, and how many of those are left today. Either figure is null where no daily cap applies.
2 fields
posts_per_day
integer · nullable
optionalThe most posts this channel accepts from you in one day. null where no daily cap applies.
remaining_today
integer · nullable
optionalHow many posts you can still make on this channel today, counting down from posts_per_day. null where no daily cap applies.
rolling_yield
object
optionalYour own yield on this channel. Never anyone else's.
2 fields
qualified_lead_rate
number · nullable
optionalThe share of leads from this channel that passed your knockout rules over the last window_days days. Your own figure only, and null when there is nothing to measure yet.
window_days
integer
optionalHow many days the rolling yield is measured over, counted back from today. qualified_lead_rate covers exactly this window.
credentials_held
boolean
optionaltrue when credentials for posting on this channel are on file for your organisation. Without them nothing can post here, and GET /v1/sourcing/readiness lists the channels missing them.
available
boolean
optionaltrue when a broadcast can go to this channel right now, false when it can't. Read it before you name the channel in channel_ids on a broadcast.
has_more
boolean
requiredtrue when there are more records after this page. Pass the last record's id as starting_after to get the next page.
Other responses
Errors it can return
# query parameters: limit (optional), category (optional), paid (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/channels?limit=25&category=formal_board&paid=true" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: limit (optional), category (optional), paid (optional)
const result = await api.sourcingChannelsList({ limit: 25, category: 'formal_board', paid: true });// query parameters: limit (optional), category (optional), paid (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/channels?limit=25&category=formal_board&paid=true', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: limit (optional), category (optional), paid (optional)
result = api.sourcing_channels_list(limit=25, category='formal_board', paid=true)import os
import requests
# query parameters: limit (optional), category (optional), paid (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/channels?limit=25&category=formal_board&paid=true',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: limit (optional), category (optional), paid (optional)
$result = $api->sourcingChannelsList(limit: 25, category: 'formal_board', paid: true);<?php
// query parameters: limit (optional), category (optional), paid (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/channels?limit=25&category=formal_board&paid=true');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
import com.droomwork.sdk.model.*;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: limit (optional), category (optional), paid (optional)
var result = api.sourcingChannelsList(25, FlowChannelCategory.fromValue("formal_board"), true);// query parameters: limit (optional), category (optional), paid (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/channels?limit=25&category=formal_board&paid=true"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: limit (optional), category (optional), paid (optional)
var result = api.SourcingChannelsList(limit: 25, category: FlowChannelCategory.FormalBoard, paid: true);// query parameters: limit (optional), category (optional), paid (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/channels?limit=25&category=formal_board&paid=true");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: limit (optional), category (optional), paid (optional)
result, _, err := client.FLOWAPI.SourcingChannelsList(ctx).Limit(25).Category(droomwork.FlowChannelCategory("formal_board")).Paid(true).Execute()// query parameters: limit (optional), category (optional), paid (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/channels?limit=25&category=formal_board&paid=true", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"id": "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel",
"category": "formal_board",
"paid": true,
"quota": {
"posts_per_day": 1,
"remaining_today": 1
},
"label": "Formal board A",
"cost_model": {
"basis": "per_post",
"indicative_unit_cost": {
"amount": 1234567,
"currency": "NGN"
}
},
"rolling_yield": {
"qualified_lead_rate": 1,
"window_days": 1
},
"credentials_held": true,
"available": true
}
],
"has_more": true
}
/v1/sourcing/channels/{channel_id}#Retrieve a channel
sourcing.channels.retrieve
Returns the channel with its cost model, quota and your rolling yield on it.
Path parameters
channel_id
string
requiredThe channel's identifier, starting with flow_enterprise_broadcast_: the id of a channel listed at GET /v1/sourcing/channels, and the channel_id you see on artefacts, deliveries and leads.
Returns
The channel.
id
string
requiredThe channel's identifier, starting with flow_enterprise_broadcast_; it never changes. You get it from GET /v1/sourcing/channels, and it is what you pass as channel_id and name in channel_ids when you broadcast.
object
always "channel"
requiredAlways channel. Tells you which kind of record you are looking at, so one handler can read any response.
category
string
requiredThe category, not the operator. Which platforms sit behind a category is not disclosed.
formal_boardprofessional_networkalumni_portalcampus_nodetalent_poollabel
string
optionalA name for your own reporting. Not the operator behind the channel.
paid
boolean
requiredtrue when posting here is charged and counts against your spend ceilings, false when it is free. cost_model says how it charges.
cost_model
object
optionalHow this channel charges, so a spend ceiling can be reasoned about.
2 fields
basis
string
optionalWhat you are charged for: per_post (each posting), per_click (each click), per_qualified_lead (each lead that passes your knockout rules) or free on a channel that never charges. indicative_unit_cost is roughly what one costs.
per_postper_clickper_qualified_leadfreeindicative_unit_cost
Money
optional2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
quota
object
requiredHow many posts this channel takes from you in a day, and how many of those are left today. Either figure is null where no daily cap applies.
2 fields
posts_per_day
integer · nullable
optionalThe most posts this channel accepts from you in one day. null where no daily cap applies.
remaining_today
integer · nullable
optionalHow many posts you can still make on this channel today, counting down from posts_per_day. null where no daily cap applies.
rolling_yield
object
optionalYour own yield on this channel. Never anyone else's.
2 fields
qualified_lead_rate
number · nullable
optionalThe share of leads from this channel that passed your knockout rules over the last window_days days. Your own figure only, and null when there is nothing to measure yet.
window_days
integer
optionalHow many days the rolling yield is measured over, counted back from today. qualified_lead_rate covers exactly this window.
credentials_held
boolean
optionaltrue when credentials for posting on this channel are on file for your organisation. Without them nothing can post here, and GET /v1/sourcing/readiness lists the channels missing them.
available
boolean
optionaltrue when a broadcast can go to this channel right now, false when it can't. Read it before you name the channel in channel_ids on a broadcast.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/channels/%7Bchannel_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingChannelsRetrieve({ channelId: '{channel_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/channels/%7Bchannel_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_channels_retrieve(channel_id='{channel_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/channels/%7Bchannel_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingChannelsRetrieve(channel_id: '{channel_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/channels/%7Bchannel_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingChannelsRetrieve("{channel_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/channels/%7Bchannel_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingChannelsRetrieve(channelId: "{channel_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/channels/%7Bchannel_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingChannelsRetrieve(ctx, "{channel_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/channels/%7Bchannel_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel",
"category": "formal_board",
"paid": true,
"quota": {
"posts_per_day": 1,
"remaining_today": 1
},
"label": "Formal board A",
"cost_model": {
"basis": "per_post",
"indicative_unit_cost": {
"amount": 1234567,
"currency": "NGN"
}
},
"rolling_yield": {
"qualified_lead_rate": 1,
"window_days": 1
},
"credentials_held": true,
"available": true
}
/v1/sourcing/requisitions/{requisition_id}/artefacts#List the generated channel artefacts
sourcing.artefacts.list
Your requisition produces a full set of channel copy, one piece sized and shaped for each destination. Preview and edit it here before anything goes out.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Query parameters
limit
integer
optionalHow many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.
Returns
A page of artefacts.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of Artefact
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
7 fields of Artefact
id
string
requiredThe artefact's identifier; it never changes. You get it from GET /v1/sourcing/requisitions/{requisition_id}/artefacts and pass it as artefact_id to retrieve or edit this copy under the same requisition.
object
always "channel_artefact"
requiredAlways channel_artefact. Tells you which kind of record you are looking at, so one handler can read any response.
channel_id
string
requiredThe channel this copy was written for: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. Each artefact is sized and shaped for one destination, and a broadcast to that channel sends this copy.
headline
string
optionalThe title line of the copy as it will appear on this channel. You can change it with PATCH while editable is true.
body
string
requiredThe text of the advert as it will go out on this channel. Every pay figure, employer legal name, statutory claim and requirement in it is compared with your requisition; see fact_check.
fact_check
FactCheck
requiredThe result of comparing this copy against the requisition. Pay figures, employer legal names, statutory claims and requirements must match exactly. A mismatch fails the render and is logged rather than corrected quietly.
3 fields of FactCheck
passed
boolean
requiredtrue when every claim in checks agrees with the requisition. false when any one differs, and that copy does not reach the channel.
checks
array of object
requiredOne entry per claim compared, giving what the requisition says, what the copy says and whether they agree. Read it to see exactly which claim failed.
4 fields
claim
string
requiredWhich kind of fact was compared: pay_figure, employer_legal_name, statutory_claim (a claim about what the law provides) or requirement. All four must match the requisition exactly.
pay_figureemployer_legal_namestatutory_claimrequirementin_requisition
string
requiredThe value as your requisition states it. This is the side that wins: the copy has to say this, never the other way round.
in_content
string
requiredThe value as the copy says it. Where it differs from in_requisition, agrees is false and the copy fails.
agrees
boolean
requiredtrue when in_content matches in_requisition exactly. One false here fails the whole check, and the copy with it.
failed_at
string · date-time · nullable
optionalWhen this copy last failed the check, as an RFC 3339 timestamp in UTC. null when it has never failed.
editable
boolean
optionalFalse once the broadcast has gone out on this channel.
has_more
boolean
requiredtrue when there are more records after this page. Pass the last record's id as starting_after to get the next page.
Other responses
Errors it can return
# query parameters: limit (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts?limit=25" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: limit (optional)
const result = await api.sourcingArtefactsList({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit: 25 });// query parameters: limit (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts?limit=25', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: limit (optional)
result = api.sourcing_artefacts_list(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit=25)import os
import requests
# query parameters: limit (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts?limit=25',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: limit (optional)
$result = $api->sourcingArtefactsList(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', limit: 25);<?php
// query parameters: limit (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts?limit=25');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: limit (optional)
var result = api.sourcingArtefactsList("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", 25);// query parameters: limit (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts?limit=25"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: limit (optional)
var result = api.SourcingArtefactsList(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", limit: 25);// query parameters: limit (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts?limit=25");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: limit (optional)
result, _, err := client.FLOWAPI.SourcingArtefactsList(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Limit(25).Execute()// query parameters: limit (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts?limit=25", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_artefact",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"body": "example",
"fact_check": {
"passed": true,
"checks": [
{
"claim": "pay_figure",
"in_requisition": "example",
"in_content": "example",
"agrees": true
}
],
"failed_at": "2026-09-01T09:00:00Z"
},
"headline": "example",
"editable": true
}
],
"has_more": true
}
/v1/sourcing/requisitions/{requisition_id}/artefacts/{artefact_id}#Retrieve an artefact
sourcing.artefacts.retrieve
Returns the copy with the result of checking it against your requisition.
Pay figures, employer legal names, statutory claims and requirements are compared exactly. A mismatch fails the render, and the failure is recorded here rather than corrected silently.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
artefact_id
string
requiredThe artefact's identifier: the id of an artefact listed at GET /v1/sourcing/requisitions/{requisition_id}/artefacts, under the same requisition you name in this path.
Returns
The artefact.
id
string
requiredThe artefact's identifier; it never changes. You get it from GET /v1/sourcing/requisitions/{requisition_id}/artefacts and pass it as artefact_id to retrieve or edit this copy under the same requisition.
object
always "channel_artefact"
requiredAlways channel_artefact. Tells you which kind of record you are looking at, so one handler can read any response.
channel_id
string
requiredThe channel this copy was written for: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. Each artefact is sized and shaped for one destination, and a broadcast to that channel sends this copy.
headline
string
optionalThe title line of the copy as it will appear on this channel. You can change it with PATCH while editable is true.
body
string
requiredThe text of the advert as it will go out on this channel. Every pay figure, employer legal name, statutory claim and requirement in it is compared with your requisition; see fact_check.
fact_check
FactCheck
requiredThe result of comparing this copy against the requisition. Pay figures, employer legal names, statutory claims and requirements must match exactly. A mismatch fails the render and is logged rather than corrected quietly.
3 fields of FactCheck
passed
boolean
requiredtrue when every claim in checks agrees with the requisition. false when any one differs, and that copy does not reach the channel.
checks
array of object
requiredOne entry per claim compared, giving what the requisition says, what the copy says and whether they agree. Read it to see exactly which claim failed.
4 fields
claim
string
requiredWhich kind of fact was compared: pay_figure, employer_legal_name, statutory_claim (a claim about what the law provides) or requirement. All four must match the requisition exactly.
pay_figureemployer_legal_namestatutory_claimrequirementin_requisition
string
requiredThe value as your requisition states it. This is the side that wins: the copy has to say this, never the other way round.
in_content
string
requiredThe value as the copy says it. Where it differs from in_requisition, agrees is false and the copy fails.
agrees
boolean
requiredtrue when in_content matches in_requisition exactly. One false here fails the whole check, and the copy with it.
failed_at
string · date-time · nullable
optionalWhen this copy last failed the check, as an RFC 3339 timestamp in UTC. null when it has never failed.
editable
boolean
optionalFalse once the broadcast has gone out on this channel.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingArtefactsRetrieve({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', artefactId: '{artefact_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_artefacts_retrieve(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', artefact_id='{artefact_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingArtefactsRetrieve(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', artefact_id: '{artefact_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingArtefactsRetrieve("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{artefact_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingArtefactsRetrieve(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", artefactId: "{artefact_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingArtefactsRetrieve(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{artefact_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_artefact",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"body": "example",
"fact_check": {
"passed": true,
"checks": [
{
"claim": "pay_figure",
"in_requisition": "example",
"in_content": "example",
"agrees": true
}
],
"failed_at": "2026-09-01T09:00:00Z"
},
"headline": "example",
"editable": true
}
/v1/sourcing/requisitions/{requisition_id}/artefacts/{artefact_id}#Edit an artefact before broadcast
sourcing.artefacts.update
Your edit is checked against the requisition the same way the generated copy is. You can't introduce a pay figure the requisition doesn't carry.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
artefact_id
string
requiredThe artefact's identifier: the id of an artefact listed at GET /v1/sourcing/requisitions/{requisition_id}/artefacts, under the same requisition you name in this path.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Body
headline
string
optionalThe new title line for this channel's copy; leave it out to keep the current one. It is checked against the requisition the same way generated copy is.
body
string
optionalThe new text of the advert for this channel; leave it out to keep the current one. A pay figure, employer legal name, statutory claim or requirement the requisition doesn't carry fails the check.
Returns
The updated artefact.
id
string
requiredThe artefact's identifier; it never changes. You get it from GET /v1/sourcing/requisitions/{requisition_id}/artefacts and pass it as artefact_id to retrieve or edit this copy under the same requisition.
object
always "channel_artefact"
requiredAlways channel_artefact. Tells you which kind of record you are looking at, so one handler can read any response.
channel_id
string
requiredThe channel this copy was written for: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. Each artefact is sized and shaped for one destination, and a broadcast to that channel sends this copy.
headline
string
optionalThe title line of the copy as it will appear on this channel. You can change it with PATCH while editable is true.
body
string
requiredThe text of the advert as it will go out on this channel. Every pay figure, employer legal name, statutory claim and requirement in it is compared with your requisition; see fact_check.
fact_check
FactCheck
requiredThe result of comparing this copy against the requisition. Pay figures, employer legal names, statutory claims and requirements must match exactly. A mismatch fails the render and is logged rather than corrected quietly.
3 fields of FactCheck
passed
boolean
requiredtrue when every claim in checks agrees with the requisition. false when any one differs, and that copy does not reach the channel.
checks
array of object
requiredOne entry per claim compared, giving what the requisition says, what the copy says and whether they agree. Read it to see exactly which claim failed.
4 fields
claim
string
requiredWhich kind of fact was compared: pay_figure, employer_legal_name, statutory_claim (a claim about what the law provides) or requirement. All four must match the requisition exactly.
pay_figureemployer_legal_namestatutory_claimrequirementin_requisition
string
requiredThe value as your requisition states it. This is the side that wins: the copy has to say this, never the other way round.
in_content
string
requiredThe value as the copy says it. Where it differs from in_requisition, agrees is false and the copy fails.
agrees
boolean
requiredtrue when in_content matches in_requisition exactly. One false here fails the whole check, and the copy with it.
failed_at
string · date-time · nullable
optionalWhen this copy last failed the check, as an RFC 3339 timestamp in UTC. null when it has never failed.
editable
boolean
optionalFalse once the broadcast has gone out on this channel.
Other responses
Errors it can return
curl -X PATCH "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"headline":"example","body":"example"}'import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingArtefactsUpdate({
requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
artefactId: '{artefact_id}',
idempotencyKey: crypto.randomUUID(),
flowArtefactUpdateRequest: {"headline":"example","body":"example"},
});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D', {
method: 'PATCH',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"headline": "example",
"body": "example"
}),
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_artefacts_update(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', artefact_id='{artefact_id}', body={"headline": "example", "body": "example"})import os
import uuid
import requests
response = requests.request(
'PATCH',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={"headline": "example", "body": "example"},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingArtefactsUpdate($idempotencyKey, json_decode('{"headline":"example","body":"example"}', true));<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => '{"headline":"example","body":"example"}',
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingArtefactsUpdate("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{artefact_id}", idempotencyKey, body);var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("PATCH", HttpRequest.BodyPublishers.ofString("""
{
"headline": "example",
"body": "example"
}
"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingArtefactsUpdate(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", artefactId: "{artefact_id}", idempotencyKey, body);using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Patch, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
{
"headline": "example",
"body": "example"
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingArtefactsUpdate(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{artefact_id}").IdempotencyKey(key).FlowArtefactUpdateRequest(body).Execute()body := strings.NewReader(`{
"headline": "example",
"body": "example"
}`)
req, _ := http.NewRequest("PATCH", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/artefacts/%7Bartefact_id%7D", body)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_artefact",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"body": "example",
"fact_check": {
"passed": true,
"checks": [
{
"claim": "pay_figure",
"in_requisition": "example",
"in_content": "example",
"agrees": true
}
],
"failed_at": "2026-09-01T09:00:00Z"
},
"headline": "example",
"editable": true
}
/v1/sourcing/requisitions/{requisition_id}/broadcasts#Broadcast a requisition across every configured channel
sourcing.broadcasts.create
The broadcast is accepted and then runs, each channel independent of the others. A channel that fails is retried on its own schedule, and when the retries run out it reaches a terminal failure you are told about. No channel is ever dropped quietly.
Your spend ceilings are checked first. If a paid channel would breach one, the broadcast is refused and no charge is calculated or debited.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Body optional
channel_ids
array of string
optionalDefaults to every channel configured for your organisation.
Returns
Broadcast accepted. Watch the deliveries.
id
string
requiredThe broadcast's identifier, starting with flow_enterprise_broadcast_; it never changes. You get it from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts and pass it as broadcast_id to read it, retry a delivery or filter deliveries.
object
always "broadcast"
requiredAlways broadcast. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
requisition_id
string
requiredThe requisition this broadcast sent out: its id, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. It is the one you named in the path when you created the broadcast, returned so the record stands on its own.
requisition_version
integer
requiredWhich version of the requisition went out: its version at the moment you broadcast. Leads from this broadcast stay bound to it, so you can reproduce a shortlist.
deliveries
array of Delivery
requiredOne delivery per channel the broadcast went to, each with its own state, attempt count and fault. A channel that failed is listed here as failed, never dropped.
10 fields of Delivery
id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_; it never changes. It is in a broadcast's deliveries, at GET /v1/sourcing/deliveries and from POST /v1/sourcing/deliveries; pass it as delivery_id to read or retry it.
object
always "channel_delivery"
requiredAlways channel_delivery. Tells you which kind of record you are looking at, so one handler can read any response.
broadcast_id
string
requiredThe broadcast this delivery is part of: the id, starting with flow_enterprise_broadcast_, from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, or the one you named as broadcast_id at POST /v1/sourcing/deliveries.
requisition_id
string
optionalThe requisition this delivery carried: the id of the requisition behind the broadcast, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. Filter GET /v1/sourcing/deliveries by it to see every channel it went to.
channel_id
string
requiredThe channel this delivery went to: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. One delivery covers one channel, so a broadcast has one delivery per channel it went to.
state
string
requiredfailed is terminal and always reported. A channel you selected is never dropped silently.
queuedsendingdeliveredretryingfailedattempts
integer · minimum 0
requiredHow many times posting to this channel has been tried so far, 0 before the first try. Read it with state and last_fault to see how a channel is doing.
next_attempt_at
string · date-time · nullable
optionalExponential backoff. Absent once the state is terminal.
last_fault
string · nullable
optionalWhy the most recent attempt at this channel failed, in plain words; null while nothing has failed. Read it before you retry.
external_reference
string · nullable
optionalThe channel's own reference for this posting, where the channel gives one. null otherwise, so name the delivery by id, never by this.
started_at
string · date-time
optionalWhen the broadcast started running, as an RFC 3339 timestamp in UTC. Each channel then runs on its own, so read deliveries for how far each one got.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/broadcasts" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"channel_ids":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}'import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingBroadcastsCreate({
requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
idempotencyKey: crypto.randomUUID(),
flowBroadcastCreateRequest: {"channelIds":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]},
});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/broadcasts', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"channel_ids": [
"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
]
}),
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_broadcasts_create(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', body={"channel_ids": ["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]})import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/broadcasts',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={"channel_ids": ["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingBroadcastsCreate($idempotencyKey, json_decode('{"channel_ids":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}', true));<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/broadcasts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => '{"channel_ids":["sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"]}',
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingBroadcastsCreate("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", idempotencyKey, body);var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/broadcasts"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"channel_ids": [
"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
]
}
"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingBroadcastsCreate(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", idempotencyKey, body);using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/broadcasts");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
{
"channel_ids": [
"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
]
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingBroadcastsCreate(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").IdempotencyKey(key).FlowBroadcastCreateRequest(body).Execute()body := strings.NewReader(`{
"channel_ids": [
"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
]
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/broadcasts", body)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "broadcast",
"livemode": true,
"mocked": true,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"requisition_version": 1,
"deliveries": [
{
"id": "flow_enterprise_delivery_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_delivery",
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"state": "queued",
"attempts": 0,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"next_attempt_at": "2026-09-01T09:00:00Z",
"last_fault": "The register did not answer within the timeout.",
"external_reference": "paye-2026-09-rivers"
}
],
"started_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/broadcasts/{broadcast_id}#Retrieve a broadcast
sourcing.broadcasts.retrieve
Returns the broadcast with the state of every channel it went to.
Path parameters
broadcast_id
string
requiredThe broadcast's identifier, starting with flow_enterprise_broadcast_: the id returned by POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, also carried as broadcast_id on every delivery.
Returns
The broadcast.
id
string
requiredThe broadcast's identifier, starting with flow_enterprise_broadcast_; it never changes. You get it from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts and pass it as broadcast_id to read it, retry a delivery or filter deliveries.
object
always "broadcast"
requiredAlways broadcast. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
requisition_id
string
requiredThe requisition this broadcast sent out: its id, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. It is the one you named in the path when you created the broadcast, returned so the record stands on its own.
requisition_version
integer
requiredWhich version of the requisition went out: its version at the moment you broadcast. Leads from this broadcast stay bound to it, so you can reproduce a shortlist.
deliveries
array of Delivery
requiredOne delivery per channel the broadcast went to, each with its own state, attempt count and fault. A channel that failed is listed here as failed, never dropped.
10 fields of Delivery
id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_; it never changes. It is in a broadcast's deliveries, at GET /v1/sourcing/deliveries and from POST /v1/sourcing/deliveries; pass it as delivery_id to read or retry it.
object
always "channel_delivery"
requiredAlways channel_delivery. Tells you which kind of record you are looking at, so one handler can read any response.
broadcast_id
string
requiredThe broadcast this delivery is part of: the id, starting with flow_enterprise_broadcast_, from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, or the one you named as broadcast_id at POST /v1/sourcing/deliveries.
requisition_id
string
optionalThe requisition this delivery carried: the id of the requisition behind the broadcast, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. Filter GET /v1/sourcing/deliveries by it to see every channel it went to.
channel_id
string
requiredThe channel this delivery went to: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. One delivery covers one channel, so a broadcast has one delivery per channel it went to.
state
string
requiredfailed is terminal and always reported. A channel you selected is never dropped silently.
queuedsendingdeliveredretryingfailedattempts
integer · minimum 0
requiredHow many times posting to this channel has been tried so far, 0 before the first try. Read it with state and last_fault to see how a channel is doing.
next_attempt_at
string · date-time · nullable
optionalExponential backoff. Absent once the state is terminal.
last_fault
string · nullable
optionalWhy the most recent attempt at this channel failed, in plain words; null while nothing has failed. Read it before you retry.
external_reference
string · nullable
optionalThe channel's own reference for this posting, where the channel gives one. null otherwise, so name the delivery by id, never by this.
started_at
string · date-time
optionalWhen the broadcast started running, as an RFC 3339 timestamp in UTC. Each channel then runs on its own, so read deliveries for how far each one got.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingBroadcastsRetrieve({ broadcastId: 'flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_broadcasts_retrieve(broadcast_id='flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingBroadcastsRetrieve(broadcast_id: 'flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingBroadcastsRetrieve("flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingBroadcastsRetrieve(broadcastId: "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingBroadcastsRetrieve(ctx, "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "broadcast",
"livemode": true,
"mocked": true,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"requisition_version": 1,
"deliveries": [
{
"id": "flow_enterprise_delivery_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_delivery",
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"state": "queued",
"attempts": 0,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"next_attempt_at": "2026-09-01T09:00:00Z",
"last_fault": "The register did not answer within the timeout.",
"external_reference": "paye-2026-09-rivers"
}
],
"started_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/broadcasts/{broadcast_id}/deliveries/{delivery_id}/retry#Retry a failed delivery
sourcing.deliveries.retry
Retries one channel without touching the others.
Path parameters
broadcast_id
string
requiredThe broadcast's identifier, starting with flow_enterprise_broadcast_: the id returned by POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, also carried as broadcast_id on every delivery.
delivery_id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_: the id of an entry in deliveries on a broadcast, of a delivery listed at GET /v1/sourcing/deliveries, or of one you recorded at POST /v1/sourcing/deliveries.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Returns
Retry accepted.
id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_; it never changes. It is in a broadcast's deliveries, at GET /v1/sourcing/deliveries and from POST /v1/sourcing/deliveries; pass it as delivery_id to read or retry it.
object
always "channel_delivery"
requiredAlways channel_delivery. Tells you which kind of record you are looking at, so one handler can read any response.
broadcast_id
string
requiredThe broadcast this delivery is part of: the id, starting with flow_enterprise_broadcast_, from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, or the one you named as broadcast_id at POST /v1/sourcing/deliveries.
requisition_id
string
optionalThe requisition this delivery carried: the id of the requisition behind the broadcast, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. Filter GET /v1/sourcing/deliveries by it to see every channel it went to.
channel_id
string
requiredThe channel this delivery went to: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. One delivery covers one channel, so a broadcast has one delivery per channel it went to.
state
string
requiredfailed is terminal and always reported. A channel you selected is never dropped silently.
queuedsendingdeliveredretryingfailedattempts
integer · minimum 0
requiredHow many times posting to this channel has been tried so far, 0 before the first try. Read it with state and last_fault to see how a channel is doing.
next_attempt_at
string · date-time · nullable
optionalExponential backoff. Absent once the state is terminal.
last_fault
string · nullable
optionalWhy the most recent attempt at this channel failed, in plain words; null while nothing has failed. Read it before you retry.
external_reference
string · nullable
optionalThe channel's own reference for this posting, where the channel gives one. null otherwise, so name the delivery by id, never by this.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/deliveries/%7Bdelivery_id%7D/retry" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingDeliveriesRetry({ broadcastId: 'flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', deliveryId: '{delivery_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/deliveries/%7Bdelivery_id%7D/retry', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Idempotency-Key': crypto.randomUUID(),
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_deliveries_retry(broadcast_id='flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', delivery_id='{delivery_id}')import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/deliveries/%7Bdelivery_id%7D/retry',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingDeliveriesRetry(broadcast_id: 'flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', delivery_id: '{delivery_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/deliveries/%7Bdelivery_id%7D/retry');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingDeliveriesRetry("flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{delivery_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/deliveries/%7Bdelivery_id%7D/retry"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingDeliveriesRetry(broadcastId: "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", deliveryId: "{delivery_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/deliveries/%7Bdelivery_id%7D/retry");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingDeliveriesRetry(ctx, "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "{delivery_id}").Execute()req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/broadcasts/flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/deliveries/%7Bdelivery_id%7D/retry", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_delivery_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_delivery",
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"state": "queued",
"attempts": 0,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"next_attempt_at": "2026-09-01T09:00:00Z",
"last_fault": "The register did not answer within the timeout.",
"external_reference": "paye-2026-09-rivers"
}
/v1/sourcing/deliveries#List deliveries
sourcing.deliveries.list
One delivery per channel per broadcast, each with its own state, attempts and terminal outcome. Filter by broadcast to see one send, or leave it off to find every failure across your requisitions.
A failed channel is always reported rather than dropped, and this is where you find it.
Query parameters
limit
integer
optionalHow many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.
starting_after
string
optionalThe id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.
broadcast_id
string
optionalOne broadcast's deliveries, one per channel it went to: pass the broadcast's id, starting with flow_enterprise_broadcast_, from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts. Leave it out to get deliveries from every broadcast.
requisition_id
string
optionalOnly deliveries for one requisition, across every broadcast of it: pass the requisition's id, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. Leave it out to get deliveries for every requisition.
state
string
optionalRestricts the list to one state: queued (not yet tried), sending, delivered, retrying (failed, another try is scheduled) or failed (terminal, the channel was never reached). Leave it out to get every delivery, whatever its state.
queuedsendingdeliveredretryingfailedReturns
A page of deliveries.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of Delivery
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
10 fields of Delivery
id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_; it never changes. It is in a broadcast's deliveries, at GET /v1/sourcing/deliveries and from POST /v1/sourcing/deliveries; pass it as delivery_id to read or retry it.
object
always "channel_delivery"
requiredAlways channel_delivery. Tells you which kind of record you are looking at, so one handler can read any response.
broadcast_id
string
requiredThe broadcast this delivery is part of: the id, starting with flow_enterprise_broadcast_, from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, or the one you named as broadcast_id at POST /v1/sourcing/deliveries.
requisition_id
string
optionalThe requisition this delivery carried: the id of the requisition behind the broadcast, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. Filter GET /v1/sourcing/deliveries by it to see every channel it went to.
channel_id
string
requiredThe channel this delivery went to: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. One delivery covers one channel, so a broadcast has one delivery per channel it went to.
state
string
requiredfailed is terminal and always reported. A channel you selected is never dropped silently.
queuedsendingdeliveredretryingfailedattempts
integer · minimum 0
requiredHow many times posting to this channel has been tried so far, 0 before the first try. Read it with state and last_fault to see how a channel is doing.
next_attempt_at
string · date-time · nullable
optionalExponential backoff. Absent once the state is terminal.
last_fault
string · nullable
optionalWhy the most recent attempt at this channel failed, in plain words; null while nothing has failed. Read it before you retry.
external_reference
string · nullable
optionalThe channel's own reference for this posting, where the channel gives one. null otherwise, so name the delivery by id, never by this.
has_more
boolean
requiredtrue when there are more records after this page. Pass the last record's id as starting_after to get the next page.
Other responses
Errors it can return
# query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/deliveries?limit=25&broadcast_id=flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&state=queued" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
const result = await api.sourcingDeliveriesList({ limit: 25, broadcastId: 'flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', state: 'queued' });// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/deliveries?limit=25&broadcast_id=flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&state=queued', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
result = api.sourcing_deliveries_list(limit=25, broadcast_id='flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', state='queued')import os
import requests
# query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/deliveries?limit=25&broadcast_id=flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&state=queued',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
$result = $api->sourcingDeliveriesList(limit: 25, broadcast_id: 'flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', state: 'queued');<?php
// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/deliveries?limit=25&broadcast_id=flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&state=queued');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
import com.droomwork.sdk.model.*;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
var result = api.sourcingDeliveriesList(25, null, "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", FlowDeliveryState.fromValue("queued"));// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/deliveries?limit=25&broadcast_id=flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&state=queued"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
var result = api.SourcingDeliveriesList(limit: 25, broadcastId: "flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", state: FlowDeliveryState.Queued);// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/deliveries?limit=25&broadcast_id=flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&state=queued");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
result, _, err := client.FLOWAPI.SourcingDeliveriesList(ctx).Limit(25).BroadcastId("flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").RequisitionId("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").State(droomwork.FlowDeliveryState("queued")).Execute()// query parameters: limit (optional), starting_after (optional), broadcast_id (optional), requisition_id (optional), state (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/deliveries?limit=25&broadcast_id=flow_enterprise_broadcast_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&state=queued", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"id": "flow_enterprise_delivery_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_delivery",
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"state": "queued",
"attempts": 0,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"next_attempt_at": "2026-09-01T09:00:00Z",
"last_fault": "The register did not answer within the timeout.",
"external_reference": "paye-2026-09-rivers"
}
],
"has_more": true
}
/v1/sourcing/deliveries#Record a channel delivery
sourcing.deliveries.create
Deliveries normally appear when a broadcast runs. Record one directly when you posted by hand on a channel we can't reach, so that posting counts in attribution like the rest.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Body optional
broadcast_id
string
optionalThe broadcast this delivery belongs to: the id of a broadcast you created at POST /v1/sourcing/requisitions/{requisition_id}/broadcasts or read at GET /v1/sourcing/broadcasts/{broadcast_id}. It starts with flow_enterprise_broadcast_.
channel_id
string
optionalThe channel you posted on by hand: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. The posting then counts in attribution like every other delivery.
Returns
The delivery.
id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_; it never changes. It is in a broadcast's deliveries, at GET /v1/sourcing/deliveries and from POST /v1/sourcing/deliveries; pass it as delivery_id to read or retry it.
object
always "channel_delivery"
requiredAlways channel_delivery. Tells you which kind of record you are looking at, so one handler can read any response.
broadcast_id
string
requiredThe broadcast this delivery is part of: the id, starting with flow_enterprise_broadcast_, from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, or the one you named as broadcast_id at POST /v1/sourcing/deliveries.
requisition_id
string
optionalThe requisition this delivery carried: the id of the requisition behind the broadcast, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. Filter GET /v1/sourcing/deliveries by it to see every channel it went to.
channel_id
string
requiredThe channel this delivery went to: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. One delivery covers one channel, so a broadcast has one delivery per channel it went to.
state
string
requiredfailed is terminal and always reported. A channel you selected is never dropped silently.
queuedsendingdeliveredretryingfailedattempts
integer · minimum 0
requiredHow many times posting to this channel has been tried so far, 0 before the first try. Read it with state and last_fault to see how a channel is doing.
next_attempt_at
string · date-time · nullable
optionalExponential backoff. Absent once the state is terminal.
last_fault
string · nullable
optionalWhy the most recent attempt at this channel failed, in plain words; null while nothing has failed. Read it before you retry.
external_reference
string · nullable
optionalThe channel's own reference for this posting, where the channel gives one. null otherwise, so name the delivery by id, never by this.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/deliveries" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"broadcast_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","channel_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}'import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingDeliveriesCreate({});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/deliveries', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}),
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_deliveries_create()import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/deliveries',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingDeliveriesCreate();<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/deliveries');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => '{"broadcast_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","channel_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}',
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingDeliveriesCreate();var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/deliveries"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}
"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingDeliveriesCreate();using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/deliveries");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
{
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingDeliveriesCreate(ctx).Execute()body := strings.NewReader(`{
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/deliveries", body)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_delivery_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_delivery",
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"state": "queued",
"attempts": 0,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"next_attempt_at": "2026-09-01T09:00:00Z",
"last_fault": "The register did not answer within the timeout.",
"external_reference": "paye-2026-09-rivers"
}
/v1/sourcing/spend_ceilings#Retrieve your spend ceilings
sourcing.spend_ceilings.retrieve
A ceiling per requisition and a ceiling for your organisation. Both are checked before any paid channel runs.
When one would be breached, the broadcast is blocked and no charge is computed. The ceilings and what you've consumed come from your wallet.
Returns
The ceilings and what has been consumed.
object
always "spend_ceilings"
requiredAlways spend_ceilings. Tells you which kind of record you are looking at, so one handler can read any response.
organisation
object
requiredYour organisation's ceiling on paid channel spend across every requisition, and what you've consumed against it. Checked before any paid channel runs.
2 fields
ceiling
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
consumed
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
per_requisition
array of object
optionalOne entry per requisition with its own ceiling, and what's been consumed against it. A broadcast is checked against the requisition's ceiling and your organisation's, and either can block it.
3 fields
requisition_id
string
requiredThe requisition this ceiling applies to: the id of one of your requisitions, from POST /v1/sourcing/requisitions or GET /v1/sourcing/requisitions. It starts with flow_enterprise_requisition_.
ceiling
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
consumed
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/spend_ceilings" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingSpendCeilingsRetrieve({});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/spend_ceilings', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_spend_ceilings_retrieve()import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/spend_ceilings',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingSpendCeilingsRetrieve();<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/spend_ceilings');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingSpendCeilingsRetrieve();var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/spend_ceilings"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingSpendCeilingsRetrieve();using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/spend_ceilings");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingSpendCeilingsRetrieve(ctx).Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/spend_ceilings", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "spend_ceilings",
"organisation": {
"ceiling": {
"amount": 1234567,
"currency": "NGN"
},
"consumed": {
"amount": 1234567,
"currency": "NGN"
}
},
"per_requisition": [
{
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"ceiling": {
"amount": 1234567,
"currency": "NGN"
},
"consumed": {
"amount": 1234567,
"currency": "NGN"
}
}
]
}
/v1/sourcing/requisitions/{requisition_id}/capture_links#Create a capture link for a channel
sourcing.capture_links.create
The link a candidate follows. Its token is opaque and can't be enumerated, and no personally identifying data ever appears in a query parameter. A link gets pasted into places you don't control.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Body
channel_id
string
requiredThe channel this link is for: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. Every lead who follows the link is attributed to this channel.
expires_at
string · date-time
optionalWhen the link stops working, as an RFC 3339 timestamp in UTC. Omit it for a link with no expiry.
Returns
The capture link.
id
string
requiredThe capture link's identifier. It starts with flow_enterprise_lead_ and never changes; pass it as capture_link_id at GET /v1/sourcing/capture_links/{capture_link_id}, and read it back on a lead's attribution.
object
always "capture_link"
requiredAlways capture_link. Tells you which kind of record you are looking at, so one handler can read any response.
requisition_id
string
requiredThe requisition the link captures leads for: the requisition_id you put in the path at POST /v1/sourcing/requisitions/{requisition_id}/capture_links, that requisition's id starting with flow_enterprise_requisition_.
channel_id
string
optionalThe channel the link was created for: the channel_id you sent at POST /v1/sourcing/requisitions/{requisition_id}/capture_links, starting with flow_enterprise_broadcast_. Every lead who follows the link is attributed to it.
url
string · uri
requiredCarries the token and nothing else. No name, no phone number and no identifier ever appears in a query parameter, because a link gets pasted where you cannot see it.
token
string
requiredOpaque and not enumerable. Guessing a neighbouring one finds nothing.
leads_captured
integer · minimum 0
optionalHow many leads have come in through this link so far. 0 for a link nobody has followed yet.
expires_at
string · date-time · nullable
optionalWhen the link stops working, as an RFC 3339 timestamp in UTC. null when the link has no expiry.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/capture_links" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"channel_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","expires_at":"2026-09-01T09:00:00Z"}'import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingCaptureLinksCreate({
requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
idempotencyKey: crypto.randomUUID(),
flowCaptureLinkCreateRequest: {"channelId":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","expiresAt":"2026-09-01T09:00:00Z"},
});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/capture_links', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"expires_at": "2026-09-01T09:00:00Z"
}),
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_capture_links_create(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', body={"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "expires_at": "2026-09-01T09:00:00Z"})import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/capture_links',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "expires_at": "2026-09-01T09:00:00Z"},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingCaptureLinksCreate($idempotencyKey, json_decode('{"channel_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","expires_at":"2026-09-01T09:00:00Z"}', true));<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/capture_links');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => '{"channel_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","expires_at":"2026-09-01T09:00:00Z"}',
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingCaptureLinksCreate("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", idempotencyKey, body);var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/capture_links"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"expires_at": "2026-09-01T09:00:00Z"
}
"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingCaptureLinksCreate(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", idempotencyKey, body);using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/capture_links");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
{
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"expires_at": "2026-09-01T09:00:00Z"
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingCaptureLinksCreate(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").IdempotencyKey(key).FlowCaptureLinkCreateRequest(body).Execute()body := strings.NewReader(`{
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"expires_at": "2026-09-01T09:00:00Z"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/capture_links", body)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "capture_link",
"url": "https://files.sandbox.droomwork.com/example",
"token": "example",
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"leads_captured": 0,
"expires_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/capture_links/{capture_link_id}#Retrieve a capture link
sourcing.capture_links.retrieve
Returns the link and how many leads it produced.
Path parameters
capture_link_id
string
requiredThe capture link's identifier: the id in the response to POST /v1/sourcing/requisitions/{requisition_id}/capture_links, or the capture_link_id on a lead's attribution. It starts with flow_enterprise_lead_.
Returns
The capture link.
id
string
requiredThe capture link's identifier. It starts with flow_enterprise_lead_ and never changes; pass it as capture_link_id at GET /v1/sourcing/capture_links/{capture_link_id}, and read it back on a lead's attribution.
object
always "capture_link"
requiredAlways capture_link. Tells you which kind of record you are looking at, so one handler can read any response.
requisition_id
string
requiredThe requisition the link captures leads for: the requisition_id you put in the path at POST /v1/sourcing/requisitions/{requisition_id}/capture_links, that requisition's id starting with flow_enterprise_requisition_.
channel_id
string
optionalThe channel the link was created for: the channel_id you sent at POST /v1/sourcing/requisitions/{requisition_id}/capture_links, starting with flow_enterprise_broadcast_. Every lead who follows the link is attributed to it.
url
string · uri
requiredCarries the token and nothing else. No name, no phone number and no identifier ever appears in a query parameter, because a link gets pasted where you cannot see it.
token
string
requiredOpaque and not enumerable. Guessing a neighbouring one finds nothing.
leads_captured
integer · minimum 0
optionalHow many leads have come in through this link so far. 0 for a link nobody has followed yet.
expires_at
string · date-time · nullable
optionalWhen the link stops working, as an RFC 3339 timestamp in UTC. null when the link has no expiry.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/capture_links/%7Bcapture_link_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingCaptureLinksRetrieve({ captureLinkId: '{capture_link_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/capture_links/%7Bcapture_link_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_capture_links_retrieve(capture_link_id='{capture_link_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/capture_links/%7Bcapture_link_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingCaptureLinksRetrieve(capture_link_id: '{capture_link_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/capture_links/%7Bcapture_link_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingCaptureLinksRetrieve("{capture_link_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/capture_links/%7Bcapture_link_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingCaptureLinksRetrieve(captureLinkId: "{capture_link_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/capture_links/%7Bcapture_link_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingCaptureLinksRetrieve(ctx, "{capture_link_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/capture_links/%7Bcapture_link_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "capture_link",
"url": "https://files.sandbox.droomwork.com/example",
"token": "example",
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"leads_captured": 0,
"expires_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/requisitions/{requisition_id}/knockout_rules#List the knockout rules for a requisition
sourcing.knockout_rules.list
The rules that decide whether a candidate passes or fails. They're deterministic, versioned, readable here, and the only thing that decides an outcome.
The screening conversation extracts a meaning from each answer. It never decides whether the answer passes; these rules do.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Returns
The knockout rules.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of KnockoutRule
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
5 fields of KnockoutRule
code
string
requiredA short code that names this rule. Use it in your own reporting to refer to the rule without quoting the question or the test.
question
string
requiredWhat the candidate is asked. The conversation may phrase it differently, but the answer is judged by rule, never by the phrasing.
rule
string
requiredThe deterministic test applied to what was extracted from the answer, such as years_experience >= 3. It is the only thing that decides pass or fail.
rule_pack_version
string
requiredThe version of the rule pack this rule belongs to, such as 2026.08.1. Rules are versioned, so you can reproduce an outcome against the version that decided it.
mandatory
boolean
optionaltrue when every candidate for this requisition is asked this question and judged by this rule. false when the conversation may leave it out.
question_cap
integer · defaults to 5
requiredFive by default. A screening conversation that runs longer than this stops being screening and starts being an interview.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/knockout_rules" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingKnockoutRulesList({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/knockout_rules', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_knockout_rules_list(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/knockout_rules',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingKnockoutRulesList(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/knockout_rules');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingKnockoutRulesList("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/knockout_rules"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingKnockoutRulesList(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/knockout_rules");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingKnockoutRulesList(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/knockout_rules", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"code": "no_payee_destination",
"question": "example",
"rule": "years_experience >= 3",
"rule_pack_version": "2026.08.1",
"mandatory": true
}
],
"question_cap": 1
}
/v1/sourcing/leads#List leads
sourcing.leads.list
Your leads. Deduplicated within a requisition by contact identity, so the same person answering twice is one lead.
Query parameters
limit
integer
optionalHow many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.
starting_after
string
optionalThe id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.
requisition_id
string
optionalRestricts the list to the leads of one requisition: its id from POST /v1/sourcing/requisitions or GET /v1/sourcing/requisitions, starting with flow_enterprise_requisition_. Leave it out to get leads across all your requisitions.
outcome
string
optionalRestricts the list to one screening outcome: in_progress (still answering), passed or failed (your knockout rules decided), or abandoned (stopped before the end). Pass passed for your shortlist; leave it out to get every lead.
in_progresspassedfailedabandonedReturns
A page of leads.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of Lead
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
14 fields of Lead
id
string
requiredThe lead's identifier. It starts with flow_enterprise_lead_ and never changes; pass it as lead_id on GET /v1/sourcing/leads/{lead_id} and the /screening, /attribution and /promote routes under it.
object
always "lead"
requiredAlways lead. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
requisition_id
string
requiredThe requisition this lead answered: its id from POST /v1/sourcing/requisitions, starting with flow_enterprise_requisition_. With requisition_version, it pins the exact version the lead was captured against.
requisition_version
integer
requiredWhich version produced this lead. A shortlist is reproducible against it.
channel_id
string
optionalThe channel the lead came through: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. It is what your yield at GET /v1/sourcing/analytics counts against.
screening_outcome
string
optionalin_progresspassedfailedabandonedfit_score
number · minimum 0 · maximum 100
requiredHow well the lead fits the requisition, from 0 to 100. The three factors behind it are in top_factors, so a score never arrives without a reason.
top_factors
array of object
optionalThe three factors that most influenced the score. Three, always, so a score is never a number without a reason.
2 fields
factor
string
requiredThe name of one of the three things that most influenced fit_score. Read it with contribution to see how far it moved the score.
contribution
number
requiredHow much this factor moved fit_score. Read the three together to see why the lead scored as it did.
consent
LeadConsent
requiredCaptured at first contact, before anything else is asked.
4 fields of LeadConsent
lawful_basis
string
requiredThe lawful basis you process this candidate's data under: consent (they agreed), legitimate_interest (your hiring interest) or contract (steps toward a contract with them). Recorded at first contact, before anything else is asked.
consentlegitimate_interestcontractchannel
string
requiredThe channel the candidate gave consent on. The channel agreed to nothing on their behalf; this is where the candidate themselves agreed.
wording_version
string
requiredThe exact wording presented. Answered from the record, not the current page.
captured_at
string · date-time
requiredWhen the candidate gave consent, as an RFC 3339 timestamp in UTC. It comes before every answer the lead gave.
duplicate_of
string · nullable
optionalSet when this response matched an existing lead on contact identity.
promoted_subject_ref
string · nullable
optionalSet once you promote the lead at POST /v1/sourcing/leads/{lead_id}/promote, null before: the person's opaque reference, starting with sub_, that you send as subject_ref at POST /v1/identity/consent_tokens and POST /v1/identity/verifications.
captured_at
string · date-time
optionalWhen the lead came in, as an RFC 3339 timestamp in UTC. Screening can still be in_progress after this; it says when the candidate was captured, not when they were judged.
has_more
boolean
requiredtrue when there are more records after this page. Pass the last record's id as starting_after to get the next page.
Other responses
Errors it can return
# query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/leads?limit=25&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=in_progress" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
const result = await api.sourcingLeadsList({ limit: 25, requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome: 'in_progress' });// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/leads?limit=25&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=in_progress', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
result = api.sourcing_leads_list(limit=25, requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome='in_progress')import os
import requests
# query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/leads?limit=25&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=in_progress',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
$result = $api->sourcingLeadsList(limit: 25, requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome: 'in_progress');<?php
// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/leads?limit=25&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=in_progress');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
import com.droomwork.sdk.model.*;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
var result = api.sourcingLeadsList(25, null, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", FlowScreeningOutcome.fromValue("in_progress"));// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/leads?limit=25&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=in_progress"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
var result = api.SourcingLeadsList(limit: 25, requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", outcome: FlowScreeningOutcome.InProgress);// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/leads?limit=25&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=in_progress");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
result, _, err := client.FLOWAPI.SourcingLeadsList(ctx).Limit(25).RequisitionId("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Outcome(droomwork.FlowScreeningOutcome("in_progress")).Execute()// query parameters: limit (optional), starting_after (optional), requisition_id (optional), outcome (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/leads?limit=25&requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=in_progress", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"id": "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "lead",
"livemode": true,
"mocked": true,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"requisition_version": 1,
"fit_score": 0,
"consent": {
"lawful_basis": "consent",
"channel": "example",
"wording_version": "2026.08.1",
"captured_at": "2026-09-01T09:00:00Z"
},
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"screening_outcome": "in_progress",
"top_factors": [
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
}
],
"duplicate_of": "example",
"promoted_subject_ref": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"captured_at": "2026-09-01T09:00:00Z"
}
],
"has_more": true
}
/v1/sourcing/leads#Record a lead
sourcing.leads.create
Record a candidate who came in through a channel. Consent is captured with the lead, never assumed from the channel: the channel agreed to nothing on the candidate's behalf.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Body optional
requisition_id
string
optionalThe requisition the lead is for: the id of a requisition you created at POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions. It starts with flow_enterprise_requisition_.
channel_id
string
optionalThe channel the lead came through: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. Your yield at GET /v1/sourcing/analytics counts the lead against it.
Returns
The lead.
id
string
requiredThe lead's identifier. It starts with flow_enterprise_lead_ and never changes; pass it as lead_id on GET /v1/sourcing/leads/{lead_id} and the /screening, /attribution and /promote routes under it.
object
always "lead"
requiredAlways lead. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
requisition_id
string
requiredThe requisition this lead answered: its id from POST /v1/sourcing/requisitions, starting with flow_enterprise_requisition_. With requisition_version, it pins the exact version the lead was captured against.
requisition_version
integer
requiredWhich version produced this lead. A shortlist is reproducible against it.
channel_id
string
optionalThe channel the lead came through: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. It is what your yield at GET /v1/sourcing/analytics counts against.
screening_outcome
string
optionalin_progresspassedfailedabandonedfit_score
number · minimum 0 · maximum 100
requiredHow well the lead fits the requisition, from 0 to 100. The three factors behind it are in top_factors, so a score never arrives without a reason.
top_factors
array of object
optionalThe three factors that most influenced the score. Three, always, so a score is never a number without a reason.
2 fields
factor
string
requiredThe name of one of the three things that most influenced fit_score. Read it with contribution to see how far it moved the score.
contribution
number
requiredHow much this factor moved fit_score. Read the three together to see why the lead scored as it did.
consent
LeadConsent
requiredCaptured at first contact, before anything else is asked.
4 fields of LeadConsent
lawful_basis
string
requiredThe lawful basis you process this candidate's data under: consent (they agreed), legitimate_interest (your hiring interest) or contract (steps toward a contract with them). Recorded at first contact, before anything else is asked.
consentlegitimate_interestcontractchannel
string
requiredThe channel the candidate gave consent on. The channel agreed to nothing on their behalf; this is where the candidate themselves agreed.
wording_version
string
requiredThe exact wording presented. Answered from the record, not the current page.
captured_at
string · date-time
requiredWhen the candidate gave consent, as an RFC 3339 timestamp in UTC. It comes before every answer the lead gave.
duplicate_of
string · nullable
optionalSet when this response matched an existing lead on contact identity.
promoted_subject_ref
string · nullable
optionalSet once you promote the lead at POST /v1/sourcing/leads/{lead_id}/promote, null before: the person's opaque reference, starting with sub_, that you send as subject_ref at POST /v1/identity/consent_tokens and POST /v1/identity/verifications.
captured_at
string · date-time
optionalWhen the lead came in, as an RFC 3339 timestamp in UTC. Screening can still be in_progress after this; it says when the candidate was captured, not when they were judged.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/leads" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"requisition_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","channel_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}'import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingLeadsCreate({});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/leads', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}),
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_leads_create()import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/leads',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
json={"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingLeadsCreate();<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/leads');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Content-Type: application/json',
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => '{"requisition_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z","channel_id":"sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"}',
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingLeadsCreate();var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/leads"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}
"""))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingLeadsCreate();using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/leads");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
request.Content = new StringContent("""
{
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}
""", Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingLeadsCreate(ctx).Execute()body := strings.NewReader(`{
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}`)
req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/leads", body)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "lead",
"livemode": true,
"mocked": true,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"requisition_version": 1,
"fit_score": 0,
"consent": {
"lawful_basis": "consent",
"channel": "example",
"wording_version": "2026.08.1",
"captured_at": "2026-09-01T09:00:00Z"
},
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"screening_outcome": "in_progress",
"top_factors": [
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
}
],
"duplicate_of": "example",
"promoted_subject_ref": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"captured_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/leads/{lead_id}#Retrieve a lead
sourcing.leads.retrieve
Returns the lead with its fit score, the three factors that most influenced it, and the requisition version it was captured against.
The version travels with the lead, so you can reproduce a shortlist for a given version.
Path parameters
lead_id
string
requiredThe lead's identifier: the id of a lead from GET /v1/sourcing/leads, from the response to POST /v1/sourcing/leads, or from a lead.captured webhook. It starts with flow_enterprise_lead_.
Returns
The lead.
id
string
requiredThe lead's identifier. It starts with flow_enterprise_lead_ and never changes; pass it as lead_id on GET /v1/sourcing/leads/{lead_id} and the /screening, /attribution and /promote routes under it.
object
always "lead"
requiredAlways lead. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
requisition_id
string
requiredThe requisition this lead answered: its id from POST /v1/sourcing/requisitions, starting with flow_enterprise_requisition_. With requisition_version, it pins the exact version the lead was captured against.
requisition_version
integer
requiredWhich version produced this lead. A shortlist is reproducible against it.
channel_id
string
optionalThe channel the lead came through: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. It is what your yield at GET /v1/sourcing/analytics counts against.
screening_outcome
string
optionalin_progresspassedfailedabandonedfit_score
number · minimum 0 · maximum 100
requiredHow well the lead fits the requisition, from 0 to 100. The three factors behind it are in top_factors, so a score never arrives without a reason.
top_factors
array of object
optionalThe three factors that most influenced the score. Three, always, so a score is never a number without a reason.
2 fields
factor
string
requiredThe name of one of the three things that most influenced fit_score. Read it with contribution to see how far it moved the score.
contribution
number
requiredHow much this factor moved fit_score. Read the three together to see why the lead scored as it did.
consent
LeadConsent
requiredCaptured at first contact, before anything else is asked.
4 fields of LeadConsent
lawful_basis
string
requiredThe lawful basis you process this candidate's data under: consent (they agreed), legitimate_interest (your hiring interest) or contract (steps toward a contract with them). Recorded at first contact, before anything else is asked.
consentlegitimate_interestcontractchannel
string
requiredThe channel the candidate gave consent on. The channel agreed to nothing on their behalf; this is where the candidate themselves agreed.
wording_version
string
requiredThe exact wording presented. Answered from the record, not the current page.
captured_at
string · date-time
requiredWhen the candidate gave consent, as an RFC 3339 timestamp in UTC. It comes before every answer the lead gave.
duplicate_of
string · nullable
optionalSet when this response matched an existing lead on contact identity.
promoted_subject_ref
string · nullable
optionalSet once you promote the lead at POST /v1/sourcing/leads/{lead_id}/promote, null before: the person's opaque reference, starting with sub_, that you send as subject_ref at POST /v1/identity/consent_tokens and POST /v1/identity/verifications.
captured_at
string · date-time
optionalWhen the lead came in, as an RFC 3339 timestamp in UTC. Screening can still be in_progress after this; it says when the candidate was captured, not when they were judged.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingLeadsRetrieve({ leadId: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_leads_retrieve(lead_id='flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingLeadsRetrieve(lead_id: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingLeadsRetrieve("flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingLeadsRetrieve(leadId: "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingLeadsRetrieve(ctx, "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "lead",
"livemode": true,
"mocked": true,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"requisition_version": 1,
"fit_score": 0,
"consent": {
"lawful_basis": "consent",
"channel": "example",
"wording_version": "2026.08.1",
"captured_at": "2026-09-01T09:00:00Z"
},
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"screening_outcome": "in_progress",
"top_factors": [
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
}
],
"duplicate_of": "example",
"promoted_subject_ref": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"captured_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/leads/{lead_id}/screening#Retrieve the screening conversation record
sourcing.screenings.retrieve
Shows you the two halves separately: what was extracted from each answer, and what the rules then decided.
That lets you tell a bad extraction from a bad rule. They're different problems with different fixes.
Path parameters
lead_id
string
requiredThe lead's identifier: the id of a lead from GET /v1/sourcing/leads, from the response to POST /v1/sourcing/leads, or from a lead.captured webhook. It starts with flow_enterprise_lead_.
Returns
The screening record.
object
always "screening"
requiredAlways screening. Tells you which kind of record you are looking at, so one handler can read any response.
lead_id
string
requiredThe lead this screening belongs to: the lead_id you put in the path at GET /v1/sourcing/leads/{lead_id}/screening, that lead's id starting with flow_enterprise_lead_. Returned so the record stands on its own.
outcome
string
requiredin_progresspassedfailedabandonedsurface
string
requiredWhere the candidate answered: whatsapp (in a WhatsApp conversation) or web (on a web page). The rules that decide pass and fail are the same on either.
whatsappwebexchanges
array of object
requiredOne entry per question put to the candidate: the question, how it was answered, what was extracted, and what the rule decided. Never more than the question_cap on the requisition's knockout rules, five by default.
4 fields
question
string
requiredThe question as it was put to the candidate. The wording can differ from the knockout rule's question; the rule it was asked for is named in decision.rule.
answer_mode
string
requiredHow the candidate answered: text (typed) or voice (spoken). Either way, extracted holds what was taken from the answer and the same rule judges it.
textvoiceextracted
object
requiredWhat was extracted from the candidate's answer. It decides nothing.
3 fields
field
string
optionalThe fact the answer was read for, named as your rule names it: years_experience for a rule of years_experience >= 3.
value
string
optionalWhat the answer was taken to say for that field, as a string. It is what the rule is applied to; a wrong value here is an extraction problem, not a rule problem.
confidence
number
optionalHow confident the extraction is that value is what the candidate meant. It changes no decision; a low figure beside a failed rule tells you to check the extraction first.
decision
object
requiredThe decision on the answer, and the rule that made it. This is the only thing that decides.
3 fields
rule
string
requiredThe knockout rule that was applied, written out exactly as you gave it, such as years_experience >= 3. What it decided is in passed.
passed
boolean
requiredtrue when the extracted value met the rule, false when it didn't. Decided by the rule alone, never by the conversation.
rule_pack_version
string
optionalThe version of the rule pack that judged this answer, such as 2026.08.1. Rules change between versions, and this names the one that applied.
decided_by
always "rule_pack"
optionalAlways rule_pack. The decision comes from your knockout rules, never from the conversation.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/screening" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingScreeningsRetrieve({ leadId: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/screening', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_screenings_retrieve(lead_id='flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/screening',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingScreeningsRetrieve(lead_id: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/screening');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingScreeningsRetrieve("flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/screening"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingScreeningsRetrieve(leadId: "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/screening");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingScreeningsRetrieve(ctx, "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/screening", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "screening",
"lead_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"outcome": "in_progress",
"surface": "whatsapp",
"exchanges": [
{
"question": "example",
"answer_mode": "text",
"extracted": {
"field": "gross.amount",
"value": "example",
"confidence": 1
},
"decision": {
"rule": "years_experience >= 3",
"passed": true,
"rule_pack_version": "2026.08.1"
}
}
],
"decided_by": "rule_pack"
}
/v1/sourcing/leads/{lead_id}/promote#Promote a lead toward identity
sourcing.leads.promote
Hands the lead on for identity resolution. Attribution survives promotion, so you can still see which channel produced this person months afterwards.
Path parameters
lead_id
string
requiredThe lead's identifier: the id of a lead from GET /v1/sourcing/leads, from the response to POST /v1/sourcing/leads, or from a lead.captured webhook. It starts with flow_enterprise_lead_.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Returns
The promoted lead.
id
string
requiredThe lead's identifier. It starts with flow_enterprise_lead_ and never changes; pass it as lead_id on GET /v1/sourcing/leads/{lead_id} and the /screening, /attribution and /promote routes under it.
object
always "lead"
requiredAlways lead. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
requisition_id
string
requiredThe requisition this lead answered: its id from POST /v1/sourcing/requisitions, starting with flow_enterprise_requisition_. With requisition_version, it pins the exact version the lead was captured against.
requisition_version
integer
requiredWhich version produced this lead. A shortlist is reproducible against it.
channel_id
string
optionalThe channel the lead came through: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. It is what your yield at GET /v1/sourcing/analytics counts against.
screening_outcome
string
optionalin_progresspassedfailedabandonedfit_score
number · minimum 0 · maximum 100
requiredHow well the lead fits the requisition, from 0 to 100. The three factors behind it are in top_factors, so a score never arrives without a reason.
top_factors
array of object
optionalThe three factors that most influenced the score. Three, always, so a score is never a number without a reason.
2 fields
factor
string
requiredThe name of one of the three things that most influenced fit_score. Read it with contribution to see how far it moved the score.
contribution
number
requiredHow much this factor moved fit_score. Read the three together to see why the lead scored as it did.
consent
LeadConsent
requiredCaptured at first contact, before anything else is asked.
4 fields of LeadConsent
lawful_basis
string
requiredThe lawful basis you process this candidate's data under: consent (they agreed), legitimate_interest (your hiring interest) or contract (steps toward a contract with them). Recorded at first contact, before anything else is asked.
consentlegitimate_interestcontractchannel
string
requiredThe channel the candidate gave consent on. The channel agreed to nothing on their behalf; this is where the candidate themselves agreed.
wording_version
string
requiredThe exact wording presented. Answered from the record, not the current page.
captured_at
string · date-time
requiredWhen the candidate gave consent, as an RFC 3339 timestamp in UTC. It comes before every answer the lead gave.
duplicate_of
string · nullable
optionalSet when this response matched an existing lead on contact identity.
promoted_subject_ref
string · nullable
optionalSet once you promote the lead at POST /v1/sourcing/leads/{lead_id}/promote, null before: the person's opaque reference, starting with sub_, that you send as subject_ref at POST /v1/identity/consent_tokens and POST /v1/identity/verifications.
captured_at
string · date-time
optionalWhen the lead came in, as an RFC 3339 timestamp in UTC. Screening can still be in_progress after this; it says when the candidate was captured, not when they were judged.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/promote" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingLeadsPromote({ leadId: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/promote', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Idempotency-Key': crypto.randomUUID(),
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_leads_promote(lead_id='flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/promote',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingLeadsPromote(lead_id: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/promote');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingLeadsPromote("flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/promote"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingLeadsPromote(leadId: "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/promote");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingLeadsPromote(ctx, "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/promote", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "lead",
"livemode": true,
"mocked": true,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"requisition_version": 1,
"fit_score": 0,
"consent": {
"lawful_basis": "consent",
"channel": "example",
"wording_version": "2026.08.1",
"captured_at": "2026-09-01T09:00:00Z"
},
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"screening_outcome": "in_progress",
"top_factors": [
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
},
{
"factor": "example",
"contribution": 1
}
],
"duplicate_of": "example",
"promoted_subject_ref": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"captured_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/leads/{lead_id}/attribution#Retrieve the attribution record for a lead
sourcing.attributions.retrieve
First touch, last touch and the referring party. It can't change once written, and it survives promotion, so you can ask which channel produced a hire long after the hire.
Path parameters
lead_id
string
requiredThe lead's identifier: the id of a lead from GET /v1/sourcing/leads, from the response to POST /v1/sourcing/leads, or from a lead.captured webhook. It starts with flow_enterprise_lead_.
Returns
The attribution record.
object
always "attribution"
requiredAlways attribution. Tells you which kind of record you are looking at, so one handler can read any response.
lead_id
string
requiredThe lead this attribution belongs to: the lead_id from the path at GET /v1/sourcing/leads/{lead_id}/attribution, starting with flow_enterprise_lead_. It survives promotion, so you can still ask which channel produced the person.
first_touch
object
requiredThe first contact this lead made: which channel it came through, the capture link if one was used, and when. Written once and never changed.
3 fields
channel_id
string
requiredThe channel the first contact came through: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. Written once and never changed.
capture_link_id
string
optionalThe capture link the first contact came through: the id of a link from POST /v1/sourcing/requisitions/{requisition_id}/capture_links, starting with flow_enterprise_lead_. Absent when the candidate arrived without a link.
at
string · date-time
requiredWhen the first contact happened, as an RFC 3339 timestamp in UTC.
last_touch
object
requiredThe latest contact this lead made: which channel it came through, the capture link if one was used, and when. Equal to first_touch when there was only one contact.
3 fields
channel_id
string
requiredThe channel the latest contact came through: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. Equal to first_touch.channel_id when there was only one contact.
capture_link_id
string
optionalThe capture link the latest contact came through: the id of a link from POST /v1/sourcing/requisitions/{requisition_id}/capture_links, starting with flow_enterprise_lead_. Absent when the candidate arrived without a link.
at
string · date-time
requiredWhen the latest contact happened, as an RFC 3339 timestamp in UTC.
referring_party
string · nullable
optionalWho referred the candidate, when the lead came by referral, and null when nobody did. Like the touches, it can't change once written.
survives_promotion
always true
optionalAlways true. Promoting the lead toward identity leaves this record in place, so you can ask which channel produced a hire long after the hire.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/attribution" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingAttributionsRetrieve({ leadId: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/attribution', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_attributions_retrieve(lead_id='flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/attribution',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingAttributionsRetrieve(lead_id: 'flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/attribution');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingAttributionsRetrieve("flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/attribution"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingAttributionsRetrieve(leadId: "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/attribution");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingAttributionsRetrieve(ctx, "flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/leads/flow_enterprise_lead_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/attribution", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "attribution",
"lead_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"first_touch": {
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"at": "2026-09-01T09:00:00Z",
"capture_link_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
},
"last_touch": {
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"at": "2026-09-01T09:00:00Z",
"capture_link_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
},
"referring_party": "example",
"survives_promotion": true
}
/v1/sourcing/analytics#Retrieve channel yield analytics
sourcing.analytics.retrieve
Leads captured, qualified, promoted and hired per channel, with cost per qualified lead.
Your organisation only. You see your own yield on a channel and never anyone else's.
Query parameters
requisition_id
string
optionalRestricts the figures to one requisition: its id from POST /v1/sourcing/requisitions or GET /v1/sourcing/requisitions, starting with flow_enterprise_requisition_. Leave it out to get your yield across every requisition.
from
string
optionalThe earliest date to count from, as YYYY-MM-DD. Leave it out and nothing is cut off at the start; pair it with to to bound a period.
to
string
optionalThe latest date to count to, as YYYY-MM-DD. Leave it out and the figures run to today; pair it with from to bound a period.
Returns
The analytics.
object
always "channel_analytics"
requiredAlways channel_analytics. Tells you which kind of record you are looking at, so one handler can read any response.
scope
always "requesting_organisation"
requiredYour own figures only. Never another organisation's yield on a channel.
channels
array of object
requiredOne entry per channel: the leads it captured, how many qualified, how many you promoted and how many were hired, and what each qualified lead cost you there. Your own figures only.
6 fields
channel_id
string
requiredThe channel these figures are for, by its id as GET /v1/sourcing/channels lists it, prefix flow_enterprise_broadcast_. Pass it to GET /v1/sourcing/channels/{channel_id} to read the channel.
captured
integer
requiredHow many leads this channel captured in the period. One person answering twice on the same requisition is one lead, so they count once.
qualified
integer
requiredHow many of this channel's leads passed your knockout rules in the period. Divide it by captured for the channel's qualification rate.
promoted
integer
requiredHow many of those leads you promoted toward identity in the period, with POST /v1/sourcing/leads/{lead_id}/promote.
hired
integer
requiredHow many of those leads went on to be hired in the period. Attribution survives promotion, so the hire is still credited to the channel that produced the lead.
cost_per_qualified_lead
Money
optional2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
Other responses
Errors it can return
# query parameters: requisition_id (optional), from (optional), to (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/analytics?requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&from=Thu%20Jan%2001%202026%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)&to=Fri%20Jan%2001%202027%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: requisition_id (optional), from (optional), to (optional)
const result = await api.sourcingAnalyticsRetrieve({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', from: 'Thu Jan 01 2026 01:00:00 GMT+0100 (West Africa Time)', to: 'Fri Jan 01 2027 01:00:00 GMT+0100 (West Africa Time)' });// query parameters: requisition_id (optional), from (optional), to (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/analytics?requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&from=Thu%20Jan%2001%202026%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)&to=Fri%20Jan%2001%202027%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: requisition_id (optional), from (optional), to (optional)
result = api.sourcing_analytics_retrieve(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', from='Thu Jan 01 2026 01:00:00 GMT+0100 (West Africa Time)', to='Fri Jan 01 2027 01:00:00 GMT+0100 (West Africa Time)')import os
import requests
# query parameters: requisition_id (optional), from (optional), to (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/analytics?requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&from=Thu%20Jan%2001%202026%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)&to=Fri%20Jan%2001%202027%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: requisition_id (optional), from (optional), to (optional)
$result = $api->sourcingAnalyticsRetrieve(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', from: 'Thu Jan 01 2026 01:00:00 GMT+0100 (West Africa Time)', to: 'Fri Jan 01 2027 01:00:00 GMT+0100 (West Africa Time)');<?php
// query parameters: requisition_id (optional), from (optional), to (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/analytics?requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&from=Thu%20Jan%2001%202026%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)&to=Fri%20Jan%2001%202027%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: requisition_id (optional), from (optional), to (optional)
var result = api.sourcingAnalyticsRetrieve("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "Thu Jan 01 2026 01:00:00 GMT+0100 (West Africa Time)", "Fri Jan 01 2027 01:00:00 GMT+0100 (West Africa Time)");// query parameters: requisition_id (optional), from (optional), to (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/analytics?requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&from=Thu%20Jan%2001%202026%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)&to=Fri%20Jan%2001%202027%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: requisition_id (optional), from (optional), to (optional)
var result = api.SourcingAnalyticsRetrieve(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", from: "Thu Jan 01 2026 01:00:00 GMT+0100 (West Africa Time)", to: "Fri Jan 01 2027 01:00:00 GMT+0100 (West Africa Time)");// query parameters: requisition_id (optional), from (optional), to (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/analytics?requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&from=Thu%20Jan%2001%202026%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)&to=Fri%20Jan%2001%202027%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: requisition_id (optional), from (optional), to (optional)
result, _, err := client.FLOWAPI.SourcingAnalyticsRetrieve(ctx).RequisitionId("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").From("Thu Jan 01 2026 01:00:00 GMT+0100 (West Africa Time)").To("Fri Jan 01 2027 01:00:00 GMT+0100 (West Africa Time)").Execute()// query parameters: requisition_id (optional), from (optional), to (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/analytics?requisition_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&from=Thu%20Jan%2001%202026%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)&to=Fri%20Jan%2001%202027%2001%3A00%3A00%20GMT%2B0100%20(West%20Africa%20Time)", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "channel_analytics",
"scope": "requesting_organisation",
"channels": [
{
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"captured": 1,
"qualified": 1,
"promoted": 1,
"hired": 1,
"cost_per_qualified_lead": {
"amount": 1234567,
"currency": "NGN"
}
}
]
}
/v1/sourcing/readiness#What FLOW needs, what you have, and what is missing
sourcing.readiness.retrieve
You don't need another module set up before FLOW, so this reports what FLOW itself needs: channel credentials and wallet funding.
Returns
The readiness report.
object
always "readiness_report"
requiredAlways readiness_report. Tells you which kind of record you are looking at, so one handler can read any response.
module
string
requiredThe module whose readiness endpoint you called, such as GET /v1/payroll/readiness: anchor (identity), proof (credentials), rail (engagements), flow (sourcing), match (allocation), run (payroll), remit (remittance) or route (payouts).
anchorproofrailflowmatchrunremitroutemode
string
requiredintegrated means a required fact comes from the Droomwork module that owns it; standalone means you supply it yourself under an attestation. The checks are the same in both, and what each fact is worth is recorded on its row as held.
integratedstandaloneready
boolean
requiredtrue when every row is satisfied and the module has what it needs from you. false when a required fact is missing or held at too low an assurance; rows says which.
rows
array of ReadinessRow
requiredOne row per fact the module requires: who owns it, the assurance it needs, what you hold and whether that satisfies it. The rows that are not satisfied are what to bring.
8 fields of ReadinessRow
fact
string
requiredNamed for what it is, not for who supplies it.
owner
string
requiredThe sibling module that owns this fact when running integrated.
contract_row
string
optionalrequired
string
requiredHow a fact was established. Recorded on the fact rather than in configuration, so an attested identity and a verified one stay distinguishable a year later, which is the distinction that matters when something is disputed.
attestedverifiedheld
one of
requiredAssuranceorsource
string · nullable
optionalintegratedstandalonenullsatisfied
boolean
requiredmissing_because
string · nullable
optionalnot_suppliedassurance_too_lownullalways_enforced
array of string
optionalGates that hold in every mode and cannot be attested away. Consent before any source is queried, bank account validation, the tax identifiers returns are filed under, and duplicate detection within the organisation's own population.
channels_without_credentials
array of string
optionalThe channels you hold no credentials for. Nothing broadcasts to one of them until you supply the credentials; credentials_held on the channel says the same thing.
wallet_funded
boolean
optionalPaid channels cannot run without it, and the ceiling check refuses first.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/readiness" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingReadinessRetrieve({});const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/readiness', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_readiness_retrieve()import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/readiness',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingReadinessRetrieve();<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/readiness');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingReadinessRetrieve();var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/readiness"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingReadinessRetrieve();using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/readiness");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingReadinessRetrieve(ctx).Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/readiness", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "readiness_report",
"module": "anchor",
"mode": "integrated",
"ready": true,
"rows": [
{
"fact": "anchored_subject",
"owner": "anchor",
"required": "attested",
"held": "attested",
"satisfied": true,
"contract_row": "6.1.13",
"source": "integrated",
"missing_because": "not_supplied"
}
],
"always_enforced": [
"example"
],
"channels_without_credentials": [
"example"
],
"wallet_funded": true
}
/v1/sourcing/deliveries/{delivery_id}#Retrieve a channel delivery
sourcing.deliveries.retrieve
What one channel did with one broadcast. A delivery the channel refused says so. A broadcast that reached four of five channels didn't work.
Path parameters
delivery_id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_: the id of an entry in deliveries on a broadcast, of a delivery listed at GET /v1/sourcing/deliveries, or of one you recorded at POST /v1/sourcing/deliveries.
Returns
The delivery.
id
string
requiredThe delivery's identifier, starting with flow_enterprise_delivery_; it never changes. It is in a broadcast's deliveries, at GET /v1/sourcing/deliveries and from POST /v1/sourcing/deliveries; pass it as delivery_id to read or retry it.
object
always "channel_delivery"
requiredAlways channel_delivery. Tells you which kind of record you are looking at, so one handler can read any response.
broadcast_id
string
requiredThe broadcast this delivery is part of: the id, starting with flow_enterprise_broadcast_, from POST /v1/sourcing/requisitions/{requisition_id}/broadcasts, or the one you named as broadcast_id at POST /v1/sourcing/deliveries.
requisition_id
string
optionalThe requisition this delivery carried: the id of the requisition behind the broadcast, starting with flow_enterprise_requisition_, from POST /v1/sourcing/requisitions. Filter GET /v1/sourcing/deliveries by it to see every channel it went to.
channel_id
string
requiredThe channel this delivery went to: the id of a channel from GET /v1/sourcing/channels, starting with flow_enterprise_broadcast_. One delivery covers one channel, so a broadcast has one delivery per channel it went to.
state
string
requiredfailed is terminal and always reported. A channel you selected is never dropped silently.
queuedsendingdeliveredretryingfailedattempts
integer · minimum 0
requiredHow many times posting to this channel has been tried so far, 0 before the first try. Read it with state and last_fault to see how a channel is doing.
next_attempt_at
string · date-time · nullable
optionalExponential backoff. Absent once the state is terminal.
last_fault
string · nullable
optionalWhy the most recent attempt at this channel failed, in plain words; null while nothing has failed. Read it before you retry.
external_reference
string · nullable
optionalThe channel's own reference for this posting, where the channel gives one. null otherwise, so name the delivery by id, never by this.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/deliveries/%7Bdelivery_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingDeliveriesRetrieve({ deliveryId: '{delivery_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/deliveries/%7Bdelivery_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_deliveries_retrieve(delivery_id='{delivery_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/deliveries/%7Bdelivery_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingDeliveriesRetrieve(delivery_id: '{delivery_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/deliveries/%7Bdelivery_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingDeliveriesRetrieve("{delivery_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/deliveries/%7Bdelivery_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingDeliveriesRetrieve(deliveryId: "{delivery_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/deliveries/%7Bdelivery_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingDeliveriesRetrieve(ctx, "{delivery_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/deliveries/%7Bdelivery_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_delivery_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "channel_delivery",
"broadcast_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"channel_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"state": "queued",
"attempts": 0,
"requisition_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"next_attempt_at": "2026-09-01T09:00:00Z",
"last_fault": "The register did not answer within the timeout.",
"external_reference": "paye-2026-09-rivers"
}
/v1/sourcing/requisitions/{requisition_id}/quarantine#Quarantine a requisition
sourcing.requisitions.quarantine
Holds a requisition that can't be published as written, with the findings that stopped it. Quarantine isn't rejection: the findings tell you what to fix.
Path parameters
requisition_id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_: the id returned by POST /v1/sourcing/requisitions or listed at GET /v1/sourcing/requisitions, or one of the requisition_ids on a bulk upload.
Headers
Idempotency-Key
string
requiredA key you make up for this request, such as a UUID, up to 255 characters. Sending the same key with the same body returns the original response, marked Droomwork-Idempotent-Replay: true; sending it with a different body is refused with idempotency_key_reused.
Returns
The quarantined requisition.
id
string
requiredThe requisition's identifier, starting with flow_enterprise_requisition_; it never changes. You get it from POST /v1/sourcing/requisitions (or in requisition_ids on a bulk upload) and pass it as requisition_id on every call about it.
object
always "requisition"
requiredAlways requisition. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm this record is in: false is the sandbox, true is live. Read it before you act on anything.
mocked
boolean
requiredWhere these figures came from: true when they were mocked, false when they were computed for real. Not the inverse of livemode: each record carries the answer that was true for it.
status
string
requiredA requisition sits in pending_confirmation while an inferred pay figure, headcount, location or start date is unconfirmed. It cannot leave that state until you confirm.
pending_confirmationdraftunder_reviewquarantinedpublishedclosedversion
integer · minimum 1
requiredAn edit after first broadcast makes a new version. Leads stay on theirs.
job_title
string
requiredThe title of the role as you gave it. The occupation code is inferred from it when you don't send one, so a local or colloquial title is fine.
occupation_code
string
optionalThe occupation this role maps to in the taxonomy, such as ng-7412. Inferred from the title when you didn't send one, and listed in inferred_fields until you confirm it.
employment_type
string
optionalpermanentfixed_termcontractcasualapprenticeshipheadcount
integer · minimum 1
requiredHow many people you are hiring for this role, at least 1. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
compensation
Compensation
optional3 fields of Compensation
amount
Money
required2 fields of Money
amount
integer · int64
requiredA whole number of the currency's minor unit, as defined by the ISO 4217 exponent. For NGN that is kobo, so 1234567 is twelve thousand three hundred and forty five naira and sixty seven kobo. A fractional value is refused with the code invalid_money_amount. Call GET /v1/currencies for the exponent of any currency. Never divide by a hundred by hand.
currency
string
requiredISO 4217 code.
period
string
requiredThe span the amount pays for: monthly, annual, daily or per_task (one payment for each task done). Required whenever you send compensation.
monthlyannualdailyper_tasknegotiable
boolean
optionalWhether the figure is open to negotiation: true when it is, false when it is fixed.
location
Location
optional3 fields of Location
description
string
requiredWhere the work is, in words a candidate would recognise, such as Ikeja, Lagos. The one part of a location you must give.
state
string
optionalThe Nigerian state the work is in, such as Lagos. Optional; the description alone is enough to create the requisition.
geofence_radius_metres
integer · nullable
optionalA radius around the location, in whole metres, or null when there is none. If it had to be inferred it comes back in inferred_fields for you to confirm.
starts_on
string · date · nullable
optionalThe date the role starts, as YYYY-MM-DD, or null when none is set. It never broadcasts on inference alone; confirm it if it appears in inferred_fields.
inferred_fields
array of string
optionalFields that were inferred rather than read from what you sent. Each has to be confirmed, and compensation, headcount, location and start date can never broadcast while they are here.
quarantine
one of
optionalWhy the requisition was held: the rule it tripped, the rule pack version, the detail and the offending text. null when nothing held it; fix what it names before you publish.
QuarantineFindingorcreated_at
string · date-time
optionalWhen the record was created, as an RFC 3339 timestamp in UTC.
Other responses
Errors it can return
curl -X POST "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/quarantine" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingRequisitionsQuarantine({ requisitionId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/quarantine', {
method: 'POST',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
'Idempotency-Key': crypto.randomUUID(),
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_requisitions_quarantine(requisition_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z')import os
import uuid
import requests
response = requests.request(
'POST',
'https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/quarantine',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
'Idempotency-Key': str(uuid.uuid4()),
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingRequisitionsQuarantine(requisition_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/quarantine');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingRequisitionsQuarantine("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/quarantine"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.method("POST", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingRequisitionsQuarantine(requisitionId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/quarantine");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingRequisitionsQuarantine(ctx, "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Execute()req, _ := http.NewRequest("POST", "https://sandbox.droomwork.io/v1/sourcing/requisitions/flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z/quarantine", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
req.Header.Set("Idempotency-Key", uuid.NewString())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "requisition",
"livemode": true,
"mocked": true,
"status": "pending_confirmation",
"version": 1,
"job_title": "example",
"headcount": 1,
"occupation_code": "ng-7412",
"employment_type": "permanent",
"compensation": {
"amount": {
"amount": 1234567,
"currency": "NGN"
},
"period": "monthly",
"negotiable": true
},
"location": {
"description": "example",
"state": "example",
"geofence_radius_metres": 1
},
"starts_on": "2026-09-01",
"inferred_fields": [
"example"
],
"quarantine": {
"rule_code": "discriminatory_criteria",
"rule_pack_version": "2026.08.1",
"detail": "The payee has no verified destination, so this line cannot be paid.",
"contested": true,
"offending_text": "example"
},
"created_at": "2026-09-01T09:00:00Z"
}
/v1/sourcing/events#List events
sourcing.events.list
Every event FLOW has recorded for you, oldest first, and nothing is ever removed. Every event here is one the webhook catalogue declares, so the code you wrote to handle a webhook delivery handles a replay too.
Two ways to read it. Pass stream with after to replay one stream from the sequence you last handled; that is exact and needs no cursor, because the sequence counts per organisation and per stream and is the only ordering you can rely on. Without stream, you get events across streams in the order they were recorded, paged with starting_after.
Query parameters
stream
string
optionalThe id of the record whose events you want, such as a requisition's id from POST /v1/sourcing/requisitions, prefix flow_enterprise_requisition_. Leave it out to get events across every record, paged with starting_after.
after
integer
optionalThe sequence of the last event you handled on this stream, as it reads on each event at GET /v1/sourcing/events; you get what came after it, and 0 reads from the start. Needs stream beside it, because a sequence counts within one stream.
limit
integer
optionalHow many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.
starting_after
string
optionalThe id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.
Returns
A page of events.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of StoredEvent
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
13 fields of StoredEvent
id
string
requiredThe event's identifier, starting with evt_, the same on a webhook delivery and on the module's events list, such as GET /v1/payroll/events. It never changes: a redelivery carries the same id, so you can recognise an event you have already handled.
type
string
requiredWhat happened, as module.resource.past_tense_verb, for example run.payslip.calculated. Pick your handler on it; data takes the shape this type promises.
schema_version
integer · minimum 1
requiredThe version of the shape data takes for this type, starting at 1. A change to the shape raises it, so check it before you read data.
org_id
string
requiredThe organisation the event belongs to, by its id, which starts with org_: the one POST /v1/registrations gave you and GET /v1/me returns. You only ever receive events for your own organisation.
sequence
integer · minimum 0
requiredPer organisation and per stream. It is how a consumer tells a replay from a new event, and it is what the delivery guarantee rests on.
occurred_at
string · date-time
requiredWhen the event happened, as an RFC 3339 timestamp in UTC. Not when it was delivered: a redelivery carries the original value.
request_id
string
optionalThe request that caused this event, where one did: the Droomwork-Request-Id that request returned, starting with req_. Absent for an event a schedule raised, such as an engagement lapsing on its end date.
livemode
boolean
requiredWhich realm the event happened in. False is the sandbox.
mocked
boolean
requiredWhether a mock produced this fact, rather than an engine computing it. Recorded on the event when it was appended and never worked out afterwards from the realm: the two answers agree while every module is on its mock and part on the day the first engine ships. See ADR-0011.
source
string
requiredWhich part of Droomwork is the authority for this fact: anchor (identity), proof (credentials), rail (engagements), flow (sourcing), match (allocation), run (payroll), remit (remittance), route (payouts), gateway (the API's front door), iam (accounts and API keys), ledger (the books), registry (rule packs), delivery (webhooks and messages), documents (rendered payslips and instruments) or intelligence (AI decisions). Read the fact from there when it matters; your own copy is never the authority.
anchorproofrailflowmatchrunremitroutegatewayiamledgerregistrydeliverydocumentsintelligenceobject
always "event"
requiredAlways event. Tells you which kind of record you are looking at, so one handler can read any response.
stream
string
requiredThe id of the record this event is about, such as a requisition's id from POST /v1/sourcing/requisitions (flow_enterprise_requisition_). sequence counts within this stream only; replay with stream and after at GET /v1/sourcing/events.
data
object
requiredThe record the event is about, in the shape its type names: a requisition, a channel delivery, a lead, or your spend ceilings. The same body a webhook delivery carries.
has_more
boolean
requiredtrue when there are more records after this page. Pass the last record's id as starting_after to get the next page.
Other responses
Errors it can return
# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/events?stream=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
const result = await api.sourcingEventsList({ stream: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', after: 0, limit: 25 });// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/events?stream=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
result = api.sourcing_events_list(stream='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', after=0, limit=25)import os
import requests
# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/events?stream=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
$result = $api->sourcingEventsList(stream: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', after: 0, limit: 25);<?php
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/events?stream=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
var result = api.sourcingEventsList("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", 0, 25, null);// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/events?stream=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
var result = api.SourcingEventsList(stream: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", after: 0, limit: 25);// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/events?stream=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
result, _, err := client.FLOWAPI.SourcingEventsList(ctx).Stream("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").After(0).Limit(25).Execute()// query parameters: stream (optional), after (optional), limit (optional), starting_after (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/events?stream=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&after=0&limit=25", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"id": "evt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"type": "run.payslip.calculated",
"schema_version": 1,
"org_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"sequence": 0,
"occurred_at": "2026-09-01T09:00:00Z",
"livemode": true,
"mocked": true,
"source": "anchor",
"request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "event",
"stream": "example",
"data": {}
}
],
"has_more": true
}
/v1/sourcing/events/{event_id}#Retrieve an event
sourcing.events.retrieve
Returns one event. An identifier belonging to another organisation comes back as not found, never as refused, so you can't learn whether it exists.
Path parameters
event_id
string
requiredThe event's id, as it reads on an event you listed at GET /v1/sourcing/events or received on a webhook delivery. It starts with evt_.
Returns
The event.
id
string
requiredThe event's identifier, starting with evt_, the same on a webhook delivery and on the module's events list, such as GET /v1/payroll/events. It never changes: a redelivery carries the same id, so you can recognise an event you have already handled.
type
string
requiredWhat happened, as module.resource.past_tense_verb, for example run.payslip.calculated. Pick your handler on it; data takes the shape this type promises.
schema_version
integer · minimum 1
requiredThe version of the shape data takes for this type, starting at 1. A change to the shape raises it, so check it before you read data.
org_id
string
requiredThe organisation the event belongs to, by its id, which starts with org_: the one POST /v1/registrations gave you and GET /v1/me returns. You only ever receive events for your own organisation.
sequence
integer · minimum 0
requiredPer organisation and per stream. It is how a consumer tells a replay from a new event, and it is what the delivery guarantee rests on.
occurred_at
string · date-time
requiredWhen the event happened, as an RFC 3339 timestamp in UTC. Not when it was delivered: a redelivery carries the original value.
request_id
string
optionalThe request that caused this event, where one did: the Droomwork-Request-Id that request returned, starting with req_. Absent for an event a schedule raised, such as an engagement lapsing on its end date.
livemode
boolean
requiredWhich realm the event happened in. False is the sandbox.
mocked
boolean
requiredWhether a mock produced this fact, rather than an engine computing it. Recorded on the event when it was appended and never worked out afterwards from the realm: the two answers agree while every module is on its mock and part on the day the first engine ships. See ADR-0011.
source
string
requiredWhich part of Droomwork is the authority for this fact: anchor (identity), proof (credentials), rail (engagements), flow (sourcing), match (allocation), run (payroll), remit (remittance), route (payouts), gateway (the API's front door), iam (accounts and API keys), ledger (the books), registry (rule packs), delivery (webhooks and messages), documents (rendered payslips and instruments) or intelligence (AI decisions). Read the fact from there when it matters; your own copy is never the authority.
anchorproofrailflowmatchrunremitroutegatewayiamledgerregistrydeliverydocumentsintelligenceobject
always "event"
requiredAlways event. Tells you which kind of record you are looking at, so one handler can read any response.
stream
string
requiredThe id of the record this event is about, such as a requisition's id from POST /v1/sourcing/requisitions (flow_enterprise_requisition_). sequence counts within this stream only; replay with stream and after at GET /v1/sourcing/events.
data
object
requiredThe record the event is about, in the shape its type names: a requisition, a channel delivery, a lead, or your spend ceilings. The same body a webhook delivery carries.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/events/%7Bevent_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingEventsRetrieve({ eventId: '{event_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/events/%7Bevent_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_events_retrieve(event_id='{event_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/events/%7Bevent_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingEventsRetrieve(event_id: '{event_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/events/%7Bevent_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingEventsRetrieve("{event_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/events/%7Bevent_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingEventsRetrieve(eventId: "{event_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/events/%7Bevent_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingEventsRetrieve(ctx, "{event_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/events/%7Bevent_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "evt_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"type": "run.payslip.calculated",
"schema_version": 1,
"org_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"sequence": 0,
"occurred_at": "2026-09-01T09:00:00Z",
"livemode": true,
"mocked": true,
"source": "anchor",
"request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "event",
"stream": "example",
"data": {}
}
/v1/sourcing/audit_entries#List audit entries
sourcing.audit_entries.list
Who did what in your organisation, newest first. One row per attempt, not per success: a refusal is recorded too, and repeated forbidden answers on one credential is what an attack looks like from the inside.
A read that succeeded is not recorded. A log holding every list call is mostly noise.
Query parameters
action
string
optionalThe method and route pattern that was attempted, exactly as action reads on each entry, such as POST /v1/sourcing/requisitions. Leave it out to get attempts on every route.
actor_id
string
optionalThe id of the API key (prefix key_) or staff account that made the attempt, exactly as actor_id reads on each entry. Leave it out to get every actor; pair it with outcome=refused to see repeated refusals on one credential.
resource
string
optionalThe collection segment of the route that was attempted, exactly as resource reads on each entry, such as requisitions, broadcasts or leads. Leave it out to get every kind of record; pair it with resource_id to narrow to one.
resource_id
string
optionalThe id of the record the route named, exactly as resource_id reads on each entry, such as a requisition's id from POST /v1/sourcing/requisitions (flow_enterprise_requisition_). Leave it out to get every record; pair it with resource.
outcome
string
optionalOne outcome only: succeeded (a 2xx answer), refused (a 4xx) or failed (a 5xx). Leave it out to get every outcome; ask for refused to see every attempt that was turned away.
succeededrefusedfailedrecorded_after
string
optionalOnly entries made after this moment, as an RFC 3339 timestamp in UTC, compared with at on each entry; an entry at exactly this instant is left out. Leave it out to reach back to your oldest entry.
recorded_before
string
optionalOnly entries made before this moment, as an RFC 3339 timestamp in UTC, compared with at on each entry; an entry at exactly this instant is left out. Leave it out to read up to now; pair it with recorded_after to read one window.
limit
integer
optionalHow many records to return on one page, from 1 to 100, and 25 if you leave it out. When has_more is true, pass the last record's id as starting_after to get the next page.
starting_after
string
optionalThe id of the last record on the previous page of this same list. Leave it out to get the first page; when a page comes back with has_more true, send its last record's id here to get the page after it.
Returns
A page of audit entries.
object
always "list"
requiredAlways list. Tells you which kind of record you are looking at, so one handler can read any response.
data
array of AuditEntry
requiredThe records on this page, in the order the list promises. Empty when nothing matched.
13 fields of AuditEntry
id
string
requiredThe entry's identifier. It starts with audit_entry_ and never changes; pass it to GET /v1/sourcing/audit_entries/{audit_entry_id} to read this entry again, or as starting_after to page past it.
object
always "audit_entry"
requiredAlways audit_entry. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm the action happened in. False is the sandbox.
mocked
boolean
requiredWhether the route this attempt was aimed at is served by a mock. It is the route and not the answer: a refused attempt and a replayed idempotent request aimed at a mocked route both say so.
at
string · date-time
requiredWhen the attempt was made, as an RFC 3339 timestamp in UTC. The list is ordered by it, newest first.
request_id
string
requiredThe Droomwork-Request-Id the call was answered with. It is on every response, refusals included, so a refusal you were shown can be matched to its entry here.
actor_type
string
requiredWhat kind of credential made the attempt. client is one of your API keys or OAuth clients; staff is a Droomwork staff member on a support grant, the same access /v1/support_access shows you.
actor_id
string
requiredWho made the attempt: with actor_type client, the API key's id as GET /v1/api_keys lists it or the client_id you send to POST /v1/oauth/token, prefix key_; with staff, the staff account's id. Filter by it to follow one credential.
action
string
requiredWhat was attempted, as the method and the route pattern.
resource
string · nullable
optionalThe kind of record the attempt was aimed at, as the collection name in the route, such as requisitions or leads. null when the call reached no route at all.
resource_id
string · nullable
optionalThe id of the record the route named, such as a requisition's id (flow_enterprise_requisition_) on POST /v1/sourcing/requisitions/{requisition_id}/publish. null for an attempt on a collection, such as creating or listing.
outcome
string
requiredHow the attempt ended: succeeded for a 2xx status, refused for a 4xx, failed for a 5xx. It is read from status, so the two never disagree.
succeededrefusedfailedstatus
integer
requiredThe HTTP status the caller was given, such as 201 or 403. It is what outcome is read from.
has_more
boolean
requiredtrue when there are more records after this page. Pass the last record's id as starting_after to get the next page.
Other responses
Errors it can return
# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/audit_entries?action=POST%20%2Fv1%2Fsourcing%2Frequisitions&actor_id=sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=requisitions&resource_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
const result = await api.sourcingAuditEntriesList({ action: 'POST /v1/sourcing/requisitions', actorId: 'sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', resource: 'requisitions', resourceId: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome: 'succeeded', recordedAfter: '2026-01-01T00:00:00Z', recordedBefore: '2027-01-01T00:00:00Z', limit: 25 });// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/audit_entries?action=POST%20%2Fv1%2Fsourcing%2Frequisitions&actor_id=sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=requisitions&resource_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
result = api.sourcing_audit_entries_list(action='POST /v1/sourcing/requisitions', actor_id='sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', resource='requisitions', resource_id='flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome='succeeded', recorded_after='2026-01-01T00:00:00Z', recorded_before='2027-01-01T00:00:00Z', limit=25)import os
import requests
# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/audit_entries?action=POST%20%2Fv1%2Fsourcing%2Frequisitions&actor_id=sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=requisitions&resource_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
# query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
$result = $api->sourcingAuditEntriesList(action: 'POST /v1/sourcing/requisitions', actor_id: 'sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', resource: 'requisitions', resource_id: 'flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z', outcome: 'succeeded', recorded_after: '2026-01-01T00:00:00Z', recorded_before: '2027-01-01T00:00:00Z', limit: 25);<?php
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/audit_entries?action=POST%20%2Fv1%2Fsourcing%2Frequisitions&actor_id=sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=requisitions&resource_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
var result = api.sourcingAuditEntriesList("POST /v1/sourcing/requisitions", "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "requisitions", "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", "succeeded", "2026-01-01T00:00:00Z", "2027-01-01T00:00:00Z", 25, null);// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/audit_entries?action=POST%20%2Fv1%2Fsourcing%2Frequisitions&actor_id=sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=requisitions&resource_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
var result = api.SourcingAuditEntriesList(action: "POST /v1/sourcing/requisitions", actorId: "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", resource: "requisitions", resourceId: "flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z", outcome: "succeeded", recordedAfter: "2026-01-01T00:00:00Z", recordedBefore: "2027-01-01T00:00:00Z", limit: 25);// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/audit_entries?action=POST%20%2Fv1%2Fsourcing%2Frequisitions&actor_id=sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=requisitions&resource_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
result, _, err := client.FLOWAPI.SourcingAuditEntriesList(ctx).Action("POST /v1/sourcing/requisitions").ActorId("sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Resource("requisitions").ResourceId("flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z").Outcome("succeeded").RecordedAfter("2026-01-01T00:00:00Z").RecordedBefore("2027-01-01T00:00:00Z").Limit(25).Execute()// query parameters: action (optional), actor_id (optional), resource (optional), resource_id (optional), outcome (optional), recorded_after (optional), recorded_before (optional), limit (optional), starting_after (optional)
req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/audit_entries?action=POST%20%2Fv1%2Fsourcing%2Frequisitions&actor_id=sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&resource=requisitions&resource_id=flow_enterprise_requisition_01J8XQ4M7K2N9P3R5T7V9W1Y3Z&outcome=succeeded&recorded_after=2026-01-01T00%3A00%3A00Z&recorded_before=2027-01-01T00%3A00%3A00Z&limit=25", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"object": "list",
"data": [
{
"id": "audit_entry_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "audit_entry",
"livemode": true,
"mocked": true,
"at": "2026-09-01T09:00:00Z",
"request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"actor_type": "example",
"actor_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"action": "example",
"outcome": "succeeded",
"status": 1,
"resource": "example",
"resource_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}
],
"has_more": true
}
/v1/sourcing/audit_entries/{audit_entry_id}#Retrieve an audit entry
sourcing.audit_entries.retrieve
Returns one entry. An identifier belonging to another organisation comes back as not found, never as refused, so you can't learn whether it exists.
Path parameters
audit_entry_id
string
requiredThe entry's id, as it reads on an entry you listed at GET /v1/sourcing/audit_entries. It starts with audit_entry_.
Returns
The audit entry.
id
string
requiredThe entry's identifier. It starts with audit_entry_ and never changes; pass it to GET /v1/sourcing/audit_entries/{audit_entry_id} to read this entry again, or as starting_after to page past it.
object
always "audit_entry"
requiredAlways audit_entry. Tells you which kind of record you are looking at, so one handler can read any response.
livemode
boolean
requiredWhich realm the action happened in. False is the sandbox.
mocked
boolean
requiredWhether the route this attempt was aimed at is served by a mock. It is the route and not the answer: a refused attempt and a replayed idempotent request aimed at a mocked route both say so.
at
string · date-time
requiredWhen the attempt was made, as an RFC 3339 timestamp in UTC. The list is ordered by it, newest first.
request_id
string
requiredThe Droomwork-Request-Id the call was answered with. It is on every response, refusals included, so a refusal you were shown can be matched to its entry here.
actor_type
string
requiredWhat kind of credential made the attempt. client is one of your API keys or OAuth clients; staff is a Droomwork staff member on a support grant, the same access /v1/support_access shows you.
actor_id
string
requiredWho made the attempt: with actor_type client, the API key's id as GET /v1/api_keys lists it or the client_id you send to POST /v1/oauth/token, prefix key_; with staff, the staff account's id. Filter by it to follow one credential.
action
string
requiredWhat was attempted, as the method and the route pattern.
resource
string · nullable
optionalThe kind of record the attempt was aimed at, as the collection name in the route, such as requisitions or leads. null when the call reached no route at all.
resource_id
string · nullable
optionalThe id of the record the route named, such as a requisition's id (flow_enterprise_requisition_) on POST /v1/sourcing/requisitions/{requisition_id}/publish. null for an attempt on a collection, such as creating or listing.
outcome
string
requiredHow the attempt ended: succeeded for a 2xx status, refused for a 4xx, failed for a 5xx. It is read from status, so the two never disagree.
succeededrefusedfailedstatus
integer
requiredThe HTTP status the caller was given, such as 201 or 403. It is what outcome is read from.
Other responses
Errors it can return
curl -X GET "https://sandbox.droomwork.io/v1/sourcing/audit_entries/%7Baudit_entry_id%7D" \
-H "Droomwork-Api-Key: $DROOMWORK_API_KEY"import { Configuration, FLOWApi } from '@droomwork/sdk';
const api = new FLOWApi(new Configuration({ basePath: 'https://sandbox.droomwork.io', accessToken: process.env.DROOMWORK_API_KEY }));
const result = await api.sourcingAuditEntriesRetrieve({ auditEntryId: '{audit_entry_id}' });const response = await fetch('https://sandbox.droomwork.io/v1/sourcing/audit_entries/%7Baudit_entry_id%7D', {
method: 'GET',
headers: {
'Droomwork-Api-Key': process.env.DROOMWORK_API_KEY,
},
});
const result = await response.json();import os
import droomwork
config = droomwork.Configuration(access_token=os.environ['DROOMWORK_API_KEY'])
config.host = 'https://sandbox.droomwork.io'
client = droomwork.ApiClient(config)
api = droomwork.FLOWApi(client)
result = api.sourcing_audit_entries_retrieve(audit_entry_id='{audit_entry_id}')import os
import requests
response = requests.request(
'GET',
'https://sandbox.droomwork.io/v1/sourcing/audit_entries/%7Baudit_entry_id%7D',
headers={
'Droomwork-Api-Key': os.environ['DROOMWORK_API_KEY'],
},
)
result = response.json()<?php
require_once __DIR__ . '/vendor/autoload.php';
$config = DroomworkSdk\Configuration::getDefaultConfiguration()
->setHost('https://sandbox.droomwork.io')
->setAccessToken(getenv('DROOMWORK_API_KEY'));
$api = new DroomworkSdk\Api\FLOWApi(new GuzzleHttp\Client(), $config);
$result = $api->sourcingAuditEntriesRetrieve(audit_entry_id: '{audit_entry_id}');<?php
$ch = curl_init('https://sandbox.droomwork.io/v1/sourcing/audit_entries/%7Baudit_entry_id%7D');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => [
'Droomwork-Api-Key: ' . getenv('DROOMWORK_API_KEY'),
],
]);
$result = json_decode(curl_exec($ch), true);import com.droomwork.sdk.ApiClient;
import com.droomwork.sdk.Configuration;
import com.droomwork.sdk.api.FlowApi;
ApiClient client = Configuration.getDefaultApiClient();
client.setBasePath("https://sandbox.droomwork.io");
client.setAccessToken(System.getenv("DROOMWORK_API_KEY"));
FlowApi api = new FlowApi(client);
var result = api.sourcingAuditEntriesRetrieve("{audit_entry_id}");var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://sandbox.droomwork.io/v1/sourcing/audit_entries/%7Baudit_entry_id%7D"))
.header("Droomwork-Api-Key", System.getenv("DROOMWORK_API_KEY"))
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
String result = response.body();using Droomwork.Sdk.Api;
using Droomwork.Sdk.Client;
var config = new Configuration { BasePath = "https://sandbox.droomwork.io" };
config.AccessToken = Environment.GetEnvironmentVariable("DROOMWORK_API_KEY");
var api = new FLOWApi(config);
var result = api.SourcingAuditEntriesRetrieve(auditEntryId: "{audit_entry_id}");using var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://sandbox.droomwork.io/v1/sourcing/audit_entries/%7Baudit_entry_id%7D");
request.Headers.Add("Droomwork-Api-Key", Environment.GetEnvironmentVariable("DROOMWORK_API_KEY"));
var response = await client.SendAsync(request);
var result = await response.Content.ReadAsStringAsync();import droomwork "github.com/fenibofubara/droomwork-sdk-go"
ctx := context.WithValue(context.Background(), droomwork.ContextAPIKeys, map[string]droomwork.APIKey{
"apiKey": {Key: os.Getenv("DROOMWORK_API_KEY")},
})
cfg := droomwork.NewConfiguration()
cfg.Servers = droomwork.ServerConfigurations{{URL: "https://sandbox.droomwork.io"}}
client := droomwork.NewAPIClient(cfg)
result, _, err := client.FLOWAPI.SourcingAuditEntriesRetrieve(ctx, "{audit_entry_id}").Execute()req, _ := http.NewRequest("GET", "https://sandbox.droomwork.io/v1/sourcing/audit_entries/%7Baudit_entry_id%7D", nil)
req.Header.Set("Droomwork-Api-Key", os.Getenv("DROOMWORK_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
{
"id": "audit_entry_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"object": "audit_entry",
"livemode": true,
"mocked": true,
"at": "2026-09-01T09:00:00Z",
"request_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"actor_type": "example",
"actor_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z",
"action": "example",
"outcome": "succeeded",
"status": 1,
"resource": "example",
"resource_id": "sub_01J8XQ4M7K2N9P3R5T7V9W1Y3Z"
}