Chat with us, powered by LiveChat
← Return to MyDisct Solver

Usage History

The POST /account/history endpoint returns a paginated list of your BBRE (Browser-Backed Request Engine) task history, including every request and session operation that has been processed through your account. This endpoint is essential for understanding how your BBRE credit is being consumed, identifying failed requests that need attention, tracking processing times across different configurations, and building internal reporting dashboards. Every task recorded in your history includes its unique identifier, the type of operation (standard request or session request), the operating mode used (passive or adaptive), the final status (completed, failed, processing, or timeout), the target URL, the HTTP method, the exact price charged for that operation, the processing time in milliseconds, and timestamps for both creation and completion. The endpoint supports powerful filtering capabilities that let you narrow results by task status, date range, or both. Combined with pagination through the limit and offset parameters, you can efficiently retrieve and analyze any subset of your usage data regardless of how many total tasks your account has processed. Results are always returned in reverse chronological order (newest first), which means the most recent operations appear at the top of the list. This ordering is fixed and cannot be changed through request parameters. Whether you are debugging a specific failed request, calculating your daily spend, analyzing success rates across different target domains, or exporting your complete usage data for external analysis, this endpoint provides the raw data you need. This page covers the endpoint definition, authentication requirements, all available request parameters, the complete response format, filtering examples, pagination patterns, working code examples in JavaScript, Python, and cURL, data analysis patterns, error handling, and best practices for working with usage history data in production systems.

Usage History Data

Your usage history contains every task that has been submitted through your API key, including tasks that are still processing, tasks that completed successfully, tasks that failed, and tasks that timed out. Each history entry records the exact cost charged for that operation, so you can use this data to reconcile your balance changes and understand your spending patterns. The history is ordered by creation time (newest first) and supports filtering by status and date range. For large accounts with thousands of tasks, use the pagination parameters to retrieve data in manageable chunks rather than requesting everything at once. The default page size is 50 tasks, which provides a good balance between response size and the number of API calls needed to iterate through your data.

Endpoint

The usage history endpoint accepts only POST requests. Unlike the balance endpoint which supports both GET and POST, the history endpoint requires POST because it accepts an optional JSON request body containing filter and pagination parameters. Even if you do not need any filters, you must send a POST request. You can send an empty body or an empty JSON object, and the endpoint will return the first 50 tasks ordered by creation date (newest first) with no filters applied.

POST https://bbre-solver-api.mydisct.com/account/history

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, including history queries. 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 or belongs to a suspended or inactive account, the API returns a 403 error with the appropriate error code (INVALID_API_KEY, ACCOUNT_SUSPENDED, or ACCOUNT_INACTIVE).

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 optional Set to application/json when sending a JSON request body with filter or pagination parameters.

When sending filter or pagination parameters in the request body, include the Content-Type: application/json header so the server can parse your JSON payload correctly. If you are sending an empty request with no filters, the Content-Type header is not strictly required, but including it is a good practice for consistency across all your BBRE API calls.

Request Parameters

All parameters for the usage history endpoint are optional. If you send an empty request body or omit all parameters, the endpoint returns the most recent 50 tasks with no filters applied. The parameters allow you to control pagination (how many results to return and where to start) and filtering (which tasks to include based on status or date range). All parameters are sent in the JSON request body.

Parameter Type Required Description
limit number optional Maximum number of tasks to return per page. Defaults to 50 if not specified. Use this to control the response size. Smaller values mean faster responses and less memory usage on the client side, while larger values reduce the number of API calls needed to iterate through your complete history.
offset number optional Number of tasks to skip before starting to return results. Defaults to 0 (start from the beginning). Use this in combination with limit to implement pagination. For example, to get the second page of 50 results, set offset to 50.
status string optional Filter tasks by their current status. Accepted values are "completed", "failed", "processing", and "timeout". When specified, only tasks matching the given status are returned. The pagination counts (total, limit, offset) reflect the filtered result set, not the total number of tasks in your account.
startDate string optional ISO 8601 date string. When specified, only tasks created on or after this date are returned. Use this to limit results to a specific time window. Example: "2024-06-01T00:00:00.000Z" returns tasks from June 1, 2024 onwards.
endDate string optional ISO 8601 date string. When specified, only tasks created on or before this date are returned. Use this together with startDate to define a specific date range. Example: "2024-06-30T23:59:59.999Z" returns tasks up to the end of June 30, 2024.

