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

# GET /jobs/{jobId}

> Poll the status of a review scraping job

# GET /api/v1/jobs/{jobId}

Check the status of a review scraping job.

## Request

**Headers**:

| Header        | Value                 | Required |
| ------------- | --------------------- | -------- |
| Authorization | `Bearer YOUR_API_KEY` | Yes      |

**Path Parameters**:

| Parameter | Type   | Description                         |
| --------- | ------ | ----------------------------------- |
| jobId     | number | Job ID from `POST /reviews/refresh` |

## Response (200 OK)

```json theme={null}
{
  "jobId": 2877,
  "asin": "B08N5WRWNW",
  "productTitle": "Example Product Title",
  "status": "completed",
  "createdAt": "2026-02-02T10:30:00.000Z",
  "updatedAt": "2026-02-02T10:31:05.000Z"
}
```

| Field        | Type   | Description                                                      |
| ------------ | ------ | ---------------------------------------------------------------- |
| jobId        | number | Job identifier                                                   |
| asin         | string | ASIN being processed                                             |
| productTitle | string | Product title (if available)                                     |
| status       | string | `queued` \| `processing` \| `completed` \| `failed` \| `unknown` |
| createdAt    | string | ISO 8601 timestamp of job creation                               |
| updatedAt    | string | ISO 8601 timestamp of last status change                         |

## Job Statuses

| Status     | Description                                    |
| ---------- | ---------------------------------------------- |
| queued     | Job is waiting to be processed                 |
| processing | Job is actively scraping reviews               |
| completed  | Job finished successfully (reviews now cached) |
| failed     | Job failed                                     |
| unknown    | Unexpected internal status (fallback value)    |

## Errors

| Status | Error                   | Cause                                         |
| ------ | ----------------------- | --------------------------------------------- |
| 400    | `Invalid job ID`        | jobId is not a valid number                   |
| 401    | `Invalid API key`       | Key doesn't exist or was revoked              |
| 404    | `Job not found`         | Job doesn't exist or belongs to another store |
| 500    | `Internal server error` | Temporary backend/service issue               |

## Examples

**cURL**:

```bash theme={null}
curl https://app.descripio.com/api/v1/jobs/2877 \
  -H "Authorization: Bearer dscr_abc123..."
```

**Python (with polling)**:

```python theme={null}
import requests
import time

API_KEY = "dscr_abc123..."
job_id = 2877
max_attempts = 24  # 2 minutes max

for attempt in range(max_attempts):
    response = requests.get(
        f"https://app.descripio.com/api/v1/jobs/{job_id}",
        headers={"Authorization": f"Bearer {API_KEY}"}
    )
    
    job = response.json()
    status = job["status"]
    
    if status == "completed":
        print(f"✅ Job complete! Fetching reviews...")
        break
    elif status == "failed":
        print(f"❌ Job failed")
        break
    else:
        print(f"⏳ Status: {status}, waiting...")
        time.sleep(5)
else:
    print("⚠️ Timeout: Job took longer than expected")
```

**JavaScript (with polling)**:

```javascript theme={null}
async function pollJob(jobId, apiKey) {
  const maxAttempts = 24;
  
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const response = await fetch(
      `https://app.descripio.com/api/v1/jobs/${jobId}`,
      { headers: { 'Authorization': `Bearer ${apiKey}` } }
    );
    
    const job = await response.json();
    
    if (job.status === 'completed') {
      console.log('Job complete!');
      return job;
    } else if (job.status === 'failed') {
      throw new Error('Job failed');
    }
    
    console.log(`Status: ${job.status}, waiting...`);
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
  
  throw new Error('Timeout');
}
```

## Best Practices

* **Poll interval**: Start with 5 seconds, use exponential backoff if needed
* **Max timeout**: Set a reasonable limit (2-3 minutes) to avoid infinite loops
* **Error handling**: Always check for `failed` status and handle gracefully


## OpenAPI

````yaml GET /api/v1/jobs/{jobId}
openapi: 3.1.0
info:
  title: Descripio Reviews API
  version: 1.1.0
  description: |
    OpenAPI contract aligned to implemented Next.js endpoints under `/api/v1`.
    Authentication uses `Authorization: Bearer <API_KEY>`.
servers:
  - url: https://app.descripio.com
    description: Production
security:
  - BearerApiKeyAuth: []
tags:
  - name: Reviews
  - name: Jobs
paths:
  /api/v1/jobs/{jobId}:
    get:
      tags:
        - Jobs
      summary: Get refresh job status
      operationId: getJob
      parameters:
        - name: jobId
          in: path
          required: true
          schema:
            type: integer
          example: 2877
      responses:
        '200':
          description: Job found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JobStatusResponse'
        '400':
          description: Invalid job ID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error: Invalid job ID
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error: Job not found
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    JobStatusResponse:
      type: object
      required:
        - jobId
        - asin
        - status
        - createdAt
        - updatedAt
      properties:
        jobId:
          type: integer
          example: 2877
        asin:
          type: string
          example: B08N5WRWNW
        productTitle:
          type: string
          nullable: true
          example: Example Product Title
        status:
          type: string
          enum:
            - queued
            - processing
            - completed
            - failed
            - unknown
          description: >-
            pending→queued, in_progress→processing, success→completed,
            failed→failed.
          example: processing
        createdAt:
          type: string
          format: date-time
          example: '2026-02-02T10:30:00.000Z'
        updatedAt:
          type: string
          format: date-time
          example: '2026-02-02T10:31:05.000Z'
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          example: Invalid API key
        message:
          type: string
          nullable: true
          example: Unable to process request. Please retry in a few moments.
        retryable:
          type: boolean
          nullable: true
          example: true
  securitySchemes:
    BearerApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: API key passed in Authorization header as Bearer token.

````