The /api/v1/jobs/{jobId} endpoint retrieves the result and status of a specific job by its ID. This is essential for checking the status of jobs created via the batch endpoint or for polling jobs that are still processing.

GET /api/v1/jobs/{jobId}

HeaderTypeRequiredDescription
x-api-keystringYesYour API key for authentication

ParameterTypeRequiredDescription
jobIdstringYesThe unique identifier of the job to retrieve

code
GET https://api.tokenthon.com/api/v1/jobs/{jobId}

bash
# Basic job retrieval
curl -X GET "https://api.tokenthon.com/api/v1/jobs/550e8400-e29b-41d4-a716-446655440000" \
  -H "x-api-key: your-api-key-here"

typescript
interface JobResultResponse {
  success: boolean;
  message: string;
  data: {
    status: "pending" | "assigned" | "completed" | "failed";
    job_id: string;
    created_at: number;
    result?: {
      response_message: string;
    };
    error?: string | Record<string, any>;
  };
}

FieldTypeDescription
statusstringCurrent job status: pending, assigned, completed, failed
job_idstringUnique identifier for the job
created_atnumberUnix timestamp when the job was created
resultobjectContains the AI response if job completed successfully
errorstring/objectError details if job failed

StatusDescriptionWhen it occurs
pendingJob is queued and waiting to be processedImmediately after creation
assignedJob has been assigned to a workerWhen processing begins
completedJob finished successfullyWhen AI completes the request
failedJob failed with an errorWhen an error occurs during processing

json
{
  "success": true,
  "message": "Job result retrieved successfully",
  "data": {
    "status": "completed",
    "job_id": "550e8400-e29b-41d4-a716-446655440000",
    "created_at": 1704067200,
    "result": {
      "response_message": "There are 8 planets in our solar system: Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and Neptune."
    },
    "error": null
  }
}

json
{
  "success": true,
  "message": "Job result retrieved successfully",
  "data": {
    "status": "pending",
    "job_id": "550e8400-e29b-41d4-a716-446655440000",
    "created_at": 1704067200,
    "result": null,
    "error": null
  }
}

json
{
  "success": true,
  "message": "Job result retrieved successfully",
  "data": {
    "status": "assigned",
    "job_id": "550e8400-e29b-41d4-a716-446655440000",
    "created_at": 1704067200,
    "result": null,
    "error": null
  }
}

json
{
  "success": true,
  "message": "Job result retrieved successfully",
  "data": {
    "status": "failed",
    "job_id": "550e8400-e29b-41d4-a716-446655440000",
    "created_at": 1704067200,
    "result": null,
    "error": "Request timeout: The job failed to complete within the allocated time."
  }
}

json
{
  "success": false,
  "message": "Job not found",
  "details": "The specified job ID does not exist or has expired"
}

json
{
  "success": false,
  "message": "Unauthorized - API key required",
  "details": "Please provide a valid API key in the x-api-key header"
}

Status CodeDescription
200Job result retrieved successfully
401Unauthorized - missing or invalid API key
404Job not found - invalid job ID
429Rate limit exceeded
500Internal server error

typescript
interface JobResult {
  status: "pending" | "assigned" | "completed" | "failed";
  job_id: string;
  created_at: number;
  result?: {
    response_message: string;
  };
  error?: string | Record<string, any>;
}
 
interface JobResultResponse {
  success: boolean;
  message: string;
  data: JobResult;
}
 
const API_CONFIG = {
  BASE_URL: "https://api.tokenthon.com",
  HEADERS: {
    "x-api-key": "your-api-key-here"
  },
};
 