You can combine all filter parameters in a single request. For example, you can filter by status and date range simultaneously to find all failed tasks within a specific week. The filters are applied with AND logic, meaning a task must match all specified criteria to be included in the results. The pagination parameters (limit and offset) are applied after filtering, so the total count in the response reflects the number of tasks that match your filters, not the total number of tasks in your account.

Response Format

The history endpoint returns a JSON response containing an array of task objects and pagination metadata. On success, the response includes the standard BBRE success fields, a tasks array with detailed information about each task, and a pagination object that tells you the total number of matching tasks, the current limit, and the current offset. This pagination metadata is essential for implementing page navigation in your application.

Success Response (200)

A successful history query returns the following structure. The tasks array contains task objects ordered by creation date (newest first). Each task object includes all the information you need to understand what happened with that specific operation: what was requested, how it was processed, how long it took, and how much it cost. The pagination object provides the metadata needed to navigate through large result sets.

JSON
{
  "success": true,
  "service": "MyDisct Solver BBRE",
  "tasks": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "type": "BBRE_REQUEST",
      "mode": "passive",
      "status": "completed",
      "url": "https://example.com/api/data",
      "method": "GET",
      "priceCharged": 0.005,
      "processingTime": 1234,
      "createdAt": "2024-06-15T10:30:00.000Z",
      "completedAt": "2024-06-15T10:30:01.234Z"
    },
    {
      "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "type": "BBRE_SESSION_REQUEST",
      "mode": "adaptive",
      "status": "completed",
      "url": "https://example.com/login",
      "method": "POST",
      "priceCharged": 0.012,
      "processingTime": 3456,
      "createdAt": "2024-06-15T10:28:00.000Z",
      "completedAt": "2024-06-15T10:28:03.456Z"
    }
  ],
  "pagination": {
    "total": 15420,
    "limit": 50,
    "offset": 0
  }
}

Tasks Array Fields

Each object in the tasks array represents a single BBRE operation that was processed through your account. The fields provide complete visibility into what was requested, how it was handled, and the outcome.

Field Type Description
id string Unique identifier (UUID) for this task. Use this ID to reference a specific task when debugging or when querying the result endpoint for completed tasks.
type string The type of BBRE operation. "BBRE_REQUEST" indicates a standard request created through the request API. "BBRE_SESSION_REQUEST" indicates a request made within an active session.
mode string The operating mode used for this task. Either "passive" (simple HTTP request mode) or "adaptive" (full browser automation mode). Adaptive mode tasks typically have higher processing times and costs.
status string The current status of the task. Possible values: "processing" (task is still being executed), "completed" (task finished successfully), "failed" (task encountered an error), "timeout" (task exceeded the maximum processing time).
url string The target URL that was requested. This is the URL you provided when creating the task or sending the session request.
method string The HTTP method used for the request (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS).
priceCharged number The amount charged for this task in USD. This is the exact amount that was deducted from your account balance when the task completed. Failed tasks and timed-out tasks may still have a charge depending on how far processing progressed before the failure.
processingTime number The total processing time for this task in milliseconds. This measures the time from when the BBRE engine started processing the task to when it completed, failed, or timed out. Does not include queue wait time.
createdAt string ISO 8601 timestamp indicating when the task was created (submitted to the API). Tasks are ordered by this field in descending order (newest first).
completedAt string ISO 8601 timestamp indicating when the task finished processing. This field is present for completed, failed, and timed-out tasks. For tasks still in "processing" status, this field may be null.

Pagination Object

The pagination object provides metadata about the result set, which you need to implement page navigation and to know when you have retrieved all matching tasks.

Field Type Description
total number The total number of tasks matching your filter criteria. If no filters are applied, this is the total number of tasks in your account. Use this value to calculate the total number of pages and to determine when you have retrieved all results.
limit number The maximum number of tasks returned in this response. This reflects the limit parameter you sent in the request, or the default value of 50 if you did not specify one.
offset number The number of tasks skipped before the current result set. This reflects the offset parameter you sent in the request, or 0 if you did not specify one. To get the next page, add the current limit to the current offset.

Error Response Examples

When the history query fails, the API returns an error response with the appropriate HTTP status code, error code, and a descriptive message. The most common error scenarios for this endpoint are authentication-related, since the filter parameters are all optional and the endpoint handles invalid values gracefully.

