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}
| Header | Type | Required | Description |
|---|---|---|---|
x-api-key | string | Yes | Your API key for authentication |
| Parameter | Type | Required | Description |
|---|---|---|---|
jobId | string | Yes | The 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>;
};
}| Field | Type | Description |
|---|---|---|
status | string | Current job status: pending, assigned, completed, failed |
job_id | string | Unique identifier for the job |
created_at | number | Unix timestamp when the job was created |
result | object | Contains the AI response if job completed successfully |
error | string/object | Error details if job failed |
| Status | Description | When it occurs |
|---|---|---|
pending | Job is queued and waiting to be processed | Immediately after creation |
assigned | Job has been assigned to a worker | When processing begins |
completed | Job finished successfully | When AI completes the request |
failed | Job failed with an error | When 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 Code | Description |
|---|---|
200 | Job result retrieved successfully |
401 | Unauthorized - missing or invalid API key |
404 | Job not found - invalid job ID |
429 | Rate limit exceeded |
500 | Internal 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)
└─────────────────────────────┘
- Created: Job is initially created (not a retrievable status)
- Pending: Job is in queue waiting for processing
- Assigned: Job is being processed by a worker
- Completed: Job finished successfully
- 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
POST /api/v1/jobs/messages- Create and execute a single jobPOST /api/v1/jobs/messages/batches- Create multiple jobs in a batch