Skip to content

Signed URL

Generate a time-limited signed URL for a result asset stored in object storage (e.g., an annotated image or JSON output from a previous prediction). The URL grants temporary read access without requiring authentication on the client side.


POST /inference/assets/signed-url

Request

Content-Type: application/json

Field Type Required Default Description
object_path string Yes Path to the object in storage (e.g., results/output.json)
expires_in integer No 3600 URL expiry time in seconds
{
  "object_path": "results/abc123/output.json",
  "expires_in": 3600
}

Response

Field Type Description
object_path string The original object path
signed_url string The temporary signed URL to access the asset
expires_in integer Expiry duration in seconds
{
  "object_path": "results/abc123/output.json",
  "signed_url": "https://storage.example.com/results/abc123/output.json?signature=...",
  "expires_in": 3600
}

URL expiry

Signed URLs are valid only for the expires_in period. Request a new URL before expiry if you need continued access.


Code Examples

async function getSignedUrl(objectPath, expiresIn = 3600) {
  const response = await fetch(
    "https://sightapi.raku.so/api/v1/inference/assets/signed-url",
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ object_path: objectPath, expires_in: expiresIn }),
    }
  );

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.detail?.message ?? "Request failed");
  }

  return response.json();
}

// Usage
const { signed_url } = await getSignedUrl("results/abc123/output.json");
console.log("Download URL:", signed_url);

// Fetch the asset
const asset = await fetch(signed_url);
const data = await asset.json();
interface SignedUrlResponse {
  object_path: string;
  signed_url: string;
  expires_in: number;
}

async function getSignedUrl(
  objectPath: string,
  expiresIn: number = 3600
): Promise<SignedUrlResponse> {
  const response = await fetch(
    "https://sightapi.raku.so/api/v1/inference/assets/signed-url",
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ object_path: objectPath, expires_in: expiresIn }),
    }
  );

  if (!response.ok) {
    const error = await response.json();
    throw new Error((error.detail as { message: string })?.message ?? "Request failed");
  }

  return response.json() as Promise<SignedUrlResponse>;
}

// Usage
const { signed_url } = await getSignedUrl("results/abc123/output.json");
console.log("Download URL:", signed_url);
import httpx
from dataclasses import dataclass

@dataclass
class SignedUrlResponse:
    object_path: str
    signed_url: str
    expires_in: int

def get_signed_url(object_path: str, expires_in: int = 3600) -> SignedUrlResponse:
    with httpx.Client() as client:
        response = client.post(
            "https://sightapi.raku.so/api/v1/inference/assets/signed-url",
            json={"object_path": object_path, "expires_in": expires_in},
        )
        response.raise_for_status()
        data = response.json()
        return SignedUrlResponse(**data)

# Usage
result = get_signed_url("results/abc123/output.json")
print("Download URL:", result.signed_url)

# Fetch the asset
with httpx.Client() as client:
    asset = client.get(result.signed_url)
    print(asset.json())
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json.Serialization;

public record SignedUrlResponse(
    [property: JsonPropertyName("object_path")] string ObjectPath,
    [property: JsonPropertyName("signed_url")] string SignedUrl,
    [property: JsonPropertyName("expires_in")] int ExpiresIn);

public class RakuSightClient
{
    private static readonly HttpClient Http = new();

    public static async Task<SignedUrlResponse> GetSignedUrlAsync(
        string objectPath, int expiresIn = 3600)
    {
        var payload = new { object_path = objectPath, expires_in = expiresIn };

        var response = await Http.PostAsJsonAsync(
            "https://sightapi.raku.so/api/v1/inference/assets/signed-url",
            payload);

        response.EnsureSuccessStatusCode();

        return await response.Content.ReadFromJsonAsync<SignedUrlResponse>()
            ?? throw new InvalidOperationException("Empty response");
    }
}

// Usage
var result = await RakuSightClient.GetSignedUrlAsync("results/abc123/output.json");
Console.WriteLine($"Download URL: {result.SignedUrl}");

// Fetch the asset via the signed URL
var asset = await new HttpClient().GetStringAsync(result.SignedUrl);
Console.WriteLine(asset);
import java.net.http.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class RakuSightClient {

    private static final HttpClient CLIENT = HttpClient.newHttpClient();
    private static final ObjectMapper MAPPER = new ObjectMapper();

    public static JsonNode getSignedUrl(String objectPath, int expiresIn) throws Exception {
        String body = String.format(
            "{\"object_path\":\"%s\",\"expires_in\":%d}",
            objectPath, expiresIn
        );

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://sightapi.raku.so/api/v1/inference/assets/signed-url"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
            .build();

        HttpResponse<String> response = CLIENT.send(
            request, HttpResponse.BodyHandlers.ofString());

        if (response.statusCode() != 200) {
            throw new RuntimeException("Request failed: " + response.body());
        }

        return MAPPER.readTree(response.body());
    }

    public static void main(String[] args) throws Exception {
        JsonNode result = getSignedUrl("results/abc123/output.json", 3600);
        String signedUrl = result.get("signed_url").asText();
        System.out.println("Download URL: " + signedUrl);

        // Fetch the asset
        HttpRequest assetRequest = HttpRequest.newBuilder()
            .uri(URI.create(signedUrl))
            .GET()
            .build();

        HttpResponse<String> asset = CLIENT.send(
            assetRequest, HttpResponse.BodyHandlers.ofString());
        System.out.println(asset.body());
    }
}
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type SignedUrlRequest struct {
    ObjectPath string `json:"object_path"`
    ExpiresIn  int    `json:"expires_in"`
}

type SignedUrlResponse struct {
    ObjectPath string `json:"object_path"`
    SignedURL  string `json:"signed_url"`
    ExpiresIn  int    `json:"expires_in"`
}

func getSignedUrl(objectPath string, expiresIn int) (*SignedUrlResponse, error) {
    if expiresIn == 0 {
        expiresIn = 3600
    }

    payload, _ := json.Marshal(SignedUrlRequest{
        ObjectPath: objectPath,
        ExpiresIn:  expiresIn,
    })

    resp, err := http.Post(
        "https://sightapi.raku.so/api/v1/inference/assets/signed-url",
        "application/json",
        bytes.NewReader(payload),
    )
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    var result SignedUrlResponse
    json.NewDecoder(resp.Body).Decode(&result)
    return &result, nil
}

func main() {
    result, err := getSignedUrl("results/abc123/output.json", 3600)
    if err != nil {
        panic(err)
    }
    fmt.Println("Download URL:", result.SignedURL)

    // Fetch the asset via signed URL
    assetResp, _ := http.Get(result.SignedURL)
    defer assetResp.Body.Close()

    var asset map[string]any
    json.NewDecoder(assetResp.Body).Decode(&asset)
    fmt.Println(asset)
}