401 - API Key Required

JSON
{
  "success": false,
  "service": "MyDisct Solver BBRE",
  "error": {
    "code": "API_KEY_REQUIRED",
    "message": "API key is required. Please provide your API key in the x-api-key or apikey header."
  }
}

403 - Invalid API Key

JSON
{
  "success": false,
  "service": "MyDisct Solver BBRE",
  "error": {
    "code": "INVALID_API_KEY",
    "message": "The provided API key is invalid or does not exist."
  }
}

403 - Account Suspended

JSON
{
  "success": false,
  "service": "MyDisct Solver BBRE",
  "error": {
    "code": "ACCOUNT_SUSPENDED",
    "message": "Your account has been suspended. Please contact support for more information."
  }
}

500 - Service Error

JSON
{
  "success": false,
  "service": "MyDisct Solver BBRE",
  "error": {
    "code": "SERVICE_ERROR",
    "message": "An internal server error occurred. Please try again later."
  }
}

Filtering Examples

The usage history endpoint supports three types of filters that can be used individually or combined: status filtering, date range filtering, and combined filtering. When multiple filters are specified, they are applied with AND logic, meaning a task must satisfy all filter conditions to appear in the results. The following examples demonstrate each filtering approach with complete request and response structures.

Filter by Status

Filtering by status is the most common use case. You might want to find all failed tasks to investigate errors, all completed tasks to calculate success metrics, or all timed-out tasks to identify URLs that consistently exceed the processing time limit. The status parameter accepts a single status value as a string.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getFailedTasks() {
  const response = await fetch(API_BASE + "/account/history", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY
    },
    body: JSON.stringify({
      status: "failed",
      limit: 20
    })
  });

  const data = await response.json();

  if (data.success) {
    console.log("Total failed tasks: " + data.pagination.total);
    for (const task of data.tasks) {
      console.log(task.id + " | " + task.url + " | " + task.mode);
    }
  }

  return data;
}

getFailedTasks();

The four valid status values are "completed" for tasks that finished successfully, "failed" for tasks that encountered an error during processing, "processing" for tasks that are currently being executed by the BBRE engine, and "timeout" for tasks that exceeded the maximum allowed processing time. Filtering by "processing" status is useful for monitoring active workloads and detecting tasks that may be stuck.

Filter by Date Range

Date range filtering lets you retrieve tasks from a specific time period. This is essential for generating daily, weekly, or monthly usage reports. Both startDate and endDate accept ISO 8601 formatted date strings. You can use either or both parameters: specifying only startDate returns all tasks from that date forward, specifying only endDate returns all tasks up to that date, and specifying both creates a bounded time window.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getTasksForDateRange(startDate, endDate) {
  const response = await fetch(API_BASE + "/account/history", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY
    },
    body: JSON.stringify({
      startDate: startDate,
      endDate: endDate,
      limit: 100
    })
  });

  const data = await response.json();

  if (data.success) {
    console.log("Tasks in range: " + data.pagination.total);
    console.log("Returned: " + data.tasks.length);
  }

  return data;
}

getTasksForDateRange("2024-06-01T00:00:00.000Z", "2024-06-30T23:59:59.999Z");

Combined Filters

Combining status and date range filters gives you precise control over which tasks are returned. For example, you can find all failed tasks from the past week, all completed tasks from a specific day, or all timed-out tasks from the last month. This is particularly useful for incident investigation when you need to understand what went wrong during a specific time period.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getFailedTasksThisWeek() {
  const now = new Date();
  const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);

  const response = await fetch(API_BASE + "/account/history", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY
    },
    body: JSON.stringify({
      status: "failed",
      startDate: weekAgo.toISOString(),
      endDate: now.toISOString(),
      limit: 100
    })
  });

  const data = await response.json();

  if (data.success) {
    console.log("Failed tasks this week: " + data.pagination.total);

    const totalCost = data.tasks.reduce((sum, task) => sum + task.priceCharged, 0);
    console.log("Total cost of failed tasks: $" + totalCost.toFixed(4));
  }

  return data;
}

getFailedTasksThisWeek();

Pagination Patterns

When your account has more tasks than can fit in a single response, you need to paginate through the results using the limit and offset parameters. The pagination.total field in the response tells you the total number of matching tasks, and you can calculate the number of pages by dividing the total by your limit value. The following patterns demonstrate how to iterate through all results efficiently.

