Add prospects to a campaign
This is a v1 legacy endpoint. It uses a different path /rest/v1
and may return different error codes and response formats compared to v2. While it remains functional, consider handling errors accordingly.
This endpoint allows you to add one or multiple prospects to a campaign prospect list in a single request. Any prospect whose current global status is not ACTIVE
(e.g., REPLIED
, BOUNCED
) will be automatically rejected unless overridden using the 'force' parameter. Duplicate records will return an appropriate message.
- You can add an existing prospect from the global prospect list to a campaign without modifying their data (snippets). To update their information, see this guide
- You can add a prospect directly to a campaign - this will also create a record in the global prospect list.
Request
Endpoint
POST https://api.woodpecker.co/rest/v1/add_prospects_campaign
Headers
x-api-key: {YOUR_API_KEY}
Content-type: application/json
For details on how to authenticate your requests, please see the authentication guide.
Body
The example below shows all available fields. The prospects[].email
and campaign.campaign_id
fields are required, while all other fields are optional. If omitted, these fields will remain blank for new prospects. For existing prospects in your global database, their stored data (snippets) will be used.
You can add up to 20 000 prospects per request
{
"campaign": {
"campaign_id": 1234567,
"send_after": "2025-04-01T00:01:01-0000"
},
"force": false,
"file_name": "API import YYYY-MM-DD",
"prospects": [
{
"email": "erlich@bachman.com",
"status": "ACTIVE",
"first_name": "Erlich",
"last_name": "Bachman",
"company": "Bachmanity",
"website": "http://www.bachmanity.com/",
"linkedin_url": "https://www.linkedin.com/in/erlich-bachman/",
"tags": "#VC",
"title": "VC Angel",
"phone": "111222333",
"address": "221 Newell Rd",
"city": "Palo Alto",
"state": "California",
"country": "USA",
"industry": "Software as a Service",
"snippet1": "Pied Piper board member",
"snippet2": "A personalized sentence <br/> in two lines",
"snippet3": "string",
"snippet4": "string",
"snippet5": "string",
"snippet6": "string",
"snippet7": "string",
"snippet8": "string",
"snippet9": "string",
"snippet10": "string",
"snippet11": "string",
"snippet12": "string",
"snippet13": "string",
"snippet14": "string",
"snippet15": "string"
}
]
}
Body schema
Field | Type | Required | Description |
---|---|---|---|
campaign | object | Yes | Contains campaign data |
└─campaign_id | integer | Yes | Campaign ID to which prospects will be added |
└─send_after | string | No | The earliest date and time prospects can be contacted. Use %2B for + in the timezone (ISO 8601-like format) |
force | boolean | No | Use with caution. Whether to add prospects to a campaign, even if their global status is other than ACTIVE . If true , prospects may be contacted again, even if they have responded in another campaign or opted out. |
file_name | string | No | Name of the import batch, visible in the imported column |
[].prospects | object | Yes | Contains prospect data, there can be multiple prospects |
└─ email | string | Yes | Prospect's email address |
└─ status | string | No | Prospect's status. By default the status is set to ACTIVE . Other available: PAUSED , TO-REVIEW , TO-CHECK ; available with force : BLACKLIST , BOUNCED , INVALID , REPLIED |
└─ first_name | string | No | Prospect's first name |
└─ last_name | string | No | Prospect's last name |
└─ company | string | No | Prospect's company name |
└─ website | string | No | Prospect's website URL |
└─ linkedin_url | string | No | Prospect's LinkedIn profile URL |
└─ tags | string | No | Tags associated with the prospect. Tags start with a # and are separated with a space |
└─ title | string | No | Prospect's job title |
└─ phone | string | No | Prospect's phone number |
└─ address | string | No | Prospect's address |
└─ city | string | No | Prospect's city |
└─ country | string | No | Prospect's country |
└─ snippet | string | No | Prospect custom snippets. There are 15 snippet fields (snippet1 to snippet15 ) |
└─ industry | string | No | Prospect's industry |
└─ state | string | No | Prospect's state or region |
Request sample
Add prospects to campaign
The example below showcases how to add multiple prospects only with selected snippets.
- cURL
- Java
- Node.js
curl --request POST \
--url "https://api.woodpecker.co/rest/v1/add_prospects_campaign" \
--header "x-api-key: {YOUR_API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"campaign": {
"campaign_id": 1234567
},
"prospects": [
{
"email": "jared@piedpiper.com",
"first_name": "Jared",
"last_name": "Dunn",
"company": "Pied Piper",
"snippet1": "Custom snippet value"
},
{
"email": "erlich@bachman.com",
"first_name": "Erlich",
"last_name": "Bachman",
"company": "Aviato",
"snippet1": "Custom snippet value"
}
]
}'
import okhttp3.*;
import java.io.IOException;
public class WoodpeckerApiClient {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
String jsonBody = "{"
+ "\"campaign\": {\"campaign_id\": 1234567},"
+ "\"prospects\": ["
+ " {"
+ " \"email\": \"jared@piedpiper.com\","
+ " \"first_name\": \"Jared\","
+ " \"last_name\": \"Dunn\","
+ " \"company\": \"Pied Piper\","
+ " \"snippet1\": \"Custom snippet value\""
+ " },"
+ " {"
+ " \"email\": \"erlich@bachman.com\","
+ " \"first_name\": \"Erlich\","
+ " \"last_name\": \"Bachman\","
+ " \"company\": \"Aviato\","
+ " \"snippet1\": \"Custom snippet value\""
+ " }"
+ "]"
+ "}";
RequestBody body = RequestBody.create(jsonBody, MediaType.parse("application/json"));
Request request = new Request.Builder()
.url("https://api.woodpecker.co/rest/v1/add_prospects_campaign")
.post(body)
.addHeader("x-api-key", "{YOUR_API_KEY}")
.addHeader("Content-Type", "application/json")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
System.err.println("Request failed: " + response);
} else {
System.out.println("Response: " + response.body().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
const axios = require('axios');
const API_URL = 'https://api.woodpecker.co/rest/v1/add_prospects_campaign';
const API_KEY = '{YOUR_API_KEY}';
const data = {
campaign: {
campaign_id: 1234567
},
prospects: [
{
email: "jared@piedpiper.com",
first_name: "Jared",
last_name: "Dunn",
company: "Pied Piper",
snippet1: "Custom snippet value"
},
{
email: "erlich@bachman.com",
first_name: "Erlich",
last_name: "Bachman",
company: "Aviato",
snippet1: "Custom snippet value"
}
]
};
axios.post(API_URL, data, {
headers: {
'x-api-key': API_KEY,
'Content-Type': 'application/json'
}
})
.then(response => {
console.log('Response:', response.data);
})
.catch(error => {
console.error('Error:', error.response ? error.response.data : error.message);
});
Response
Response examples
- 200 (added)
- 200 (partially added)
- 400
- 400 (bad request)
- 401
- 403
- 404
- 409
- 500
All prospects have been added to the campaign prospect list. The first prospect already existed in the global prospect list, while the second was newly added.
{
"prospects": [
{
"email": "jared@piedpiper.com",
"id": 1091123456,
"prospect": "DUPLICATE"
},
{
"email": "erlich@bachman.com",
"id": 1091123457
}
],
"status": {
"status": "OK",
"code": "OK",
"msg": "OK"
}
}
Body schema
Field | Data Type | Description |
---|---|---|
prospects | array[object] | An array of prospects added to the campaign prospect list |
└─[].email | string | Prospect's email |
└─[].id | integer | Unique ID assigned to the prospect |
└─[].prospect | string/null | DUPLICATE . Indicates that the prospect already exists in the global prospect list but does not prevent them from being added to a campaign |
status | object | Object containing the status details of the request |
└─status | string | General status message |
└─code | string | Code indicating the error category |
└─msg | string | Error message |
Some of the prospects were added. Any duplicates or prospects that could not be added are returned with an appropriate error description. Prospects that return prospect_campaign
are not considered as an error.
{
"prospects": [
{
"email": "erlich.b@bachman.com",
"id": 1091123458
},
{
"email": "jared@piedpiper.com",
"id": 1091123456,
"prospect": "DUPLICATE",
"prospect_campaign": "DUPLICATE"
},
{
"email": "erlichbachman.com",
"status": "ERROR",
"code": "E_EMAIL",
"msg": "This looks like invalid email format: erlichbachman.com"
}
],
"status": {
"status": "OK",
"code": "OK",
"msg": "OK"
}
}
Body schema
Field | Data Type | Description |
---|---|---|
prospects | array[object] | An array of processed prospects |
└─[].email | string | Prospect's email |
└─[].id | integer/null | Unique ID assigned to the prospect if successfully added. For duplicates, returns the ID of the existing prospect |
└─[].prospect | string/null | DUPLICATE . Indicates that the prospect already exists in the global prospect list but does not prevent them from being added to a campaign |
└─[].prospect_campaign | string/null | DUPLICATE . Indicates that the prospect already exists in this campaign's prospect list. Prospect remains unmodified |
└─[].status | string/null | ERROR . Returned if the prospect has not been added |
└─[].code | string/null | Code indicating the error category. Returned if the prospect has not been added |
└─[].msg | string/null | Descriptive error message. Returned if the prospect has not been added |
status | object | Object containing the status details of the request |
└─status | string | General status message |
└─code | string | Code indicating the error category |
└─msg | string | Error message |
None of the requested prospects have been added to the prospect list. For Status is other than ACTIVE.
error message, please refer to force
in the request body
{
"prospects": [
{
"email": "jared@piedpiper.com",
"id": 1091123456,
"prospect": "DUPLICATE",
"status": "ERROR",
"code": "E_INV_STATUS",
"msg": "Status is other than ACTIVE."
},
{
"email": "erlichbachman.com",
"status": "ERROR",
"code": "E_EMAIL",
"msg": "This looks like invalid email format: erlichbachman.com"
}
],
"status": {
"status": "ERROR",
"code": "E_INV_STATUS",
"msg": "Status is other than ACTIVE."
}
}
Body schema
A list of all available status.code
values is available here
Field | Data Type | Description |
---|---|---|
prospects | array[object] | An array of processed prospects |
└─[].email | string | Prospect's email |
└─[].id | integer/null | Unique ID assigned to the prospect if successfully added. For duplicates, returns the ID of the existing prospect |
└─[].prospect | string/null | DUPLICATE . Indicates that the prospect already exists in the global prospect list but does not prevent them from being added to a campaign |
└─[].prospect_campaign | string/null | DUPLICATE . Indicates that the prospect already exists in this campaign's prospect list. Prospect remains unmodified |
└─[].status | string/null | ERROR . Returned if the prospect has not been added |
└─[].code | string/null | Code indicating the error category. Returned if the prospect has not been added |
└─[].msg | string/null | Descriptive error message. Returned if the prospect has not been added |
status | object | Object containing the status details of the request |
└─status | string | ERROR . General status message |
└─code | string | Code indicating the error category |
└─msg | string | Error message |
Invalid request or malformed request syntax.
{
"status": {
"status": "ERROR",
"code": "E_PARSER_ERROR" | "E_RECORD_NOT_FOUND",
"msg": "Invalid request body." | "Campaign not found." | "Campaign ID not found."
}
}
Body schema
A list of all available status.code
values is available here
Field | Data Type | Description |
---|---|---|
status | object | Contains error details |
└─status | string | Overall status, set to ERROR for non-2xx responses |
└─code | string | Code indicating the error category |
└─msg | string | Descriptive error message |
An issue with authorization. Please review the authorization guide
{
"status": {
"status": "ERROR",
"code": "E_SESSION",
"msg": "The API key you've entered is incorrect or no longer valid. Check if you pasted the key correctly. You can generate a new key in Woodpecker: Settings -> API Keys."
}
}
Body schema
A list of all available status.code
values is available here
Field | Data Type | Description |
---|---|---|
status | object | Contains error details |
└─status | string | Overall status, set to ERROR for non-2xx responses |
└─code | string | Code indicating the error category |
└─msg | string | Descriptive error message |
API access denied. You subscription might not be active, lack the API add-on, or the key belongs to an inactive client company.
{
"status": {
"status": "ERROR",
"code": "E_NO_PERMISSION",
"msg": "Api access denied." | "You need to have an API keys addon to access our API."
}
}
Body schema
A list of all available status.code
values is available here
Field | Data Type | Description |
---|---|---|
status | object | Contains error details |
└─status | string | Overall status, set to ERROR for non-2xx responses |
└─code | string | Code indicating the error category |
└─msg | string | Descriptive error message |
Please review the request URL
{
"status": {
"status": "ERROR",
"code": "E_URL_NOT_FOUND",
"msg": "URL not found: /Woodpecker/rest/v1/webhooks/someMadeUpURL"
}
}
Body schema
A list of all available status.code
values is available here
Field | Data Type | Description |
---|---|---|
status | object | Contains error details |
└─status | string | Overall status, set to ERROR for non-2xx responses |
└─code | string | Code indicating the error category |
└─msg | string | Descriptive error message |
Please review the rate limits. API v1 is subject to the same rate limits as v2, however the response code is 409
instead of 429
.
{
"status": {
"status": "ERROR",
"code": "E_TOO_MANY_REQUESTS",
"msg": "Too many requests in one time"
}
}
Body schema
A list of all available status.code
values is available here
Field | Data Type | Description |
---|---|---|
status | object | Contains error details |
└─status | string | Overall status, set to ERROR for non-2xx responses |
└─code | string | Code indicating the error category |
└─msg | string | Descriptive error message |
An unknown error. Please try again later.
{
"status": {
"status": "ERROR",
"code": "E_UNNOWN",
"msg": "Unknown error."
}
}
Body schema
A list of all available status.code
values is available here
Field | Data Type | Description |
---|---|---|
status | object | Contains error details |
└─status | string | Overall status, set to ERROR for non-2xx responses |
└─code | string | Code indicating the error category |
└─msg | string | Descriptive error message |