Fetch Request Result
The POST /request/result endpoint retrieves the result of an asynchronous task
that was previously created using the POST /request/create endpoint. After you
submit a request through the create endpoint, the BBRE engine processes it in the background
and you receive a task ID. This endpoint is how you check on that task and eventually retrieve
the full response data once processing is complete. The result endpoint is designed around a
polling pattern: your application calls it repeatedly with the task ID until the task reaches
a terminal state (completed, failed, or timeout). When the task completes successfully, the
response includes the full HTTP response from the target server, including the status code,
response headers, response body, cookies set by the server, and the browser fingerprint profile
that was used during the request. If the task fails or times out, the response includes error
details and your account balance is automatically refunded. Once a task reaches the completed
state, the result is cached internally, so subsequent calls with the same task ID return the
cached result immediately without any additional processing. This page provides a complete
reference for the result endpoint, including all possible response statuses, detailed field
descriptions, polling implementation strategies with exponential backoff, complete workflow
examples in JavaScript, Python, and cURL, error handling patterns, and best practices for
building robust polling logic in production systems.
This endpoint is designed to be called repeatedly until the task reaches a terminal state.
A task can be in one of four states: processing (still working),
completed (result available), failed (error occurred), or
timeout (processing exceeded the time limit). When the status is
processing, wait a short interval and call the endpoint again. A polling
interval of 2 seconds works well for most use cases. If you are using the Node.js SDK
(mydisctsolver-bbre), the polling is handled automatically by the
client.request() method, so you do not need to implement it yourself.
Endpoint
Authentication
All requests to the BBRE API require authentication via an API key. You must include your API
key in the HTTP headers of every request. The API accepts the key through either the
x-api-key header or the apikey header. Both header names are
supported and functionally identical. If no API key is provided, the API returns a
401 error with the API_KEY_REQUIRED error code. If the provided
key is invalid, the API returns a 403 error with the INVALID_API_KEY
error code. The task you are querying must belong to the authenticated user. You cannot
retrieve results for tasks created by other accounts.
| Header | Type | Required | Description |
|---|---|---|---|
x-api-key |
string | required | Your BBRE API key. You can find this in your MyDisct Solver dashboard. |
Content-Type |
string | required | Must be set to application/json for all requests. |
Request Body Parameters
The request body must be a JSON object containing the task ID of the asynchronous request
you want to check. This endpoint accepts a single parameter. The task ID is the value
returned by the POST /request/create endpoint when you initially submitted
the request. Each task ID is unique and tied to your account, so you can only retrieve
results for tasks that were created with your API key.
| Parameter | Type | Required | Description |
|---|---|---|---|
taskId |
string | required | The unique task identifier returned by POST /request/create. This ID is used to track and retrieve the result of your asynchronous request. Example: "task_abc123def456" |
Response Statuses
The result endpoint returns different response structures depending on the current state of
the task. There are four possible task statuses, each with its own response format. Understanding
these statuses is critical for building a reliable polling loop. The processing
status means the task is still being worked on and you should poll again after a short delay.
The completed status means the result is ready and includes the full HTTP response
data. The failed and timeout statuses are terminal error states
where the balance is automatically refunded to your account.
| Status | Terminal | Balance Refund | Description |
|---|---|---|---|
processing |
No | N/A | The BBRE engine is still processing the request. Poll again after a short interval. |
completed |
Yes | No | The request was processed successfully. The full result is included in the response. |
failed |
Yes | Yes | The request failed during processing. The deducted balance is refunded automatically. |
timeout |
Yes | Yes | The request exceeded the configured timeout duration. The deducted balance is refunded automatically. |
Completed Response (200)
When the task completes successfully, the response includes the full HTTP response from the
target server. The result object contains the HTTP status code, response headers,
response body, cookies set by the server, and the browser fingerprint profile used during the
request. The processingTime field indicates how long the BBRE engine took to
process the request, measured in milliseconds. Once a task reaches the completed state, the
result is cached, so calling this endpoint again with the same task ID returns the cached
result immediately.
{
"success": true,
"service": "MyDisct Solver BBRE",
"data": {
"task": {
"id": "task_abc123def456",
"status": "completed",
"result": {
"statusCode": 200,
"headers": {
"content-type": "text/html; charset=utf-8",
"server": "nginx",
"x-powered-by": "Express",
"cache-control": "no-cache"
},
"body": "<html><head><title>Example</title></head><body>...</body></html>",
"cookies": {
"session_id": "s3ss10n_v4lu3",
"tracking": "tr4ck_abc"
},
"profile": {
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"platform": "Win32",
"screen": {
"width": 1920,
"height": 1080
},
"timezone": "America/New_York",
"language": "en-US"
}
}
},
"processingTime": 2345
}
}
Processing Response (200)
When the task is still being processed by the BBRE engine, the response indicates that the task is in progress. This is the status you will see most frequently during polling. When you receive this response, wait for your configured polling interval (recommended: 2 seconds) and then call the endpoint again. The processing duration depends on the mode and sensibility settings used when creating the task. Passive mode requests typically complete within 2-5 seconds, while adaptive mode requests may take 10-30 seconds or longer depending on page complexity and the target site's response time.
{
"success": true,
"service": "MyDisct Solver BBRE",
"data": {
"task": {
"id": "task_abc123def456",
"status": "processing"
}
},
"message": "Task is still processing"
}
Failed Response (200)
When the BBRE engine encounters an error while processing the request, the task enters the failed state. This can happen for various reasons: the target server returned an unrecoverable error, the proxy connection failed, the browser instance crashed during adaptive mode processing, or an internal service error occurred. When a task fails, the balance that was deducted when the task was created is automatically refunded to your account. You do not need to take any action to receive the refund. The error object in the response contains a message describing what went wrong.
{
"success": true,
"service": "MyDisct Solver BBRE",
"data": {
"task": {
"id": "task_abc123def456",
"status": "failed"
},
"error": {
"message": "Request failed"
}
}
}
Timeout Response (200)
When the BBRE engine cannot complete the request within the configured timeout duration, the
task enters the timeout state. The timeout value is set when creating the task through the
timeout parameter on the POST /request/create endpoint (default:
30 seconds). Timeout is a specific type of failure that indicates the request took too long
rather than encountering a processing error. Like the failed state, the balance is
automatically refunded when a task times out. If you frequently encounter timeouts, consider
increasing the timeout value, switching to passive mode for faster processing, or checking
whether the target server is responding slowly.
{
"success": true,
"service": "MyDisct Solver BBRE",
"data": {
"task": {
"id": "task_abc123def456",
"status": "timeout"
},
"error": {
"message": "Request timeout"
}
}
}
Response Field Descriptions
The following table describes every field that can appear in the response from this endpoint.
Not all fields are present in every response. The fields available depend on the task status.
For example, the result object is only present when the status is
completed, and the error object is only present when the status
is failed or timeout.
| Field | Type | Description |
|---|---|---|
success |
boolean | Indicates whether the API call itself was successful. Always true for valid requests, even if the task status is failed or timeout. |
service |
string | Always "MyDisct Solver BBRE". Identifies the service that processed the request. |
data.task.id |
string | The unique task identifier that was provided in the request body. |
data.task.status |
string | The current status of the task. One of: "processing", "completed", "failed", or "timeout". |
data.task.result |
object | The full HTTP response data. Only present when status is "completed". |
data.task.result.statusCode |
number | The HTTP status code returned by the target server (e.g., 200, 301, 403, 500). |
data.task.result.headers |
object | The HTTP response headers from the target server as key-value pairs. Header names are lowercase. |
data.task.result.body |
string | The response body from the target server. For HTML pages, this is the full HTML source. For JSON APIs, this is the JSON string. For adaptive mode, this is the rendered DOM after JavaScript execution. |
data.task.result.cookies |
object | Cookies set by the target server during the request, as key-value pairs. Useful for maintaining session state across multiple requests. |
data.task.result.profile |
object / null | The browser fingerprint profile used during the request. Contains fields like userAgent, platform, screen, timezone, and language. May be null if profile data is not available. |
data.processingTime |
number | The total time the BBRE engine spent processing the request, in milliseconds. Only present when status is "completed". Useful for monitoring performance and tuning timeout values. |
data.error |
object | Error details. Only present when status is "failed" or "timeout". |
data.error.message |
string | A human-readable description of what went wrong during processing. |
message |
string | A human-readable status message. Present when the task is still processing. |
Basic Usage Examples
The following examples show how to call the POST /request/result endpoint to
check the status of a task. These are single-call examples that demonstrate the request
format. For complete polling implementations that handle all status transitions, see the
Polling Implementation section below.
const axios = require("axios");
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";
async function fetchResult(taskId) {
const response = await axios.post(
API_BASE + "/request/result",
{ taskId: taskId },
{
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
}
}
);
const data = response.data.data;
console.log("Task ID:", data.task.id);
console.log("Status:", data.task.status);
if (data.task.status === "completed") {
console.log("Status Code:", data.task.result.statusCode);
console.log("Body Length:", data.task.result.body.length);
console.log("Processing Time:", data.processingTime, "ms");
}
return data;
}
fetchResult("task_abc123def456");
import requests
API_BASE = "https://bbre-solver-api.mydisct.com"
API_KEY = "YOUR_API_KEY"
headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY
}
response = requests.post(
API_BASE + "/request/result",
headers=headers,
json={"taskId": "task_abc123def456"}
)
data = response.json()["data"]
print("Task ID:", data["task"]["id"])
print("Status:", data["task"]["status"])
if data["task"]["status"] == "completed":
print("Status Code:", data["task"]["result"]["statusCode"])
print("Body Length:", len(data["task"]["result"]["body"]))
print("Processing Time:", data["processingTime"], "ms")
curl -X POST https://bbre-solver-api.mydisct.com/request/result \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"taskId": "task_abc123def456"
}'
Polling Implementation Guide
Building a robust polling loop is essential for working with the asynchronous BBRE request system. A well-designed polling implementation handles all four task statuses correctly, uses appropriate intervals to avoid unnecessary API calls, implements a maximum attempt limit to prevent infinite loops, and optionally uses exponential backoff to reduce load during longer processing times. The following sections cover different polling strategies from simple to production-grade.
Simple Polling Loop
The simplest polling approach uses a fixed interval between each check. This works well for most use cases and is easy to understand and debug. The loop checks the task status on each iteration and exits when a terminal state is reached.
const axios = require("axios");
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";
const apiHeaders = {
"Content-Type": "application/json",
"x-api-key": API_KEY
};
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function pollForResult(taskId) {
const maxAttempts = 60;
const pollInterval = 2000;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const response = await axios.post(
API_BASE + "/request/result",
{ taskId: taskId },
{ headers: apiHeaders }
);
const data = response.data.data;
const status = data.task.status;
if (status === "completed") {
console.log("Completed in", data.processingTime, "ms");
return data.task.result;
}
if (status === "failed") {
throw new Error("Task failed: " + data.error.message);
}
if (status === "timeout") {
throw new Error("Task timed out: " + data.error.message);
}
console.log("Attempt", attempt, "- still processing...");
await sleep(pollInterval);
}
throw new Error("Polling limit reached after " + maxAttempts + " attempts");
}
pollForResult("task_abc123def456");
Polling with Exponential Backoff
Exponential backoff is a more sophisticated polling strategy that starts with short intervals and gradually increases the wait time between each attempt. This approach is ideal for production systems because it reduces the number of API calls during longer processing times while still providing fast response detection for quick tasks. The backoff starts at 1 second and doubles with each attempt, capped at a maximum interval to prevent excessively long waits.
const axios = require("axios");
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";
const apiHeaders = {
"Content-Type": "application/json",
"x-api-key": API_KEY
};
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function pollWithBackoff(taskId, options) {
const maxAttempts = options.maxAttempts || 30;
const initialInterval = options.initialInterval || 1000;
const maxInterval = options.maxInterval || 10000;
const backoffMultiplier = options.backoffMultiplier || 2;
let currentInterval = initialInterval;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const response = await axios.post(
API_BASE + "/request/result",
{ taskId: taskId },
{ headers: apiHeaders }
);
const data = response.data.data;
const status = data.task.status;
if (status === "completed") {
return data.task.result;
}
if (status === "failed") {
throw new Error("Task failed: " + data.error.message);
}
if (status === "timeout") {
throw new Error("Task timed out: " + data.error.message);
}
console.log("Attempt", attempt, "- waiting", currentInterval, "ms");
await sleep(currentInterval);
currentInterval = Math.min(
currentInterval * backoffMultiplier,
maxInterval
);
}
throw new Error("Polling limit reached");
}
pollWithBackoff("task_abc123def456", {
maxAttempts: 30,
initialInterval: 1000,
maxInterval: 10000,
backoffMultiplier: 2
});
import requests
import time
API_BASE = "https://bbre-solver-api.mydisct.com"
API_KEY = "YOUR_API_KEY"
headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY
}
def poll_with_backoff(task_id, max_attempts=30, initial_interval=1, max_interval=10):
current_interval = initial_interval
for attempt in range(1, max_attempts + 1):
response = requests.post(
API_BASE + "/request/result",
headers=headers,
json={"taskId": task_id}
)
data = response.json()["data"]
status = data["task"]["status"]
if status == "completed":
return data["task"]["result"]
if status == "failed":
raise Exception("Task failed: " + data["error"]["message"])
if status == "timeout":
raise Exception("Task timed out: " + data["error"]["message"])
print(f"Attempt {attempt} - waiting {current_interval}s")
time.sleep(current_interval)
current_interval = min(current_interval * 2, max_interval)
raise Exception("Polling limit reached")
result = poll_with_backoff("task_abc123def456")
TASK_ID="task_abc123def456"
API_KEY="YOUR_API_KEY"
MAX_ATTEMPTS=30
INTERVAL=2
for i in $(seq 1 $MAX_ATTEMPTS); do
RESPONSE=$(curl -s -X POST https://bbre-solver-api.mydisct.com/request/result \
-H "Content-Type: application/json" \
-H "x-api-key: $API_KEY" \
-d "{\"taskId\": \"$TASK_ID\"}")
STATUS=$(echo $RESPONSE | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['task']['status'])")
echo "Attempt $i - Status: $STATUS"
if [ "$STATUS" = "completed" ]; then
echo "Task completed!"
echo $RESPONSE | python3 -m json.tool
break
fi
if [ "$STATUS" = "failed" ] || [ "$STATUS" = "timeout" ]; then
echo "Task ended with status: $STATUS"
echo $RESPONSE | python3 -m json.tool
break
fi
sleep $INTERVAL
done
Complete Create-and-Poll Workflow
The most common usage pattern combines the POST /request/create and
POST /request/result endpoints into a single workflow. The following examples
demonstrate the complete flow from creating a task to retrieving and processing the result.
These are production-ready examples that handle all status transitions, implement proper
error handling, and use exponential backoff for efficient polling.
JavaScript Complete Workflow
const axios = require("axios");
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";
const apiHeaders = {
"Content-Type": "application/json",
"x-api-key": API_KEY
};
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function bbRequest(url, options) {
const createResponse = await axios.post(
API_BASE + "/request/create",
{
url: url,
method: options.method || "GET",
mode: options.mode || "passive",
sensibility: options.sensibility || "medium",
headers: options.headers || {},
body: options.body || null,
timeout: options.timeout || 30
},
{ headers: apiHeaders }
);
const taskId = createResponse.data.task.id;
console.log("Task created:", taskId);
let interval = 1000;
const maxInterval = 10000;
const maxAttempts = 60;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
await sleep(interval);
const resultResponse = await axios.post(
API_BASE + "/request/result",
{ taskId: taskId },
{ headers: apiHeaders }
);
const data = resultResponse.data.data;
const status = data.task.status;
if (status === "completed") {
console.log("Completed in", data.processingTime, "ms");
return {
statusCode: data.task.result.statusCode,
headers: data.task.result.headers,
body: data.task.result.body,
cookies: data.task.result.cookies,
profile: data.task.result.profile,
processingTime: data.processingTime
};
}
if (status === "failed") {
throw new Error("Request failed: " + data.error.message);
}
if (status === "timeout") {
throw new Error("Request timed out: " + data.error.message);
}
interval = Math.min(interval * 1.5, maxInterval);
}
throw new Error("Polling limit reached");
}
async function main() {
const result = await bbRequest("https://example.com/products", {
mode: "passive",
sensibility: "medium",
timeout: 60
});
console.log("HTTP Status:", result.statusCode);
console.log("Content-Type:", result.headers["content-type"]);
console.log("Body Length:", result.body.length);
console.log("Cookies:", JSON.stringify(result.cookies));
console.log("Total Time:", result.processingTime, "ms");
}
main();
Python Complete Workflow
import requests
import time
API_BASE = "https://bbre-solver-api.mydisct.com"
API_KEY = "YOUR_API_KEY"
api_headers = {
"Content-Type": "application/json",
"x-api-key": API_KEY
}
def bbre_request(url, method="GET", mode="passive", sensibility="medium",
custom_headers=None, body=None, timeout=30):
create_response = requests.post(
API_BASE + "/request/create",
headers=api_headers,
json={
"url": url,
"method": method,
"mode": mode,
"sensibility": sensibility,
"headers": custom_headers or {},
"body": body,
"timeout": timeout
}
)
create_data = create_response.json()
task_id = create_data["task"]["id"]
print("Task created:", task_id)
interval = 1
max_interval = 10
max_attempts = 60
for attempt in range(1, max_attempts + 1):
time.sleep(interval)
result_response = requests.post(
API_BASE + "/request/result",
headers=api_headers,
json={"taskId": task_id}
)
data = result_response.json()["data"]
status = data["task"]["status"]
if status == "completed":
print(f"Completed in {data['processingTime']}ms")
return {
"statusCode": data["task"]["result"]["statusCode"],
"headers": data["task"]["result"]["headers"],
"body": data["task"]["result"]["body"],
"cookies": data["task"]["result"]["cookies"],
"profile": data["task"]["result"]["profile"],
"processingTime": data["processingTime"]
}
if status == "failed":
raise Exception("Request failed: " + data["error"]["message"])
if status == "timeout":
raise Exception("Request timed out: " + data["error"]["message"])
interval = min(interval * 1.5, max_interval)
raise Exception("Polling limit reached")
result = bbre_request(
"https://example.com/products",
mode="passive",
sensibility="medium",
timeout=60
)
print("HTTP Status:", result["statusCode"])
print("Content-Type:", result["headers"].get("content-type"))
print("Body Length:", len(result["body"]))
print("Total Time:", result["processingTime"], "ms")
cURL Complete Workflow
API_KEY="YOUR_API_KEY"
CREATE_RESPONSE=$(curl -s -X POST https://bbre-solver-api.mydisct.com/request/create \
-H "Content-Type: application/json" \
-H "x-api-key: $API_KEY" \
-d '{
"url": "https://example.com/products",
"mode": "passive",
"sensibility": "medium",
"timeout": 60
}')
TASK_ID=$(echo $CREATE_RESPONSE | python3 -c "import sys,json; print(json.load(sys.stdin)['task']['id'])")
echo "Task created: $TASK_ID"
MAX_ATTEMPTS=60
INTERVAL=2
for i in $(seq 1 $MAX_ATTEMPTS); do
RESULT=$(curl -s -X POST https://bbre-solver-api.mydisct.com/request/result \
-H "Content-Type: application/json" \
-H "x-api-key: $API_KEY" \
-d "{\"taskId\": \"$TASK_ID\"}")
STATUS=$(echo $RESULT | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['task']['status'])")
if [ "$STATUS" = "completed" ]; then
echo "Task completed!"
echo $RESULT | python3 -m json.tool
exit 0
fi
if [ "$STATUS" = "failed" ] || [ "$STATUS" = "timeout" ]; then
echo "Task ended with status: $STATUS"
echo $RESULT | python3 -m json.tool
exit 1
fi
echo "Attempt $i - still processing..."
sleep $INTERVAL
done
echo "Polling limit reached"
Using the Node.js SDK
If you are working with Node.js, the mydisctsolver-bbre SDK handles the entire
create-and-poll workflow automatically. When you call client.request() or any
of the HTTP shorthand methods like client.get(), the SDK internally creates the
task, polls for the result with configurable intervals, and returns the final result directly.
You never need to call the result endpoint manually when using the SDK. The SDK also handles
error states, throwing appropriate exceptions for failed and timed-out tasks.
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY",
mode: "passive",
sensibility: "medium",
pollingInterval: 2000
});
async function fetchPage() {
const result = await client.get("https://example.com/products");
console.log("Status Code:", result.statusCode);
console.log("Body Length:", result.body.length);
console.log("Cookies:", JSON.stringify(result.cookies));
if (result.profile) {
console.log("User Agent:", result.profile.userAgent);
console.log("Platform:", result.profile.platform);
}
return result;
}
fetchPage();
const BBREClient = require("mydisctsolver-bbre");
const client = new BBREClient({
apiKey: "YOUR_API_KEY"
});
async function fetchWithErrorHandling() {
try {
const result = await client.get("https://protected-site.example.com/data", {
mode: "adaptive",
sensibility: "high",
timeout: 120
});
console.log("Status Code:", result.statusCode);
console.log("Body:", result.body.substring(0, 200));
return result;
} catch (error) {
console.log("Request failed:", error.message);
return null;
}
}
fetchWithErrorHandling();
The SDK's pollingInterval option controls how frequently the SDK checks for
results. The default is 2000 milliseconds (2 seconds). For high-throughput applications
processing many concurrent requests, you may want to increase this value to reduce API
call volume. For latency-sensitive applications, you can decrease it to detect completed
tasks faster. See the Node.js SDK Overview
for more configuration options.
Error Responses
When a request to the result endpoint itself fails (as opposed to the underlying task failing), the API returns an error response with an appropriate HTTP status code, an error code string for programmatic handling, and a human-readable message. These errors relate to the API call itself, not to the task processing. Task-level failures are reported through the task status field as described in the Response Statuses section above.
Missing Task ID Error
{
"success": false,
"service": "MyDisct Solver BBRE",
"error": "TASK_ID_REQUIRED",
"message": "Task ID is required"
}
Task Not Found Error
{
"success": false,
"service": "MyDisct Solver BBRE",
"error": "TASK_NOT_FOUND",
"message": "Task not found"
}
Complete Error Code Reference
| HTTP Status | Error Code | Cause | Solution |
|---|---|---|---|
400 |
TASK_ID_REQUIRED |
The taskId parameter is missing from the request body. |
Include the taskId field in the JSON request body. The task ID is the value returned by POST /request/create. |
401 |
API_KEY_REQUIRED |
No API key was provided in the request headers. | Include your API key in the x-api-key or apikey HTTP header. |
403 |
INVALID_API_KEY |
The provided API key does not match any active account. | Verify that you are using the correct API key from your MyDisct Solver dashboard. Check for extra whitespace or truncated characters. |
403 |
ACCOUNT_SUSPENDED |
Your account has been suspended due to a policy violation. | Contact MyDisct Solver support to resolve the suspension. |
403 |
ACCOUNT_INACTIVE |
Your account is not currently active. | Log in to the MyDisct Solver dashboard and activate your account. |
404 |
TASK_NOT_FOUND |
No task exists with the provided task ID, or the task belongs to a different account. | Verify that the task ID is correct and was returned by a previous POST /request/create call made with the same API key. Task IDs are case-sensitive. Also check that the task has not expired from the system. |
500 |
SERVICE_ERROR |
An internal error occurred while retrieving the task status. | Retry the request after a short delay. If the error persists, contact support with the task ID. |
Error Handling Example
const axios = require("axios");
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";
async function fetchResultSafely(taskId) {
try {
const response = await axios.post(
API_BASE + "/request/result",
{ taskId: taskId },
{
headers: {
"Content-Type": "application/json",
"x-api-key": API_KEY
}
}
);
return response.data;
} catch (error) {
if (error.response) {
const status = error.response.status;
const data = error.response.data;
if (status === 400) {
console.log("Bad request:", data.error, data.message);
} else if (status === 401) {
console.log("Authentication failed. Check your API key.");
} else if (status === 403) {
console.log("Access denied:", data.error);
} else if (status === 404) {
console.log("Task not found. Verify the task ID:", taskId);
} else if (status >= 500) {
console.log("Server error. Will retry on next poll cycle.");
}
} else {
console.log("Network error:", error.message);
}
return null;
}
}
fetchResultSafely("task_abc123def456");
Result Caching Behavior
Once a task reaches the completed state, the result is cached internally by the
BBRE system. This means that subsequent calls to POST /request/result with the
same task ID will return the cached result immediately without any additional processing or
delay. This caching behavior is useful in several scenarios: if your application crashes
after the task completes but before it processes the result, you can safely call the result
endpoint again to retrieve the data. If multiple parts of your application need the same
result, they can all call the endpoint independently without concern about duplicate
processing or additional costs.
The caching applies only to completed tasks. Tasks in the processing state
always trigger a fresh status check against the BBRE engine. Tasks in the failed
or timeout state also return their cached error information immediately. There
is no additional charge for retrieving a cached result. The result remains available for
retrieval as long as the task record exists in the system.
Automatic Balance Refund
When you create a task through POST /request/create, the request cost is
deducted from your account balance immediately. If the task subsequently fails or times out
during processing, the deducted amount is automatically refunded to your account. You do not
need to take any action to receive the refund; it is handled as part of the BBRE error
processing pipeline. The refund happens at the moment the task transitions to the
failed or timeout state, which means your balance is restored
before you even receive the error response from the result endpoint.
This automatic refund mechanism ensures that you are only charged for successfully completed requests. If you are monitoring your balance programmatically, be aware that the balance may temporarily decrease when a task is created and then increase again if the task fails. You can use the Account Balance endpoint to check your current balance at any time, and the Usage History endpoint to see detailed transaction records including refunds.
Best Practices
Instead of polling at a fixed interval, implement exponential backoff that starts with a short interval (1 second) and gradually increases (2s, 4s, 8s) up to a maximum cap (10 seconds). This approach detects fast-completing tasks quickly while reducing unnecessary API calls for longer-running tasks. Exponential backoff is especially important when processing many concurrent requests, as it significantly reduces the total number of polling calls your application makes. For passive mode requests that typically complete in 2-5 seconds, the first few polls at short intervals will catch most results. For adaptive mode requests that may take 10-30 seconds, the backoff prevents dozens of unnecessary polling calls.
Never create an infinite polling loop. Always define a maximum number of attempts or a maximum total polling duration. A reasonable limit is 2-3 times the task timeout value. For example, if you created the task with a 30-second timeout, set your polling limit to 60-90 seconds total. If the task has not reached a terminal state within this window, treat it as a failure in your application logic. This prevents your application from hanging indefinitely if something unexpected happens. The BBRE engine will eventually transition the task to a terminal state, but your application should not depend on this for its own stability.
Your polling logic should explicitly handle all four possible task statuses:
processing, completed, failed, and
timeout. Do not assume that a non-completed status means the task is
still processing. The failed and timeout statuses are
terminal states that require different handling than processing. For
failed and timeout, you should log the error, potentially
retry with different parameters, and move on. For processing, you should
continue polling. Treating failed or timeout as
processing would cause your application to poll indefinitely for a task
that will never complete.
Network errors (connection timeouts, DNS failures, HTTP 500 errors) can occur during polling without meaning the task itself has failed. Your polling loop should catch these errors and continue polling rather than treating them as task failures. The task continues processing on the BBRE engine regardless of whether your polling call succeeds. Implement a separate counter for consecutive network errors and only abort if you experience multiple failures in a row (for example, 5 consecutive network errors). This makes your integration resilient to temporary network issues.
If you are working with Node.js, the mydisctsolver-bbre SDK eliminates the
need to implement polling logic entirely. The SDK's client.request() method
handles task creation, polling, status checking, and error handling internally. It uses
a configurable polling interval and throws appropriate exceptions for failed and timed-out
tasks. Using the SDK reduces your code complexity and eliminates an entire category of
potential bugs related to polling implementation. See the
Node.js SDK Overview for installation and
configuration details.
Common Issues
Issue 1: TASK_NOT_FOUND Error When Polling
You receive a 404 TASK_NOT_FOUND error when calling the result endpoint
with a task ID that was returned by the create endpoint.
Solution: This error has several possible causes. First, verify that you are using the exact task ID string returned by the create endpoint without any modifications, extra whitespace, or truncation. Task IDs are case-sensitive. Second, confirm that you are using the same API key for both the create and result calls. Each task is associated with the account that created it, and you cannot retrieve results for tasks created by other accounts. Third, check that you are not accidentally using a task ID from a different environment (for example, using a production task ID against a staging API). If you are storing task IDs in a database or queue, ensure the storage mechanism preserves the full string without modification.
Issue 2: Task Stays in Processing State Indefinitely
You are polling for a task result, but the status remains "processing"
for much longer than expected without transitioning to a terminal state.
Solution: The most common cause is that the task timeout value set during creation is longer than your expected processing time. The BBRE engine will continue processing until the timeout is reached. For passive mode, tasks typically complete within 2-5 seconds. For adaptive mode, 10-30 seconds is normal depending on page complexity. If the task is taking significantly longer than these ranges, the target server may be slow to respond, or the page may have complex JavaScript that takes time to execute. Ensure your polling loop has a maximum attempt limit so it does not run forever. As a rule of thumb, set your polling timeout to 2-3 times the task timeout value. If the task still has not completed by then, treat it as a failure in your application and create a new task if needed.
Issue 3: Completed Task Returns Unexpected Body Content
The task completes successfully but the response body contains a bot detection page, a CAPTCHA challenge, or content that does not match what you see in a regular browser.
Solution: This indicates that the target site's bot detection identified
the request as automated. The task itself completed successfully because the HTTP request
was made and a response was received, but the response content is a challenge page rather
than the expected content. To resolve this, try escalating your configuration: switch from
passive to adaptive mode, increase the sensibility from low to medium or high, add a custom
fingerprint with geographic settings matching the target audience, or use a proxy with an
IP address in the expected region. You can check the result.statusCode field
to detect challenge pages (many bot detection systems return 403 or redirect to a challenge
URL). See the Hybrid Workflow Guide for
strategies on combining passive and adaptive modes effectively.