> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veritus.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Callbacks

> Set up webhooks to receive job completion notifications

When creating a job, you can optionally provide a `callbackUrl` to receive a notification when the job completes. This allows you to avoid polling the [job status endpoint](/learn/search-api/jobs-status).

## Setting Up Callbacks

To enable callbacks, include a `callbackUrl` field in your job creation request body:

```json theme={null}
{
  "callbackUrl": "https://your-domain.com/webhook",
  "keywords": ["machine learning", "neural networks", "deep learning"]
}
```

## Callback URL Requirements

* **Protocol**: Must be HTTPS (HTTP and localhost URLs are not allowed)
* **Format**: Must be a valid URL
* **Example**: `https://api.example.com/webhooks/veritus`

## Callback Payload

When a job completes successfully, a POST request will be sent to your callback URL with the following JSON payload:

```json theme={null}
{
  "data": [
    {
      "abstract": "Paper abstract text or null",
      "authors": "Author1, Author2, Author3",
      "doi": "10.1234/example.doi",
      "downloadable": true,
      "engine": "ss-veritus",
      "fieldsOfStudy": ["Computer Science", "Mathematics"],
      "id": "paper_id_string",
      "impactFactor": {
        "citationCount": 150,
        "influentialCitationCount": 25,
        "referenceCount": 50
      },
      "isOpenAccess": true,
      "isPrePrint": false,
      "journalName": "Journal Name",
      "link": "https://example.com/paper",
      "pdfLink": "https://example.com/paper.pdf",
      "publicationType": "journal",
      "publishedAt": "2023-01-15",
      "score": 0.95,
      "semanticLink": "https://semanticscholar.org/paper/123",
      "title": "Paper Title",
      "titleLink": "https://example.com/paper",
      "tldr": "TLDR summary of the paper",
      "v_country": "United States",
      "v_journal_name": "Journal Name",
      "v_publisher": "Publisher Name",
      "v_quartile_ranking": "Q1",
      "year": 2023
    }
  ],
  "event": {
    "api_version": "v1",
    "createdAt": "2024-01-15T10:30:00.000Z",
    "id": "result_id_string"
  },
  "job": {
    "id": "507f1f77bcf86cd799439011"
  }
}
```

## Callback Payload Fields

* `data`: Array of paper results (same structure as the `results` field in the job status response)
* `event`: Event metadata:
  * `api_version`: API version used (currently "v1")
  * `createdAt`: ISO 8601 timestamp when the result was created
  * `id`: Unique result identifier
* `job`: Job information:
  * `id`: The job ID that was returned when creating the job

## Callback Behavior

* **When Sent**: Callbacks are only sent when a job completes successfully (`status: "success"`)
* **Retries**: The system automatically retries failed callback requests
* **No Callback on Error**: If a job fails (`status: "error"`), no callback will be sent
* **HTTP Method**: Callbacks are sent via POST request
* **Content-Type**: The request body is JSON with `Content-Type: application/json`

## Handling Callbacks

Your callback endpoint should:

1. **Return 200 OK**: Respond with a 200 status code to acknowledge receipt
2. **Process Quickly**: Keep processing time under 10 seconds to avoid timeouts
3. **Handle Duplicates**: Be idempotent - the same callback may be sent multiple times due to retries
4. **Validate Job ID**: Verify the `job.id` matches a job you created
5. **Store Results**: Save the results data for later retrieval

## Example Callback Handler

Here's an example of a simple callback handler:

```javascript theme={null}
// Express.js example
app.post("/webhook", async (req, res) => {
  try {
    const { data, event, job } = req.body;

    // Validate job ID
    const jobRecord = await findJobById(job.id);
    if (!jobRecord) {
      return res.status(404).json({ error: "Job not found" });
    }

    // Store results
    await saveJobResults(job.id, data);

    // Update job status in your system
    await updateJobStatus(job.id, "completed");

    // Return 200 to acknowledge receipt
    res.status(200).json({ received: true });
  } catch (error) {
    console.error("Error processing callback:", error);
    // Still return 200 to prevent retries for application errors
    res.status(200).json({ received: true, error: "Processing failed" });
  }
});
```

## Testing Callbacks

To test callbacks locally, you can use services like:

* [ngrok](https://ngrok.com/) - Create HTTPS tunnels to localhost
* [webhook.site](https://webhook.site/) - Temporary webhook URLs for testing
* [RequestBin](https://requestbin.com/) - HTTP request inspector

**Note**: Localhost URLs are not accepted. You must use a publicly accessible HTTPS endpoint.
