Async API Request ID Correlation Release Notes - January 2026
Release Date: January 2026
Affected Endpoints:
- POST /api/v1/property/search/async
- POST /api/v1/property/lookup/async
- POST /api/v1/property/skip-trace/async
- POST /api/v1/phone/verification/async
- POST /api/v1/phone/dnc/async
- POST /api/v1/phone/tcpa/async
Overview
This release introduces Request ID Correlation for all async API endpoints, enabling you to reliably match async requests with their webhook responses. Previously, when using async endpoints, correlating the webhook callback to its original request required custom tracking logic. Now, every async request returns a unique requestId that is echoed back in the webhook response.
What's New
1. Immediate Request ID in Async Responses
All async endpoints now return a requestId in the immediate HTTP response. This ID uniquely identifies your request and will match the meta.requestId in the webhook callback.
Before:
{
"status": {
"code": 200,
"text": "OK"
}
}
After:
{
"status": {
"code": 200,
"text": "OK"
},
"requestId": "01KEVP1WBGPDR87GMRPSHWK131"
}
2. ULID Format for Request IDs
All requestId values now use the ULID (Universally Unique Lexicographically Sortable Identifier) format:
Property | Description |
Length | 26 characters |
Character Set | Uppercase alphanumeric (Crockford Base32) |
Example |
|
Sortable | Yes - ULIDs sort lexicographically by creation time |
Uniqueness | Guaranteed unique across all requests |
Benefits of ULID format:
- Time-ordered: IDs created later sort after earlier IDs
- URL-safe: No special characters
- Case-insensitive: Works reliably in any system
- Debuggable: Timestamp extractable for troubleshooting
3. Self-Contained Webhook Responses
Async webhook responses now include all context needed to process results without looking up the original request:
Request metadata echoed in the response
Search criteria included for search endpoints
Original request data returned for correlation
Example Webhook Payload:
{
"results": {
"properties": [...],
"meta": {
"results": {
"requestCount": 1,
"matchCount": 1,
"noMatchCount": 0,
"errorCount": 0
},
"performance": {
"totalRequestTime": 1234,
"startTime": "2026-01-13T14:06:08.465Z",
"endTime": "2026-01-13T14:06:09.699Z"
},
"requestId": "01KEVP1WBGPDR87GMRPSHWK131",
"apiVersion": "6.72.0"
},
"searchCriteria": {
"query": "Phoenix, AZ",
"building": {
"bedrooms": { "min": 3 }
}
}
}
}
How to Use Request ID Correlation
Basic Workflow
1. Send async request
POST /api/v1/property/search/async2. Receive immediate response with requestId
{ "status": {...}, "requestId": "01KEVP1WBGPDR87GMRPSHWK131" }3. Store requestId with your internal job/order ID4. Webhook arrives with results
{ "results": { "meta": { "requestId": "01KEVP1WBGPDR87GMRPSHWK131" }, ... } }5. Match webhook to original request using requestId
Implementation Example
Python Example:
import requests
import json# Track pending requests
pending_requests = {}def send_async_search(search_criteria, internal_job_id):
"""Send async search and track the request ID"""
response = requests.post(
"https://api.batchdata.com/api/v1/property/search/async",
headers={
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json"
},
json={
"searchCriteria": search_criteria,
"webhookUrl": "https://your-webhook.com/callback"
}
) data = response.json()
request_id = data.get("requestId") # Store mapping of API request ID to your internal ID
pending_requests[request_id] = {
"internal_job_id": internal_job_id,
"search_criteria": search_criteria,
"sent_at": datetime.now()
} return request_iddef handle_webhook(webhook_payload):
"""Process webhook callback and match to original request"""
request_id = webhook_payload["results"]["meta"]["requestId"] # Find the original request
original_request = pending_requests.get(request_id)
if original_request:
internal_job_id = original_request["internal_job_id"]
# Process results for your internal job
process_results(internal_job_id, webhook_payload["results"])
# Clean up
del pending_requests[request_id]
Breaking Change: Skip Trace V3
Removed Fields
The following fields have been removed from Skip Trace V3 (/api/v3/property/skip-trace) responses:
Removed Field | Replacement |
| Use |
| Use array index position for ordering |
Migration Guide
Before (deprecated):
{
"results": {
"data": [
{
"inputId": "custom-id-123",
"inputIndex": 0,
"contacts": [...]
}
]
}
}
After:
{
"results": {
"data": [
{
"input": {
"requestId": "custom-id-123"
},
"contacts": [...]
}
],
"meta": {
"requestId": "01KEVP28S5B241XVJR5AN4PS0V"
}
}
}
Migration steps:
1. Replace inputId references with input.requestId
2. Use array index (results.data[0], results.data[1], etc.) instead of inputIndex
3. Update any code that parses the deprecated field locations
Per-Item Request ID for Property Lookup
The Property Lookup API (/api/v1/property/lookup/all-attributes) supports per-item requestId values, enabling you to correlate individual items in batch requests back to your source records.
Two Types of Request IDs
Type | Location | Purpose | Format |
API Call ID |
| Identifies the entire API call for support/debugging | ULID (26 chars) |
Per-Item ID |
| Correlates individual items in batch requests | Your value or auto-generated |
How It Works
If you provide a
requestId: Your value is echoed back unchanged in the responseIf you don't provide one: A short ID is auto-generated
Use per-item IDs to match results back to your original input records
Property Lookup Example
Request:
{
"requests": [
{
"address": {
"street": "123 Main St",
"city": "Phoenix",
"state": "AZ",
"zip": "85001"
},
"requestId": "my-property-001"
},
{
"address": {
"street": "456 Oak Ave",
"city": "Tempe",
"state": "AZ",
"zip": "85281"
},
"requestId": "my-property-002"
}
]
}
Response:
{
"results": {
"properties": [
{
"address": {...},
"meta": {
"requestId": "my-property-001"
}
},
{
"address": {...},
"meta": {
"requestId": "my-property-002"
}
}
],
"meta": {
"apiVersion": "6.71.0",
"requestId": "01KEVP21JEPJ1XQTE1TJSN94FQ"
}
}
}
Use Cases
Batch Processing Correlation:
# Build batch request with your database IDs
records = [
{"id": "DB-001", "address": "123 Main St, Phoenix, AZ"},
{"id": "DB-002", "address": "456 Oak Ave, Tempe, AZ"},
]requests = [{
"address": parse_address(r["address"]),
"requestId": r["id"] # Use your database ID
} for r in records]# Send batch request
response = api.property_lookup(requests=requests)# Match results back to your records
for prop in response["results"]["properties"]:
db_id = prop["meta"]["requestId"]
# Update your database record using the matched ID
Debugging Failed Items:
{
"results": {
"properties": [
{"meta": {"requestId": "prop-001"}, "address": {...}},
{"meta": {"requestId": "prop-002", "error": true}, "errorMessage": "Address not found"}
]
}
}
Best Practices
Use meaningful IDs - Include identifiers from your system (database IDs, file row numbers) rather than random strings
Keep IDs unique per batch - Each item should have a unique
requestIdto avoid confusionLog the API Call ID - Always log
results.meta.requestIdfor support requests and debugging
Customer Impact
Before
No standard way to correlate async requests with webhook responses
Required custom tracking logic and database lookups
Skip Trace V3 used deprecated
inputId/inputIndexfieldsRequest IDs used inconsistent formats (ShortId, NanoId)
After
Immediate
requestIdreturned for all async requestsDirect correlation between request and webhook using
requestIdSelf-contained webhook responses include original request context
Consistent ULID format across all endpoints
Skip Trace V3 uses standard
requestIdpattern
Backward Compatibility
Existing integrations continue to work without changes
The
requestIdin async responses is a new field (additive change)Skip Trace V3 field removal is a breaking change for customers using
inputId/inputIndexWebhook payloads now include additional context fields (additive change)
Frequently Asked Questions
Q: Do I need to change my existing integrations?
A: Only if you use Skip Trace V3 and rely on inputId or inputIndex fields. All other integrations continue to work unchanged.
Q: Can I provide my own requestId for async requests?
A: The HTTP-level requestId is always system-generated. For batch endpoints that support per-item requestId, you can provide your own value which will be echoed back.
Q: What format should custom per-item requestId values use?
A: You can use any string value. Common choices include database IDs, UUIDs, or your own identifiers.
Q: Is the requestId guaranteed to be unique?
A: Yes. System-generated ULIDs are guaranteed unique. For custom per-item IDs, uniqueness is your responsibility.
Q: How long should I retain requestId mappings?
A: We recommend retaining mappings until you receive the webhook callback, plus a buffer period for retries. Webhook callbacks typically arrive within minutes but may take longer for large result sets.
Q: What if my webhook doesn't receive a callback?
A: Contact support with your requestId for troubleshooting. The ULID format includes a timestamp component that helps us locate your request in our logs.
Support
If you have questions about Request ID correlation or need assistance with your integration:
Documentation: developer.batchdata.com
Support Email: support@batchdata.com
API Status: status.batchdata.com
Technical Notes
ULID Specification
ULIDs follow the ULID specification:
01AN4Z07BY 79KA1307SR9X4MV3 |----------| |----------------| Timestamp Randomness 48bits 80bits
Timestamp: Millisecond precision, encoded in first 10 characters
Randomness: 80 bits of randomness for uniqueness within the same millisecond
Encoding: Crockford Base32 (excludes I, L, O, U to avoid confusion)
Async Request Flow
βββββββββββββββββββ βββββββββββββββββββββ βββββββββββββββββββ
β Your Client β β BatchData API β β Your Webhook β
ββββββββββ¬βββββββββ βββββββββββ¬ββββββββββ ββββββββββ¬βββββββββ
β β β
β POST /async β β
β {webhookUrl: "..."} β β
ββββββββββββββββββββββββ>β β
β β β
β 200 OK β β
β {requestId: "01KEV.."β β
β<ββββββββββββββββββββββββ β
β β β
β Store requestId β Process request β
β with your job ID β (async) β
β β β
β β POST webhook β
β β {meta: {requestId: β
β β "01KEV.."}, ...} β
β ββββββββββββββββββββββββ>β
β β β
β β β Match requestId
β β β to original job
β β β
β β 200 OK β
β β<ββββββββββββββββββββββββ
β β β
Last Updated: January 2026