Iterating Through All Results

The most common pagination pattern is to start at offset 0 and increment the offset by the limit value after each request until you have retrieved all tasks. The loop terminates when the current offset plus the number of returned tasks equals or exceeds the total count. This approach works well for data export, reporting, and analysis workflows where you need to process every task in your history.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getAllTasks(filters) {
  const allTasks = [];
  const pageSize = 100;
  let offset = 0;
  let total = null;

  while (true) {
    const response = await fetch(API_BASE + "/account/history", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": API_KEY
      },
      body: JSON.stringify({
        ...filters,
        limit: pageSize,
        offset: offset
      })
    });

    const data = await response.json();

    if (!data.success) {
      throw new Error("API error: " + data.error.code);
    }

    allTasks.push(...data.tasks);
    total = data.pagination.total;

    console.log("Fetched " + allTasks.length + " of " + total + " tasks");

    if (allTasks.length >= total) {
      break;
    }

    offset += pageSize;
  }

  return allTasks;
}

getAllTasks({ status: "completed" }).then(tasks => {
  console.log("Total completed tasks: " + tasks.length);
});

Page-Based Navigation

If you are building a user interface that displays history data with page numbers, you can calculate the offset from the page number and page size. This pattern is useful for web dashboards and admin panels where users navigate between pages of results.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getPage(pageNumber, pageSize) {
  const offset = (pageNumber - 1) * pageSize;

  const response = await fetch(API_BASE + "/account/history", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY
    },
    body: JSON.stringify({
      limit: pageSize,
      offset: offset
    })
  });

  const data = await response.json();

  if (data.success) {
    const totalPages = Math.ceil(data.pagination.total / pageSize);
    console.log("Page " + pageNumber + " of " + totalPages);
    console.log("Showing " + data.tasks.length + " tasks");
    console.log("Total tasks: " + data.pagination.total);
  }

  return data;
}

getPage(1, 25);
getPage(3, 25);

Python Pagination

A Python implementation of the full iteration pattern. This is useful when you need to export your complete usage history for analysis in tools like pandas, Excel, or a custom reporting system.

Python
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
}

def get_all_tasks(status_filter=None, page_size=100):
    all_tasks = []
    offset = 0

    while True:
        payload = {
            "limit": page_size,
            "offset": offset
        }

        if status_filter:
            payload["status"] = status_filter

        response = requests.post(
            API_BASE + "/account/history",
            headers=headers,
            json=payload
        )

        data = response.json()

        if not data["success"]:
            raise Exception(f"API error: {data['error']['code']}")

        all_tasks.extend(data["tasks"])
        total = data["pagination"]["total"]

        print(f"Fetched {len(all_tasks)} of {total} tasks")

        if len(all_tasks) >= total:
            break

        offset += page_size

    return all_tasks

tasks = get_all_tasks(status_filter="completed")
print(f"Total completed tasks: {len(tasks)}")

Code Examples

The following examples demonstrate how to query your usage history using different programming languages. All examples show complete, working code that you can copy and run directly. Remember to replace YOUR_API_KEY with your actual BBRE API key. Each example includes filter parameters to demonstrate the full request format.

JavaScript (fetch)

A complete JavaScript example using the native fetch API to retrieve usage history with status filtering and pagination. This example fetches the most recent 10 completed tasks and displays their details.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getUsageHistory() {
  const response = await fetch(API_BASE + "/account/history", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY
    },
    body: JSON.stringify({
      status: "completed",
      limit: 10,
      offset: 0
    })
  });

  const data = await response.json();

  if (data.success) {
    console.log("Total completed tasks: " + data.pagination.total);
    console.log("Showing: " + data.tasks.length);

    for (const task of data.tasks) {
      const cost = "$" + task.priceCharged.toFixed(4);
      const time = task.processingTime + "ms";
      console.log(task.id + " | " + task.url + " | " + cost + " | " + time);
    }
  } else {
    console.log("Error: " + data.error.code + " - " + data.error.message);
  }

  return data;
}

getUsageHistory();

JavaScript with Date Range Filter

