Upload an Image
curl --request PUT \
--url https://{host}/v1/images/{gall_id}/{post_no}/{NN} \
--header 'Authorization: <api-key>' \
--header 'Content-Type: image/jpeg' \
--data '"<string>"'import requests
url = "https://{host}/v1/images/{gall_id}/{post_no}/{NN}"
payload = "<string>"
headers = {
"Authorization": "<api-key>",
"Content-Type": "image/jpeg"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: '<api-key>', 'Content-Type': 'image/jpeg'},
body: JSON.stringify('<string>')
};
fetch('https://{host}/v1/images/{gall_id}/{post_no}/{NN}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{host}/v1/images/{gall_id}/{post_no}/{NN}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode('<string>'),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: image/jpeg"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{host}/v1/images/{gall_id}/{post_no}/{NN}"
payload := strings.NewReader("\"<string>\"")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "image/jpeg")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://{host}/v1/images/{gall_id}/{post_no}/{NN}")
.header("Authorization", "<api-key>")
.header("Content-Type", "image/jpeg")
.body("\"<string>\"")
.asString();require 'uri'
require 'net/http'
url = URI("https://{host}/v1/images/{gall_id}/{post_no}/{NN}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'image/jpeg'
request.body = "\"<string>\""
response = http.request(request)
puts response.read_body{
"error": {
"code": "bad_request",
"message": "2 fields failed validation",
"fields": [
{
"path": "candidates[0].created_at",
"problem": "timestamp must include an explicit offset"
},
{
"path": "engagement[3].views",
"problem": "must be a non-negative integer or null"
}
]
}
}{
"error": {
"code": "unauthorized",
"message": "API key missing or unknown"
}
}{
"error": {
"code": "conflict",
"message": "image already exists with different bytes"
}
}{
"error": {
"code": "too_large",
"message": "JSON body exceeds 16 MiB after decompression"
}
}{
"error": {
"code": "unsupported_media_type",
"message": "expected image/jpeg"
}
}{
"error": {
"code": "server_error",
"message": "internal error"
}
}Images API
Upload an Image
Proposed image transfer for new rehearsal candidates
PUT
/
v1
/
images
/
{gall_id}
/
{post_no}
/
{NN}
Upload an Image
curl --request PUT \
--url https://{host}/v1/images/{gall_id}/{post_no}/{NN} \
--header 'Authorization: <api-key>' \
--header 'Content-Type: image/jpeg' \
--data '"<string>"'import requests
url = "https://{host}/v1/images/{gall_id}/{post_no}/{NN}"
payload = "<string>"
headers = {
"Authorization": "<api-key>",
"Content-Type": "image/jpeg"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: '<api-key>', 'Content-Type': 'image/jpeg'},
body: JSON.stringify('<string>')
};
fetch('https://{host}/v1/images/{gall_id}/{post_no}/{NN}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{host}/v1/images/{gall_id}/{post_no}/{NN}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode('<string>'),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: image/jpeg"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://{host}/v1/images/{gall_id}/{post_no}/{NN}"
payload := strings.NewReader("\"<string>\"")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "image/jpeg")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://{host}/v1/images/{gall_id}/{post_no}/{NN}")
.header("Authorization", "<api-key>")
.header("Content-Type", "image/jpeg")
.body("\"<string>\"")
.asString();require 'uri'
require 'net/http'
url = URI("https://{host}/v1/images/{gall_id}/{post_no}/{NN}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'image/jpeg'
request.body = "\"<string>\""
response = http.request(request)
puts response.read_body{
"error": {
"code": "bad_request",
"message": "2 fields failed validation",
"fields": [
{
"path": "candidates[0].created_at",
"problem": "timestamp must include an explicit offset"
},
{
"path": "engagement[3].views",
"problem": "must be a non-negative integer or null"
}
]
}
}{
"error": {
"code": "unauthorized",
"message": "API key missing or unknown"
}
}{
"error": {
"code": "conflict",
"message": "image already exists with different bytes"
}
}{
"error": {
"code": "too_large",
"message": "JSON body exceeds 16 MiB after decompression"
}
}{
"error": {
"code": "unsupported_media_type",
"message": "expected image/jpeg"
}
}{
"error": {
"code": "server_error",
"message": "internal error"
}
}DCinside sends each candidate’s images once when it enters the queue. Surf proposes a separate upload endpoint; HTTPS versus an S3 folder and the exact layout remain open technical decisions.
The existing proposal follows the delivered v1.3 layout,
<gall_id>/<post_no>/<NN>.jpg. NN is the original body’s one-based image position, zero-padded to at least two digits. Gaps are permitted when a source image cannot be fetched. Preserve original positions rather than renumbering.
The delivered image convention includes all images, resized to a maximum 1,024-pixel long edge without upscaling. The request body for this endpoint is JPEG. The current server has a 5 MiB per-image engineering limit; verify it against rehearsal data rather than treating it as a client quota.
images_in_post and optional image_positions describe expected uploads. Confirm these fields and missing-image handling with the client. Whether scoring waits for image features is not settled by using a separate upload route. Verify image readiness and fallback behavior with the actual Model 0924 pipeline before rehearsal.
The optional X-Content-SHA256 header checks the uploaded bytes. Repeating the same image path with identical bytes is safe in the current implementation. Different bytes at an existing image key return 409; the stored image is preserved. Verify image retention and replay across restarts before rehearsal. The current route accepts only 1–3 digits for NN and stores a three-digit name; confirm this path convention against the client image layout rather than assuming it matches every source filename.Authorizations
Proposed API key sent as the whole Authorization header value. Long-lived credential scope, handoff and rotation need confirmation. Per-endpoint scopes are not currently enforced.
Headers
Hex SHA-256 of the body. When present we verify it, and a mismatch is rejected with 400.
Pattern:
^[0-9a-f]{64}$Path Parameters
Gallery id.
Minimum string length:
1Example:
"example_gallery"
Post number.
Required range:
x >= 1Example:
31900001
The image's position in the original body: one-based, zero-padded to at least two digits, gaps allowed. The v1.3 layout <gall_id>/<post_no>/<NN>.jpg.
Pattern:
^\d{2,}$Example:
"01"
Body
image/jpeg
The JPEG, 1024 px on the long edge. Smaller originals are not upscaled.
Response
Already stored with the same bytes.