JavaScript

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

OptionTypeDefaultDescription
apiKeystringSATEAIS_API_KEYAPI key. Falls back to the environment variable.
baseUrlstringhttps://api.spcsft.com/api/v1API base URL. Trailing slashes are removed.
timeoutMsnumber30_000Per-request timeout in milliseconds. Set to 0 to disable the timeout.
fetchtypeof fetchglobal fetchCustom fetch implementation.
apiClientApiClientInject a custom transport implementing the ApiClient interface. Intended for testing — when set, all HTTP options above are ignored.

Properties

PropertyTypeDescription
analyzeAnalyzeResourceDetection job submission methods.
jobsJobsResourceJob 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;
}
OptionTypeDefaultDescription
intervalMsnumber60_000Milliseconds between status polls.
timeoutMsnumberInfinityMaximum time to wait before throwing JobTimeoutError.
onPoll(job: JobStatusResponse) => voidCalled 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.

ErrorMaps toDescription
SateaisErrorBase class for every SDK error.
SateaisApiError4xx / 5xxBase for API error responses. Has code and status.
AuthenticationError401 / 403Missing, invalid, or unauthorized API key.
ValidationError400Invalid request — bad parameter or polygon over the area cap.
InsufficientCreditsError402Not enough credits for the job.
NotFoundError404 / 410Job not found, or result past retention.
RateLimitError429Request or concurrency limit exceeded.
ResponseParseErrorA successful (2xx) response body could not be parsed as JSON. Has status. Extends SateaisError, not SateaisApiError.
JobFailedErrorA job did not complete successfully. Has jobId, errorCode, errorMessage.
JobTimeoutErrorjobs.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);
  }
}

Next steps

On this page