This example demonstrates how to query tasks within a specific date range. It retrieves all tasks from the current month and calculates the total spending for that period.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getMonthlyHistory() {
  const now = new Date();
  const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);

  const response = await fetch(API_BASE + "/account/history", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY
    },
    body: JSON.stringify({
      startDate: firstDayOfMonth.toISOString(),
      endDate: now.toISOString(),
      limit: 100
    })
  });

  const data = await response.json();

  if (data.success) {
    const totalSpent = data.tasks.reduce((sum, t) => sum + t.priceCharged, 0);
    console.log("Tasks this month: " + data.pagination.total);
    console.log("Total spent (this page): $" + totalSpent.toFixed(4));
  }

  return data;
}

getMonthlyHistory();

Python (requests library)

A Python example using the requests library to query usage history with combined filters. This example retrieves failed tasks from the past 7 days and prints a summary of each failure.

Python
import requests
from datetime import datetime, timedelta

API_BASE = "https://bbre-solver-api.mydisct.com"
API_KEY = "YOUR_API_KEY"

headers = {
    "Content-Type": "application/json",
    "x-api-key": API_KEY
}

now = datetime.utcnow()
week_ago = now - timedelta(days=7)

payload = {
    "status": "failed",
    "startDate": week_ago.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
    "endDate": now.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
    "limit": 50,
    "offset": 0
}

response = requests.post(
    API_BASE + "/account/history",
    headers=headers,
    json=payload
)

data = response.json()

if data["success"]:
    print(f"Failed tasks (last 7 days): {data['pagination']['total']}")
    for task in data["tasks"]:
        print(f"  {task['id']} | {task['url']} | {task['mode']} | ${task['priceCharged']:.4f}")
else:
    print(f"Error: {data['error']['code']}")

Python with Full Pagination

A more complete Python example that iterates through all pages of results and collects every task matching the filter criteria. This is useful for data export and analysis workflows.

Python
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
}

def fetch_all_history(status_filter=None):
    all_tasks = []
    offset = 0
    page_size = 100

    while True:
        payload = {"limit": page_size, "offset": offset}
        if status_filter:
            payload["status"] = status_filter

        response = requests.post(
            API_BASE + "/account/history",
            headers=headers,
            json=payload
        )
        data = response.json()

        if not data["success"]:
            print(f"Error: {data['error']['code']}")
            break

        all_tasks.extend(data["tasks"])
        total = data["pagination"]["total"]

        if len(all_tasks) >= total:
            break

        offset += page_size

    return all_tasks

completed_tasks = fetch_all_history("completed")
total_cost = sum(t["priceCharged"] for t in completed_tasks)
print(f"All completed tasks: {len(completed_tasks)}")
print(f"Total cost: ${total_cost:.4f}")

cURL

Quick history queries from the command line using cURL. These examples demonstrate different filter combinations that you can use for quick checks and debugging.

Bash
curl -X POST https://bbre-solver-api.mydisct.com/account/history \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"limit": 10}'
Bash
curl -X POST https://bbre-solver-api.mydisct.com/account/history \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"status": "failed", "limit": 20}'
Bash
curl -X POST https://bbre-solver-api.mydisct.com/account/history \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"status": "completed", "startDate": "2024-06-01T00:00:00.000Z", "endDate": "2024-06-30T23:59:59.999Z", "limit": 50}'

Data Analysis Patterns

The usage history data contains rich information that you can analyze to optimize your BBRE usage, reduce costs, and improve reliability. The following patterns demonstrate common analysis workflows that extract actionable insights from your task history.

Cost Tracking and Spending Analysis

Track your spending over time by aggregating the priceCharged field across tasks. This pattern calculates daily spending totals and identifies which types of operations consume the most credit. Understanding your cost distribution helps you optimize your configuration choices and budget allocation.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function analyzeCosts(startDate, endDate) {
  const allTasks = [];
  let offset = 0;

  while (true) {
    const response = await fetch(API_BASE + "/account/history", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": API_KEY
      },
      body: JSON.stringify({
        startDate: startDate,
        endDate: endDate,
        limit: 100,
        offset: offset
      })
    });

    const data = await response.json();
    allTasks.push(...data.tasks);

    if (allTasks.length >= data.pagination.total) break;
    offset += 100;
  }

  const totalCost = allTasks.reduce((sum, t) => sum + t.priceCharged, 0);
  const avgCost = totalCost / allTasks.length;

  const costByMode = {};
  for (const task of allTasks) {
    if (!costByMode[task.mode]) costByMode[task.mode] = 0;
    costByMode[task.mode] += task.priceCharged;
  }

  const costByType = {};
  for (const task of allTasks) {
    if (!costByType[task.type]) costByType[task.type] = 0;
    costByType[task.type] += task.priceCharged;
  }

  console.log("Total tasks: " + allTasks.length);
  console.log("Total cost: $" + totalCost.toFixed(4));
  console.log("Average cost per task: $" + avgCost.toFixed(4));
  console.log("Cost by mode:", costByMode);
  console.log("Cost by type:", costByType);

  return { totalCost, avgCost, costByMode, costByType };
}

