JavaScript reference
Full reference for the SateAIs JavaScript/TypeScript SDK — client, analysis methods, jobs, types, and errors.
Complete reference for the @sateais/sdk package. For setup and authentication, see the JavaScript SDK guide.
Client
import { Client } from "@sateais/sdk";
const client = new Client(options?: ClientOptions);ClientOptions
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | SATEAIS_API_KEY | API key. Falls back to the environment variable. |
baseUrl | string | https://api.spcsft.com/api/v1 | API base URL. Trailing slashes are removed. |
timeoutMs | number | 30_000 | Per-request timeout in milliseconds. Set to 0 to disable the timeout. |
fetch | typeof fetch | global fetch | Custom fetch implementation. |
apiClient | ApiClient | — | Inject a custom transport implementing the ApiClient interface. Intended for testing — when set, all HTTP options above are ignored. |
Properties
| Property | Type | Description |
|---|---|---|
analyze | AnalyzeResource | Detection job submission methods. |
jobs | JobsResource | Job status and result methods. |
Analysis methods
All client.analyze.* methods submit a detection job and resolve to a JobCreateResponse with status "pending". Use jobs.wait() to await the result.
analyze.ship / analyze.oilslick
client.analyze.ship(params: SceneAnalyzeParams): Promise<JobCreateResponse>analyze.oilslick(...) has the same signature. SceneAnalyzeParams is a union — pass either a scene_id or a polygon + date:
type SceneAnalyzeParams = SceneIdInput | PolygonDateInput;
interface SceneIdInput {
satellite_id?: "sentinel-1";
scene_id: string;
}
interface PolygonDateInput {
satellite_id?: "sentinel-1";
polygon: string; // WKT, EPSG:4326
date: string; // "YYYY-MM-DD"
date_direction?: "before" | "after" | "nearest"; // default "nearest"
orbit_direction?: "ascending" | "descending";
}// By scene ID
const job = await client.analyze.ship({ scene_id: "S1A_IW_GRDH_..." });
// By polygon + date (auto scene selection)
const job = await client.analyze.oilslick({
polygon: "POLYGON((55.5 26.7, 56.1 26.7, 56.1 27.0, 55.5 27.0, 55.5 26.7))",
date: "2026-03-10",
date_direction: "nearest",
});analyze.newbuilding / analyze.disappearbuilding / analyze.timeseries
client.analyze.newbuilding(params: PolygonPeriodParams): Promise<JobCreateResponse>analyze.disappearbuilding(...) and analyze.timeseries(...) share this signature.
interface PolygonPeriodParams {
satellite_id?: "sentinel-1";
polygon: string; // WKT, EPSG:4326
date_start: string; // "YYYY-MM-DD"
date_end: string; // "YYYY-MM-DD"
orbit_direction?: "ascending" | "descending";
}const job = await client.analyze.timeseries({
polygon: "POLYGON((139.7 35.6, 139.8 35.6, 139.8 35.7, 139.7 35.7, 139.7 35.6))",
date_start: "2026-01-01",
date_end: "2026-05-01",
});Per-endpoint area caps apply: newbuilding / disappearbuilding ≤ 30,000 km², timeseries ≤ 50 km². Exceeding a cap throws ValidationError before any credits are consumed. See Polygons & AOI.
Job methods
jobs.status
client.jobs.status(jobId: string): Promise<JobStatusResponse>Fetches the current state of a job (a single poll).
const job = await client.jobs.status("351e635d-7c25-4ae8-a2a5-60c01a6f434c");
console.log(job.status);jobs.result
client.jobs.result(jobId: string): Promise<GeoJSONResponse>Returns the GeoJSON FeatureCollection for a completed job. Throws NotFoundError if the job is not complete or the result is past its 30-day retention window.
const geojson = await client.jobs.result("351e635d-7c25-4ae8-a2a5-60c01a6f434c");
console.log(geojson.type, geojson.features.length);jobs.wait
client.jobs.wait(jobId: string, options?: WaitOptions): Promise<GeoJSONResponse>Polls until the job reaches a terminal state, then resolves to the result GeoJSON.
interface WaitOptions {
intervalMs?: number; // default 60_000
timeoutMs?: number; // default Infinity (no limit)
onPoll?: (job: JobStatusResponse) => void;
}| Option | Type | Default | Description |
|---|---|---|---|
intervalMs | number | 60_000 | Milliseconds between status polls. |
timeoutMs | number | Infinity | Maximum time to wait before throwing JobTimeoutError. |
onPoll | (job: JobStatusResponse) => void | — | Called with the latest status after each poll. |
Rejects with JobTimeoutError if timeoutMs elapses first, or JobFailedError if the job reaches any status other than pending, processing, or completed — this includes failed as well as unrecognized statuses, so polling never loops forever.
const result = await client.jobs.wait(job.job_id, {
intervalMs: 30_000,
timeoutMs: 3_600_000,
onPoll: (j) => console.log(j.status),
});Tip
Detection jobs typically run 30–60 minutes, so intervalMs defaults to 60 s. See How it works.
Types
JobCreateResponse
Returned by all analyze.* methods.
interface JobCreateResponse {
job_id: string;
status: JobStatus; // "pending" | "processing" | "completed" | "failed"
created_at: string; // ISO 8601
completed_at: string | null;
result_path: string | null;
error: string | null; // null while pending
}JobStatusResponse
Returned by jobs.status().
interface JobStatusResponse {
job_id: string;
status: JobStatus;
created_at: string;
completed_at: string | null;
result_path: string | null;
error_code: string | null; // set when failed
error_message: string | null; // set when failed
error: string | null; // @deprecated — mirrors error_code
}GeoJSONResponse
Returned by jobs.result() and jobs.wait() — a standard GeoJSON FeatureCollection in EPSG:4326.
interface GeoJSONResponse {
type: "FeatureCollection";
features: GeoJSONFeature[];
crs?: { type: string; properties: Record<string, unknown> };
}Errors
All errors inherit from SateaisError.
| Error | Maps to | Description |
|---|---|---|
SateaisError | — | Base class for every SDK error. |
SateaisApiError | 4xx / 5xx | Base for API error responses. Has code and status. |
AuthenticationError | 401 / 403 | Missing, invalid, or unauthorized API key. |
ValidationError | 400 | Invalid request — bad parameter or polygon over the area cap. |
InsufficientCreditsError | 402 | Not enough credits for the job. |
NotFoundError | 404 / 410 | Job not found, or result past retention. |
RateLimitError | 429 | Request or concurrency limit exceeded. |
ResponseParseError | — | A successful (2xx) response body could not be parsed as JSON. Has status. Extends SateaisError, not SateaisApiError. |
JobFailedError | — | A job did not complete successfully. Has jobId, errorCode, errorMessage. |
JobTimeoutError | — | jobs.wait() exceeded timeoutMs. Has jobId. |
import { SateaisApiError } from "@sateais/sdk";
try {
await client.analyze.ship({ scene_id: "bad-id" });
} catch (err) {
if (err instanceof SateaisApiError) {
console.error(err.status, err.code, err.message);
}
}