Order domains
Order domains and mailboxes that are preconfigured for cold emailing and ready to use in Woodpecker. Creating a domain owner is required before placing an order.
Domain and mailbox purchases are paid from your prepaid funds, so you need enough balance before placing an order. After purchase, mailbox renewals are covered by your regular monthly Woodpecker billing cycle. If the order fails because of insufficient funds, add prepaid funds in Woodpecker before retrying.
Request
This endpoint will create billable domain and mailbox assets
Use the get domain providers endpoint to check mailbox pricing, and an availability endpoint to check domain pricing and availability before placing an order. The purchase itself is paid from prepaid funds; ongoing mailbox renewals are billed monthly after purchase.
Endpoint
POST https://api.woodpecker.co/rest/v2/domains/order
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
{
"provider": "GOOGLE",
"domains": [
"piedpiper.com"
],
"mailboxes": [
{
"first_name": "Richard",
"last_name": "Hendricks",
"email": "richard@piedpiper.com"
}
]
}
Body schema
| Field | Type | Required | Description |
|---|---|---|---|
provider | string | Yes | Provider used for the order. Valid values include MAILDOSO, MAILFORGE, GOOGLE, and MICROSOFT. Check providers endpoint to list available providers |
domains | array[string] | Yes | Domains to order. Values must be unique and must not already exist for the account. Use order mailboxes endpoint to purchase mailboxes for an already existing domain |
mailboxes | array | Yes | Mailboxes to order with the domains |
└─ first_name | string | Yes | Mailbox owner's first name. Used to display the 'from name' |
└─ last_name | string | Yes | Mailbox owner's last name. Used to display the 'from name' |
└─ email | string | Yes | Mailbox email address to order |
Request samples
Order a domain with one mailbox
- cURL
- Python
- Java
- Node.js
- PHP
curl --request POST \
--url "https://api.woodpecker.co/rest/v2/domains/order" \
--header "x-api-key: {YOUR_API_KEY}" \
--header "Content-Type: application/json" \
--data '{
"provider": "GOOGLE",
"domains": [
"piedpiper.com"
],
"mailboxes": [
{
"first_name": "Richard",
"last_name": "Hendricks",
"email": "richard@piedpiper.com"
}
]
}'
import requests
def order_domains():
url = "https://api.woodpecker.co/rest/v2/domains/order"
headers = {
"x-api-key": "{YOUR_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"provider": "GOOGLE",
"domains": [
"piedpiper.com"
],
"mailboxes": [
{
"first_name": "Richard",
"last_name": "Hendricks",
"email": "richard@piedpiper.com"
}
]
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 202:
return f"Domain order accepted: {response.status_code}"
else:
raise Exception(f"POST request failed: {response.status_code}, {response.text}")
if __name__ == "__main__":
try:
result = order_domains()
print("POST response:", result)
except Exception as e:
print("Error:", e)
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class WoodpeckerApiClient {
public static void main(String[] args) {
try {
String url = "https://api.woodpecker.co/rest/v2/domains/order";
String jsonData = """
{
"provider": "GOOGLE",
"domains": [
"piedpiper.com"
],
"mailboxes": [
{
"first_name": "Richard",
"last_name": "Hendricks",
"email": "richard@piedpiper.com"
}
]
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("x-api-key", "{YOUR_API_KEY}")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 202) {
System.out.println("POST response: Domain order accepted: " + response.statusCode());
} else {
throw new Exception("POST request failed: " + response.statusCode() + ", " + response.body());
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
const axios = require('axios');
async function orderDomains() {
const url = 'https://api.woodpecker.co/rest/v2/domains/order';
const headers = {
'x-api-key': '{YOUR_API_KEY}',
'Content-Type': 'application/json'
};
const data = {
provider: 'GOOGLE',
domains: [
'piedpiper.com'
],
mailboxes: [
{
first_name: 'Richard',
last_name: 'Hendricks',
email: 'richard@piedpiper.com'
}
]
};
try {
const response = await axios.post(url, data, { headers });
console.log('POST response:', `Domain order accepted: ${response.status}`);
} catch (error) {
console.error('POST request failed:', error.response ? error.response.status : error.message);
}
}
orderDomains();
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$client = new Client([
'base_uri' => 'https://api.woodpecker.co/rest/v2/',
'headers' => [
'x-api-key' => getenv('WOODPECKER_API_KEY'),
'Content-Type' => 'application/json',
],
]);
try {
$response = $client->post('domains/order', [
'json' => [
'provider' => 'GOOGLE',
'domains' => [
'piedpiper.com',
],
'mailboxes' => [
[
'first_name' => 'Richard',
'last_name' => 'Hendricks',
'email' => 'richard@piedpiper.com',
],
],
],
]);
echo $response->getStatusCode(), "\n";
echo $response->getBody(), "\n";
} catch (RequestException $e) {
echo "Error: ", $e->getMessage(), "\n";
if ($e->hasResponse()) {
echo $e->getResponse()->getBody(), "\n";
}
}
Response
Response examples
- 202
- 400
- 401
- 422
- 500
- 503
The order has been accepted for processing. Use the get domain endpoint to review the processing status.
Invalid request or malformed request syntax
{
"title": "Bad Request",
"status": 400,
"details": "error details",
"timestamp": "2026-05-06T12:00:00Z"
}
Body schema
| Field | Type | Description |
|---|---|---|
title | string | A short title describing the error |
status | integer | The HTTP status code |
details | string | A detailed message explaining the error |
timestamp | string | The timestamp when the error occurred |
Authentication failed. Please review the authentication guide
{
"title": "Unauthorized",
"status": 401,
"details": "error details",
"timestamp": "2026-05-06T12:00:00Z"
}
Body schema
| Field | Type | Description |
|---|---|---|
title | string | A short title describing the error |
status | integer | The HTTP status code |
details | string | A detailed message explaining the error |
timestamp | string | The timestamp when the error occurred |
Returned when the request body is valid JSON but contains invalid or missing fields, or when business validation fails before the order can be accepted.
If code is insufficient_funds, add prepaid funds in Woodpecker before retrying the order.
{
"type": "validation_error",
"message": "Invalid field(s)",
"code": "invalid_fields",
"request_id": "dc4faa0f-78bf-54e9-9d5d-ce9538f2eec5",
"fields": [
{
"field": "provider",
"issue": "Valid values are MAILDOSO, MAILFORGE, GOOGLE, MICROSOFT",
"value": "MAILDOSO1"
},
{
"field": "domains[0]",
"issue": "Valid format is example.com",
"value": "invalid_domain"
},
{
"field": "mailboxes[0].email",
"issue": "Valid format is email@example.com",
"value": "invalid"
}
]
}
Body schema
| Field | Type | Description |
|---|---|---|
type | string | Error type |
message | string | Error message |
code | string | Error code. Possible business error values include domain_owner_required, insufficient_funds, payment_failed, domain_unavailable, and domain_price_unavailable |
request_id | string or null | Request identifier when available |
fields | array/null | Fields that failed validation. Present for field-level validation errors |
└─ field | string | Field with a validation issue |
└─ issue | string | Detailed description of the validation issue |
└─ value | string/null | Rejected value, or null for a missing required field |
Unexpected server error
{
"title": "Internal Server Error",
"status": 500,
"details": "error details",
"timestamp": "2026-05-06T12:00:00Z"
}
Body schema
| Field | Type | Description |
|---|---|---|
title | string | A short title describing the error |
status | integer | The HTTP status code |
details | string | A detailed message explaining the error |
timestamp | string | The timestamp when the error occurred |
Service unavailable or communication error
{
"title": "Service Unavailable",
"status": 503,
"details": "error details",
"timestamp": "2026-05-06T12:00:00Z"
}
Body schema
| Field | Type | Description |
|---|---|---|
title | string | A short title describing the error |
status | integer | The HTTP status code |
details | string | A detailed message explaining the error |
timestamp | string | The timestamp when the error occurred |