analyzeCosts("2024-06-01T00:00:00.000Z", "2024-06-30T23:59:59.999Z");

Failure Analysis

Analyzing failed tasks helps you identify problematic URLs, configurations, or patterns that consistently cause failures. This pattern groups failed tasks by URL domain and mode to reveal which combinations are unreliable, allowing you to adjust your approach for those specific targets.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function analyzeFailures() {
  const response = await fetch(API_BASE + "/account/history", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY
    },
    body: JSON.stringify({
      status: "failed",
      limit: 100
    })
  });

  const data = await response.json();

  if (!data.success) {
    console.log("Error: " + data.error.code);
    return;
  }

  const failuresByDomain = {};
  for (const task of data.tasks) {
    const url = new URL(task.url);
    const domain = url.hostname;
    if (!failuresByDomain[domain]) {
      failuresByDomain[domain] = { count: 0, modes: {} };
    }
    failuresByDomain[domain].count++;
    if (!failuresByDomain[domain].modes[task.mode]) {
      failuresByDomain[domain].modes[task.mode] = 0;
    }
    failuresByDomain[domain].modes[task.mode]++;
  }

  console.log("Total failed tasks: " + data.pagination.total);
  console.log("Failures by domain:");
  for (const [domain, info] of Object.entries(failuresByDomain)) {
    console.log("  " + domain + ": " + info.count + " failures");
    for (const [mode, count] of Object.entries(info.modes)) {
      console.log("    " + mode + ": " + count);
    }
  }
}

analyzeFailures();

Performance Monitoring with Python

Track processing times across your tasks to identify performance trends and outliers. This Python example calculates average processing times grouped by mode and identifies tasks that took significantly longer than average, which may indicate targets that need different configuration settings.

Python
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 + "/account/history",
    headers=headers,
    json={"status": "completed", "limit": 100}
)

data = response.json()

if data["success"]:
    tasks = data["tasks"]

    by_mode = {}
    for task in tasks:
        mode = task["mode"]
        if mode not in by_mode:
            by_mode[mode] = []
        by_mode[mode].append(task["processingTime"])

    for mode, times in by_mode.items():
        avg_time = sum(times) / len(times)
        max_time = max(times)
        min_time = min(times)
        print(f"Mode: {mode}")
        print(f"  Tasks: {len(times)}")
        print(f"  Avg processing time: {avg_time:.0f}ms")
        print(f"  Min: {min_time}ms | Max: {max_time}ms")

    total_cost = sum(t["priceCharged"] for t in tasks)
    success_rate = len(tasks) / data["pagination"]["total"] * 100
    print(f"Total cost (this page): ${total_cost:.4f}")
    print(f"Tasks shown: {len(tasks)} of {data['pagination']['total']}")

Daily Usage Summary

Generate a daily summary of your BBRE usage by grouping tasks by date. This pattern is useful for building internal dashboards that track daily request volumes, success rates, and spending trends over time.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getDailySummary(startDate, endDate) {
  const allTasks = [];
  let offset = 0;

  while (true) {
    const response = await fetch(API_BASE + "/account/history", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": API_KEY
      },
      body: JSON.stringify({
        startDate: startDate,
        endDate: endDate,
        limit: 100,
        offset: offset
      })
    });

    const data = await response.json();
    allTasks.push(...data.tasks);
    if (allTasks.length >= data.pagination.total) break;
    offset += 100;
  }

  const dailyStats = {};
  for (const task of allTasks) {
    const day = task.createdAt.split("T")[0];
    if (!dailyStats[day]) {
      dailyStats[day] = { total: 0, completed: 0, failed: 0, cost: 0 };
    }
    dailyStats[day].total++;
    dailyStats[day][task.status]++;
    dailyStats[day].cost += task.priceCharged;
  }

  console.log("Daily Usage Summary:");
  for (const [day, stats] of Object.entries(dailyStats).sort()) {
    const successRate = stats.total > 0
      ? ((stats.completed / stats.total) * 100).toFixed(1)
      : "0.0";
    console.log(day + " | " + stats.total + " tasks | " + successRate + "% success | $" + stats.cost.toFixed(4));
  }

  return dailyStats;
}

