Working with the API
Jobs
Two hosts, one job. Submit and follow it on the queue; read, cancel and download it on the platform.
A generation is a job. You submit it, it runs without you, and you collect it later.
#Two hosts, one job
The queue host follows the common IN_QUEUE / IN_PROGRESS / COMPLETED queue protocol, so a client
written for it works unchanged (Compatibility). The platform host holds the account's view of the same job. They share every id.
| Host | Does | |
|---|---|---|
POST /<address> | queue.auray.run | Submits. Answers the queue envelope below. |
GET /<address>/requests/{id}/status | queue.auray.run | Where it is: IN_QUEUE, IN_PROGRESS, COMPLETED. Add ?logs=1 for progress lines. |
GET /<address>/requests/{id}/status/stream | queue.auray.run | The same, as server-sent events until it completes. Each stream closes after a few minutes with no final frame; reconnect and keep reading, as the official clients do. |
GET /<address>/requests/{id} | queue.auray.run | The result once COMPLETED. Before then it answers 400 request_in_progress, as that protocol does. |
PUT /<address>/requests/{id}/cancel | queue.auray.run | Asks it to stop: 202 requested, 400 already completed, 404 unknown. |
POST /<address> | auray.run | The same submit, held open until the job settles or 300 seconds pass. |
GET /v1/jobs/{id} | api.auray.ai | The job as the account sees it: five statuses, settled, the charge. |
GET /v1/jobs/{id}/assets | api.auray.ai | Signed download URLs. Metered by the megabyte. |
DELETE /v1/jobs/{id} | api.auray.ai | Cancel, and answer what the job became. |
GET /v1/jobs | api.auray.ai | The account's jobs, newest first. |
{id} is the request_id the submit answered: <product>_<your idempotency key>.
#Five statuses, three states
queued ──▶ running ──▶ succeeded
├─▶ failed
└─▶ cancelled| Status | Queue state | Means |
|---|---|---|
queued | IN_QUEUE | Accepted and waiting. Nothing has started. |
running | IN_PROGRESS | Running now. |
succeeded | COMPLETED | Finished. assets holds the output. |
failed | COMPLETED | Stopped. error_code says why, and the charge is reversed. |
cancelled | COMPLETED | You stopped it. What hadn't been made yet is refunded. |
Only queued and running are open. Once a job reaches any of the other three it never changes
again, and settled: true on the platform read says the charge is final too.
A failed job is COMPLETED, which reads wrong and is right: it has finished queueing and
finished running, and the failure travels in error rather than in the state. A client that loops
until COMPLETED terminates on every outcome. A fourth FAILED state is exactly the change that
would make such a client loop for ever.
#Submitting
curl -X POST https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image \
-H "Authorization: Bearer $AURAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "prompt": "…", "aspect_ratio": "16:9", "resolution": 1024 }'import { randomUUID } from "node:crypto";
import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
const job = await auray.queue.submit("auray-ai/krea-2-turbo/text-to-image", {
input: {
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
},
idempotencyKey: randomUUID(),
});
console.log(job.request_id, job.status);import uuid
from auray_client import Client
auray = Client() # reads AURAY_API_KEY
job = auray.queue.submit(
"auray-ai/krea-2-turbo/text-to-image",
input={
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
},
idempotency_key=str(uuid.uuid4()),
)
print(job["request_id"], job["status"]){
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "submit_job",
"arguments": {
"address": "auray-ai/krea-2-turbo/text-to-image",
"input": {
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
}
}
}
}import { randomUUID } from "node:crypto";
const res = await fetch("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
"content-type": "application/json",
"Idempotency-Key": randomUUID(),
},
body: JSON.stringify({
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
}),
});
console.log(res.status, await res.json());import os, uuid, requests
r = requests.post(
"https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
},
)
r.raise_for_status()
print(r.json())package main
import (
"bytes"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"net/http"
"os"
)
func main() {
body := []byte(`{
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
}`)
req, err := http.NewRequest("POST", "https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image", bytes.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
req.Header.Set("Content-Type", "application/json")
key := make([]byte, 16)
rand.Read(key)
req.Header.Set("Idempotency-Key", hex.EncodeToString(key))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
"Content-Type: application/json",
"Idempotency-Key: " . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => json_encode([
"prompt" => "…",
"aspect_ratio" => "16:9",
"resolution" => 1024,
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
require "json"
require "securerandom"
uri = URI("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
req["Idempotency-Key"] = SecureRandom.uuid
req["Content-Type"] = "application/json"
req.body = {
"prompt" => "…",
"aspect_ratio" => "16:9",
"resolution" => 1024
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;
public class Main {
public static void main(String[] args) throws Exception {
String body = """
{
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.header("Idempotency-Key", UUID.randomUUID().toString())
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Post, "https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image");
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
var body = """
{
"prompt": "…",
"aspect_ratio": "16:9",
"resolution": 1024
}
""";
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");You get 200 with the queue envelope straight away. The connection closing does not affect the
job. Quickstart shows the whole body; the fields that matter here are
request_id, status, queue_position (how many are ahead while the platform is full),
credits_charged, credits_quoted, expected_seconds, and the three URLs. A job that waits in the
queue is charged when it starts, not when it is submitted: until then its credits_charged is 0,
and credits_quoted is what it will be charged.
Two options travel as query parameters on the submit: ?webhook=<url> (or ?fal_webhook=) asks
for a signed delivery when the job settles, and ?wait=<seconds> holds the request open on the
queue host for up to that long. The synchronous host does the second by default.
#Polling
curl "https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1" \
-H "Authorization: Bearer $AURAY_API_KEY"import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
const status = await auray.queue.status("auray-ai/krea-2-turbo/text-to-image", { requestId: "photo_docs-mtpb1vnh", logs: true });
console.log(status.status);from auray_client import Client
auray = Client() # reads AURAY_API_KEY
status = auray.queue.status("auray-ai/krea-2-turbo/text-to-image", request_id="photo_docs-mtpb1vnh", logs=True)
print(status["status"]){
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "check_job",
"arguments": {
"address": "auray-ai/krea-2-turbo/text-to-image",
"request_id": "photo_docs-mtpb1vnh"
}
}
}const res = await fetch("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, requests
r = requests.get(
"https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
)
r.raise_for_status()
print(r.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest("GET", "https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
],
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
uri = URI("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Get, "https://queue.auray.run/auray-ai/krea-2-turbo/text-to-image/requests/photo_docs-mtpb1vnh/status?logs=1");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{
"status": "IN_PROGRESS",
"request_id": "photo_docs-mtpb1vnh",
"job_id": "photo_docs-mtpb1vnh",
"logs": [],
"metrics": {},
"status_url": "…", "response_url": "…", "cancel_url": "…"
}metrics.inference_time appears once the runner has reported how long the work itself took.
Video reports its phase as a log line while it runs.
The platform read is the same job from the account's side, and it tells you how long to wait:
curl https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh \
-H "Authorization: Bearer $AURAY_API_KEY"import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
console.log(await auray.platform.jobs.get("photo_docs-mtpb1vnh"));from auray_client import Client
auray = Client() # reads AURAY_API_KEY
print(auray.platform.jobs.get("photo_docs-mtpb1vnh"))const res = await fetch("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, requests
r = requests.get(
"https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
)
r.raise_for_status()
print(r.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest("GET", "https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
],
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
uri = URI("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");{
"id": "photo_docs-mtpb1vnh",
"job_id": "photo_docs-mtpb1vnh",
"object": "job",
"product": "photo",
"model": "auray-ai/krea-2-turbo/text-to-image",
"engine": "Krea 2 Turbo",
"status": "succeeded",
"settled": true,
"provider_job_id": "f30c5f765770468097181c2bcb31fd4d",
"credits_charged": 4,
"credits_reserved": 4,
"created_at": "2026-09-06T04:21:58.245391+00:00",
"error": null,
"error_code": null,
"assets": [
{ "index": 0, "kind": "image", "key": "photo/krea-2-turbo/f30c5f765770468097181c2bcb31fd4d/0.png", "width": 1344, "height": 768, "bytes": 1065131 }
],
"request_id": "fd85461a-706a-4c71-9d0d-5391319b442a"
}While a job is open the read carries poll_after_seconds; honour it. Reads are rate-limited on
their own bucket, and a 429 carries Retry-After. Both RateLimit-* and X-RateLimit-*
headers say where you stand on every answer.
For anything slower than a few seconds, a webhook is better: you get told once, at the moment it settles, instead of asking repeatedly.
#Collecting the output
The job's assets name what was made. The signed URLs to download it come from one route, on
the platform host, because signing them is metered against the egress bucket and a status poll
is not. The bucket counts the signing, not the fetch: a signed link can be fetched again until it
expires, and asking for the links again counts their size again:
curl https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets \
-H "Authorization: Bearer $AURAY_API_KEY"import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
const { assets } = await auray.platform.jobs.assets("photo_docs-mtpb1vnh");
for (const asset of assets) console.log(asset.url);from auray_client import Client
auray = Client() # reads AURAY_API_KEY
listing = auray.platform.jobs.assets("photo_docs-mtpb1vnh")
for asset in listing["assets"]:
print(asset["url"]){
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_job_result",
"arguments": {
"address": "auray-ai/krea-2-turbo/text-to-image",
"request_id": "photo_docs-mtpb1vnh",
"assets": true
}
}
}const res = await fetch("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, requests
r = requests.get(
"https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
)
r.raise_for_status()
print(r.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest("GET", "https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
],
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
uri = URI("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh/assets");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");Each asset comes back with filename, content_type, bytes and a url that is good for
15 minutes; the answer's expires_at says when. Download what you intend to keep — treat the
URL as a handle to fetch through, not as permanent storage. Fetching assets needs assets:read.
A job is kept 3 days. After that its request and its results are deleted, and both
GET /v1/jobs/{id} and its assets answer 404 not_found — fetch what you need before then. In
the minutes between the end of its 3 days and the sweep that deletes it, its assets answer
410 expired with reason: retention_ended instead: no link is signed past the life of the file
it points at.
#Cancelling
curl -X DELETE https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh \
-H "Authorization: Bearer $AURAY_API_KEY"import { createClient } from "@auray/client";
const auray = createClient(); // reads AURAY_API_KEY
console.log(await auray.platform.jobs.cancel("photo_docs-mtpb1vnh"));from auray_client import Client
auray = Client() # reads AURAY_API_KEY
print(auray.platform.jobs.cancel("photo_docs-mtpb1vnh"))const res = await fetch("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.AURAY_API_KEY}`,
},
});
console.log(res.status, await res.json());import os, requests
r = requests.delete(
"https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh",
headers={"Authorization": f"Bearer {os.environ['AURAY_API_KEY']}"},
)
r.raise_for_status()
print(r.json())package main
import (
"fmt"
"io"
"net/http"
"os"
)
func main() {
req, err := http.NewRequest("DELETE", "https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh", nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("AURAY_API_KEY"))
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, _ := io.ReadAll(res.Body)
fmt.Println(res.Status, string(out))
}<?php
$ch = curl_init("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("AURAY_API_KEY"),
],
]);
$response = curl_exec($ch);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $response, PHP_EOL;require "net/http"
uri = URI("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("AURAY_API_KEY")}"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.code, res.bodyimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh"))
.header("Authorization", "Bearer " + System.getenv("AURAY_API_KEY"))
.DELETE()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode() + " " + response.body());
}
}using System.Net.Http.Headers;
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AURAY_API_KEY"));
using var request = new HttpRequestMessage(HttpMethod.Delete, "https://api.auray.ai/v1/jobs/photo_docs-mtpb1vnh");
using var response = await client.SendAsync(request);
Console.WriteLine($"{(int)response.StatusCode} {await response.Content.ReadAsStringAsync()}");The answer says what the job became, whichever way it went:
{
"id": "photo_docs-mtpb1vnh",
"object": "job",
"product": "photo",
"status": "succeeded",
"settled": true,
"cancelled": false,
"credits_charged": 4,
"credits_reserved": 4,
"request_id": "9caaaf7e-d181-4892-90b1-6a7a74032d9a"
}The queue host's PUT …/cancel answers the protocol's three: 202 with CANCELLATION_REQUESTED, 400
already_completed, or 404.
#Money
A refused job is never charged. Anything caught before inference — a bad scope, a malformed body, no credits, a ceiling reached, an address that is not open yet — costs nothing.
A job that fails after starting is refunded automatically. You do not file anything and there is nothing to reconcile.
Every case, product by product — read from the same declaration the refunds are tested against:
| Case | Images | Music | Video | 3D | Catalogue models |
|---|---|---|---|---|---|
| Refused before it starts | Nothing is charged. | Nothing is charged. | Nothing is charged. | Nothing is charged. | Nothing is charged. |
| Waiting for a slot | Nothing is charged until it is dispatched. | Nothing is charged until it is dispatched. | Nothing is charged until it is dispatched. | Nothing is charged until it is dispatched. | No queue: it runs or is refused. |
| Failed | Everything comes back. | Everything comes back. | Everything comes back. | Everything comes back. | Everything comes back. |
| Partly withheld or short | What did not arrive comes back; if nothing arrived, everything does. | What did not arrive comes back; if nothing arrived, everything does. | What did not arrive comes back; if nothing arrived, everything does. | What did not arrive comes back; if nothing arrived, everything does. | What did not arrive comes back; if nothing arrived, everything does. |
| Stopped before it began | Everything comes back. | Everything comes back. | Everything comes back. | Everything comes back until the service starts it; from then — which can be while it still reads queued — the first stage's start-up share is kept. | A job cannot be stopped. |
| Stopped while running | Everything comes back. | The base price is kept, and so is what already ran, rounded down; the rest comes back. | What already ran is kept, rounded down; the rest comes back. | What already ran is kept, rounded down; the rest comes back. | A job cannot be stopped; it finishes and is charged for what it delivers. |
| Stopped responding | Closed 30 minutes after it started, and everything comes back. | Closed 2 hours after it started, and everything comes back. | Closed 210 minutes after it started, and everything comes back. | Closed 2 hours after it started, and everything comes back. | Closed 2 hours after it started, and everything comes back. |
So the only credits you keep paying for are the ones that produced something.