async function getJobResult(jobId: string): Promise<JobResultResponse> {
  const response = await fetch(`${API_CONFIG.BASE_URL}/api/v1/jobs/${jobId}`, {
    method: "GET",
    headers: API_CONFIG.HEADERS,
  });
 
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Error ${response.status}: ${error.message || 'Unknown error'}`);
  }
 
  return await response.json();
}
 
// Poll for job completion
async function waitForJobCompletion(
  jobId: string,
  maxAttempts: number = 30,
  pollInterval: number = 2000
): Promise<JobResult> {
  let attempts = 0;
 
  while (attempts < maxAttempts) {
    try {
      const response = await getJobResult(jobId);
      const { data: job } = response;
 
      console.log(`Attempt ${attempts + 1}: Job status is ${job.status}`);
 
      if (job.status === "completed") {
        if (job.result) {
          return job;
        } else {
          throw new Error("Job completed but no result available");
        }
      }
 
      if (job.status === "failed") {
        throw new Error(`Job failed: ${job.error || 'Unknown error'}`);
      }
 
      // Job is still processing, wait and retry
      await new Promise(resolve => setTimeout(resolve, pollInterval));
      attempts++;
    } catch (error) {
      if (attempts === maxAttempts - 1) {
        throw error;
      }
      // Log error but continue polling (unless it's the last attempt)
      console.error(`Error polling job ${jobId}:`, error);
      await new Promise(resolve => setTimeout(resolve, pollInterval));
      attempts++;
    }
  }
 
  throw new Error(`Job ${jobId} did not complete within ${maxAttempts} attempts`);
}
 
// Example usage
async function processJob(jobId: string) {
  try {
    // First, get immediate status
    const initialResult = await getJobResult(jobId);
    console.log("Initial job status:", initialResult.data.status);
 
    // If job is not completed, wait for completion
    if (initialResult.data.status !== "completed") {
      console.log("Waiting for job completion...");
      const finalResult = await waitForJobCompletion(jobId);
      
      console.log("Job completed successfully!");
      console.log("Response:", finalResult.result?.response_message);
      
      return finalResult;
    } else {
      console.log("Job already completed!");
      console.log("Response:", initialResult.data.result?.response_message);
      
      return initialResult.data;
    }
  } catch (error) {
    console.error("Error processing job:", error);
    throw error;
  }
}
 
// Usage example
const jobId = "550e8400-e29b-41d4-a716-446655440000";
processJob(jobId)
  .then(result => console.log("Final result:", result))
  .catch(error => console.error("Processing failed:", error));

typescript
async function checkMultipleJobStatus(jobIds: string[]): Promise<JobResult[]> {
  const results: JobResult[] = [];
 
  for (const jobId of jobIds) {
    try {
      const response = await getJobResult(jobId);
      results.push(response.data);
    } catch (error) {
      console.error(`Failed to get status for job ${jobId}:`, error);
      // You might want to add a placeholder result or skip
    }
  }
 
  return results;
}
 
// Monitor all jobs in a batch
async function monitorBatchJobs(jobIds: string[]) {
  let allComplete = false;
  let attempts = 0;
  const maxAttempts = 60; // 2 minutes with 2-second intervals
 
  while (!allComplete && attempts < maxAttempts) {
    const results = await checkMultipleJobStatus(jobIds);
    
    const completed = results.filter(job => job.status === "completed");
    const failed = results.filter(job => job.status === "failed");
    const pending = results.filter(job => job.status === "pending" || job.status === "assigned");
 
    console.log(`Status update: ${completed.length} completed, ${failed.length} failed, ${pending.length} pending`);
 
    if (pending.length === 0) {
      allComplete = true;
      console.log("All jobs have completed!");
      
      // Process results
      completed.forEach(job => {
        console.log(`Job ${job.job_id}: ${job.result?.response_message}`);
      });
      
      failed.forEach(job => {
        console.error(`Job ${job.job_id} failed: ${job.error}`);
      });
    }
 
    if (!allComplete) {
      await new Promise(resolve => setTimeout(resolve, 2000));
      attempts++;
    }
  }
 
  if (!allComplete) {
    console.warn("Batch monitoring timed out");
  }
}
 
// Usage
const batchJobIds = [
  "550e8400-e29b-41d4-a716-446655440000",
  "550e8400-e29b-41d4-a716-446655440001",
  "550e8400-e29b-41d4-a716-446655440002"
];
 
monitorBatchJobs(batchJobIds);

bash
# Get job status
curl -X GET "https://api.tokenthon.com/api/v1/jobs/550e8400-e29b-41d4-a716-446655440000" \
  -H "x-api-key: your-api-key-here"
 
# Poll job status in a loop
#!/bin/bash
 
JOB_ID="550e8400-e29b-41d4-a716-446655440000"
API_KEY="your-api-key-here"
 
for i in {1..30}; do
  echo "Poll attempt $i..."
  
  RESPONSE=$(curl -s -X GET "https://api.tokenthon.com/api/v1/jobs/$JOB_ID" \
    -H "x-api-key: $API_KEY")
  
  STATUS=$(echo $RESPONSE | jq -r '.data.status')
  
  echo "Status: $STATUS"
  
  if [ "$STATUS" = "completed" ]; then
    RESULT=$(echo $RESPONSE | jq -r '.data.result.response_message')
    echo "Job completed! Result: $RESULT"
    break
  elif [ "$STATUS" = "failed" ]; then
    ERROR=$(echo $RESPONSE | jq -r '.data.error')
    echo "Job failed! Error: $ERROR"
    break
  fi
  
  if [ $i -eq 30 ]; then
    echo "Timeout reached"
    break
  fi
  
  sleep 2
done

  • Use exponential backoff for polling intervals
  • Implement a maximum number of polling attempts
  • Add jitter to prevent thundering herd problems

  • Handle different error scenarios gracefully
  • Log job IDs for debugging
  • Implement retry logic for transient errors

  • Cache job results to avoid redundant API calls
  • Use webhooks when possible instead of polling
  • Batch status checks for multiple jobs

  • Validate job IDs before making API calls
  • Use secure storage for API keys
  • Implement rate limiting on the client side

code
Created → Pending → Assigned → Completed/Failed
    ↑        ↓         ↓           ↓
    │   (queued)  (processing)  (finished)
    └─────────────────────────────┘
  1. Created: Job is initially created (not a retrievable status)
  2. Pending: Job is in queue waiting for processing
  3. Assigned: Job is being processed by a worker
  4. Completed: Job finished successfully
  5. Failed: Job failed due to an error

  • Invalid Job ID: Job doesn't exist or has expired
  • Authentication Issues: Missing or invalid API key
  • Rate Limiting: Too many requests in short time
  • Service Unavailable: Temporary service issues

  • Timeout: Job took too long to complete
  • Content Policy: Request violated content policies
  • Model Errors: Issues with the specified AI model
  • Validation Errors: Invalid request parameters

  • Check job status at regular intervals
  • Good for small numbers of jobs
  • Easy to implement

  • Increase polling interval over time
  • Reduces server load
  • Better for long-running jobs

  • Use webhooks for primary notifications
  • Fall back to polling if webhook fails
  • Most reliable approach

  • Check multiple jobs in sequence
  • Efficient for batch operations
  • Consolidates status updates