getDailySummary("2024-06-01T00:00:00.000Z", "2024-06-07T23:59:59.999Z");

Error Codes

The following table lists all error codes that can be returned by the usage history endpoint, along with their HTTP status codes, descriptions, and recommended solutions. Because the history endpoint has only optional parameters, the most common errors are authentication-related. Implementing proper error handling for these codes ensures your history queries and reporting workflows degrade gracefully when issues occur.

HTTP Status Error Code Description Solution
401 API_KEY_REQUIRED No API key was provided in the request headers. The history endpoint requires authentication like all other BBRE endpoints. Include your API key in the x-api-key or apikey header. Verify that your HTTP client is sending the header correctly and that it is not being stripped by a proxy or middleware.
403 INVALID_API_KEY The provided API key is not valid or does not exist in the system. Verify your API key in the MyDisct Solver dashboard. Ensure you are copying the complete key without extra spaces or line breaks. If you recently regenerated your key, update it in your application configuration.
403 ACCOUNT_SUSPENDED Your account has been suspended. Suspended accounts cannot access any BBRE API endpoints, including the history endpoint. Contact MyDisct Solver support for information about your account suspension and steps to resolve it.
403 ACCOUNT_INACTIVE Your account is inactive. Inactive accounts need to be activated before they can use the BBRE API. Activate your account through the MyDisct Solver dashboard or contact support for assistance.
500 SERVICE_ERROR An internal server error occurred while processing the history request. This can happen if the database is temporarily overloaded or if there is a connectivity issue between the API server and the database. Retry the request after a short delay (2-5 seconds). If the error persists, try reducing the limit parameter to request fewer results per page. Contact support if the error continues.

Error Handling Example

The following example demonstrates robust error handling for the history endpoint. In production systems, your history queries should handle errors gracefully and implement retry logic for transient failures. This is especially important for automated reporting workflows that run on a schedule.

JavaScript
const API_BASE = "https://bbre-solver-api.mydisct.com";
const API_KEY = "YOUR_API_KEY";

async function getHistorySafe(filters, maxRetries) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(API_BASE + "/account/history", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": API_KEY
        },
        body: JSON.stringify(filters)
      });

      const data = await response.json();

      if (data.success) {
        return { tasks: data.tasks, pagination: data.pagination, error: null };
      }

      const errorCode = data.error.code;

      if (errorCode === "API_KEY_REQUIRED" || errorCode === "INVALID_API_KEY") {
        return { tasks: [], pagination: null, error: "Authentication failed: " + errorCode };
      }

      if (errorCode === "ACCOUNT_SUSPENDED" || errorCode === "ACCOUNT_INACTIVE") {
        return { tasks: [], pagination: null, error: "Account issue: " + errorCode };
      }

      if (errorCode === "SERVICE_ERROR" && attempt < maxRetries) {
        const delay = attempt * 2000;
        console.log("Service error, retrying in " + delay + "ms...");
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }

      return { tasks: [], pagination: null, error: "API error: " + errorCode };

    } catch (networkError) {
      if (attempt < maxRetries) {
        const delay = attempt * 2000;
        console.log("Network error, retrying in " + delay + "ms...");
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      return { tasks: [], pagination: null, error: "Network error: " + networkError.message };
    }
  }
}

async function main() {
  const result = await getHistorySafe({ limit: 20 }, 3);

  if (result.error) {
    console.log("Could not fetch history: " + result.error);
    return;
  }

  console.log("Retrieved " + result.tasks.length + " tasks");
  console.log("Total matching: " + result.pagination.total);
}

main();

Best Practices

Use Pagination for Large Result Sets

Never attempt to retrieve your entire task history in a single request. Use the limit and offset parameters to paginate through results in manageable chunks. A page size of 50-100 tasks provides a good balance between response size and the number of API calls needed. For data export workflows, iterate through all pages using a loop that increments the offset by the limit value after each request. Check the pagination.total field to know when you have retrieved all matching tasks. This approach prevents memory issues on the client side and ensures consistent response times from the API.

Apply Filters to Reduce Response Size

