Jobs
Bulk export PODs or shipping labels
Queue an async POD or shipping label export using POST /dn/jobs/bulk/export. Poll the returned status URL to retrieve the download link.
POST
/
dn
/
jobs
/
bulk
/
export
Bulk export PODs or shipping labels
curl --request POST \
--url https://app.detrack.com/api/v2/dn/jobs/bulk/export \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '
{
"data": {
"ids": [
"<string>"
],
"query": {
"do_numbers": [
"DO-10001",
"DO-10002"
],
"date": "2026-09-15"
},
"document": "job"
}
}
'import requests
url = "https://app.detrack.com/api/v2/dn/jobs/bulk/export"
payload = { "data": {
"ids": ["<string>"],
"query": {
"do_numbers": ["DO-10001", "DO-10002"],
"date": "2026-09-15"
},
"document": "job"
} }
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
data: {
ids: ['<string>'],
query: {do_numbers: ['DO-10001', 'DO-10002'], date: '2026-09-15'},
document: 'job'
}
})
};
fetch('https://app.detrack.com/api/v2/dn/jobs/bulk/export', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.detrack.com/api/v2/dn/jobs/bulk/export",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'ids' => [
'<string>'
],
'query' => [
'do_numbers' => [
'DO-10001',
'DO-10002'
],
'date' => '2026-09-15'
],
'document' => 'job'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.detrack.com/api/v2/dn/jobs/bulk/export"
payload := strings.NewReader("{\n \"data\": {\n \"ids\": [\n \"<string>\"\n ],\n \"query\": {\n \"do_numbers\": [\n \"DO-10001\",\n \"DO-10002\"\n ],\n \"date\": \"2026-09-15\"\n },\n \"document\": \"job\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.detrack.com/api/v2/dn/jobs/bulk/export")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"data\": {\n \"ids\": [\n \"<string>\"\n ],\n \"query\": {\n \"do_numbers\": [\n \"DO-10001\",\n \"DO-10002\"\n ],\n \"date\": \"2026-09-15\"\n },\n \"document\": \"job\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.detrack.com/api/v2/dn/jobs/bulk/export")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": {\n \"ids\": [\n \"<string>\"\n ],\n \"query\": {\n \"do_numbers\": [\n \"DO-10001\",\n \"DO-10002\"\n ],\n \"date\": \"2026-09-15\"\n },\n \"document\": \"job\"\n }\n}"
response = http.request(request)
puts response.read_body{
"status_url": "https://app.detrack.com/api/v2/dn/jobs/export/status/5b22033310c92b1a086ece03"
}{
"code": "invalid_json_format"
}{
"code": "invalid_key",
"message": "Invalid key"
}{
"code": "forbidden"
}{
"code": "validation_failed",
"message": "Validation Failed",
"errors": [
{
"field": "do_number",
"codes": [
"can't be blank"
]
}
]
}Use this endpoint to request a bulk export of shipping labels or proof-of-delivery (POD) documents. The export runs asynchronously. The response contains a
The server picks the file format from the document type, so any
status_url that you poll until the export finishes and a signed download_url becomes available.
Document types
| Value | Output |
|---|---|
job (default) | One PDF containing the proof of delivery for every selected job. |
pod | A ZIP file with a separate POD PDF for each job. |
shipping-labels | One PDF of shipping labels. Note the plural; Download document uses the singular shipping-label. |
format you send is ignored.
Polling for the result
Send a GET request to thestatus_url every 5 to 10 seconds. When the export is complete, the response contains a download_url. The download URL is signed and expires after about 15 minutes. Each status request returns a freshly signed URL.
See Get export status for the polling endpoint details and example response.Authorizations
Your Detrack API key, from Integrations > API Key in the dashboard.
Body
application/json
Select jobs with query.do_numbers, with query.date (every job on that date), or with ids.
Show child attributes
Show child attributes
Response
Queued. The body isn't wrapped in data.
Example:
"https://app.detrack.com/api/v2/dn/jobs/export/status/5b22033310c92b1a086ece03"
Bulk export PODs or shipping labels
curl --request POST \
--url https://app.detrack.com/api/v2/dn/jobs/bulk/export \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '
{
"data": {
"ids": [
"<string>"
],
"query": {
"do_numbers": [
"DO-10001",
"DO-10002"
],
"date": "2026-09-15"
},
"document": "job"
}
}
'import requests
url = "https://app.detrack.com/api/v2/dn/jobs/bulk/export"
payload = { "data": {
"ids": ["<string>"],
"query": {
"do_numbers": ["DO-10001", "DO-10002"],
"date": "2026-09-15"
},
"document": "job"
} }
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
data: {
ids: ['<string>'],
query: {do_numbers: ['DO-10001', 'DO-10002'], date: '2026-09-15'},
document: 'job'
}
})
};
fetch('https://app.detrack.com/api/v2/dn/jobs/bulk/export', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.detrack.com/api/v2/dn/jobs/bulk/export",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'data' => [
'ids' => [
'<string>'
],
'query' => [
'do_numbers' => [
'DO-10001',
'DO-10002'
],
'date' => '2026-09-15'
],
'document' => 'job'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.detrack.com/api/v2/dn/jobs/bulk/export"
payload := strings.NewReader("{\n \"data\": {\n \"ids\": [\n \"<string>\"\n ],\n \"query\": {\n \"do_numbers\": [\n \"DO-10001\",\n \"DO-10002\"\n ],\n \"date\": \"2026-09-15\"\n },\n \"document\": \"job\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.detrack.com/api/v2/dn/jobs/bulk/export")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"data\": {\n \"ids\": [\n \"<string>\"\n ],\n \"query\": {\n \"do_numbers\": [\n \"DO-10001\",\n \"DO-10002\"\n ],\n \"date\": \"2026-09-15\"\n },\n \"document\": \"job\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.detrack.com/api/v2/dn/jobs/bulk/export")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"data\": {\n \"ids\": [\n \"<string>\"\n ],\n \"query\": {\n \"do_numbers\": [\n \"DO-10001\",\n \"DO-10002\"\n ],\n \"date\": \"2026-09-15\"\n },\n \"document\": \"job\"\n }\n}"
response = http.request(request)
puts response.read_body{
"status_url": "https://app.detrack.com/api/v2/dn/jobs/export/status/5b22033310c92b1a086ece03"
}{
"code": "invalid_json_format"
}{
"code": "invalid_key",
"message": "Invalid key"
}{
"code": "forbidden"
}{
"code": "validation_failed",
"message": "Validation Failed",
"errors": [
{
"field": "do_number",
"codes": [
"can't be blank"
]
}
]
}