When you only need specific types of tasks, always use the status and date range filters to narrow the result set before pagination. Filtering on the server side is significantly more efficient than retrieving all tasks and filtering on the client side. For example, if you need to analyze failed tasks from the past week, use both the status: "failed" filter and the startDate parameter rather than fetching all tasks and filtering in your application code. Server-side filtering reduces network bandwidth, response parsing time, and memory usage.

Implement Retry Logic for History Queries

History queries that scan large datasets can occasionally fail due to temporary database load or network issues. Implement retry logic with exponential backoff for your history queries, especially in automated reporting workflows that run on a schedule. Start with a 2-second delay after the first failure and double the delay for each subsequent retry, up to a maximum of 3 retries. This approach handles transient failures without overwhelming the API with rapid retry attempts. For pagination loops, implement retry logic at the individual page level so that a failure on page 5 does not require restarting from page 1.

Use Date Ranges for Incremental Data Sync

If you are syncing usage history data to an external system (database, spreadsheet, analytics platform), use the startDate parameter to fetch only new tasks since your last sync. Store the timestamp of the most recent task from each sync operation and use it as the startDate for the next sync. This incremental approach is much more efficient than re-fetching your entire history on every sync cycle. It reduces API calls, network bandwidth, and processing time, especially as your total task count grows over time.

Monitor Failed Tasks Regularly

Set up a regular check for failed and timed-out tasks using the status filter. A sudden increase in failure rates often indicates a problem with a specific target website (changed structure, added protection), a configuration issue (wrong mode or sensibility for the target), or a systemic problem that needs attention. Catching failures early allows you to adjust your approach before they accumulate and waste significant credit. Consider building an automated alert that triggers when the failure rate exceeds a threshold, such as more than 10% of tasks failing within a one-hour window.

Common Issues

Issue 1: Empty Tasks Array Despite Having History

Problem

You call the history endpoint and receive a successful response with "tasks": [] and "total": 0, even though you know your account has processed tasks. The response structure is correct but contains no data.

Solution: This usually happens when your filter parameters are too restrictive. Check the following: if you are using the status filter, verify that the value is one of the four valid statuses ("completed", "failed", "processing", "timeout") and that it is spelled correctly with the exact casing shown. If you are using date range filters, verify that the startDate is before the endDate and that the date range actually contains tasks. Also check that your dates are in ISO 8601 format. Try removing all filters first to confirm that your account has history data, then add filters back one at a time to identify which filter is causing the empty result.

Issue 2: Pagination Returns Duplicate Tasks

Problem

When paginating through results, you notice that some tasks appear on multiple pages. Your collected data contains duplicate entries that skew your analysis.

Solution: Duplicates can occur if new tasks are being created while you are paginating through the results. Because results are ordered by creation date (newest first), a new task created between your page requests shifts all subsequent tasks by one position, causing the last task on the previous page to appear as the first task on the next page. To handle this, deduplicate your collected tasks by the id field after completing the pagination loop. Alternatively, use the endDate filter set to the time when you started the pagination to freeze the result set and prevent new tasks from affecting your pagination.

Issue 3: Total Count Changes Between Pages

Problem

The pagination.total value is different on each page of results. Page 1 shows a total of 1500, but page 2 shows a total of 1503, making it difficult to determine when you have retrieved all tasks.

Solution: The total count reflects the current number of matching tasks at the time of each request. If new tasks are being created or if tasks are transitioning between statuses while you paginate, the total will change. This is expected behavior and not a bug. For accurate pagination, use the total from the first page as your target and stop when you have collected that many tasks. Alternatively, use the endDate filter to create a stable snapshot of the data. If the number of returned tasks on a page is less than the limit, you have reached the end of the result set regardless of what the total says.

Issue 4: Date Filter Not Working as Expected

Problem

You set a startDate and endDate filter, but the results include tasks outside your expected date range, or the results are empty when you know tasks exist within that range.

Solution: Ensure your date strings are in ISO 8601 format with the full timestamp including timezone information. The correct format is "2024-06-15T00:00:00.000Z" where the Z suffix indicates UTC timezone. If you omit the time portion or timezone, the server may interpret the date differently than you expect. Also note that the date filter applies to the createdAt field of each task, not the completedAt field. A task created on June 14 that completed on June 15 would be included in a filter for June 14 but not in a filter that starts on June 15. When constructing date ranges for "today", use the start of the current day in UTC as startDate and the current timestamp as endDate.