Skip to main content
The Egocentric API annotates first-person videos asynchronously. Submit a batch of video URLs, save the returned batch and job IDs, then poll for completion and download each successful result. Each input becomes one job; all jobs in a batch use the same annotation options.

Authenticate

Use a Perceptron API key in the Authorization: Bearer header on every request, including result downloads. Batches and jobs belong to your organization and can be accessed with another valid key from that organization. Set PERCEPTRON_API_KEY in your environment. The examples use the public base URL https://api.perceptron.inc and require curl and jq.

Submit a batch

Save the following as egocentric-request.json. Replace the example URL with an HTTP(S) URL that serves your video directly. Keep the video accessible while the job is waiting to be processed. See input requirements and limits.
Choose a unique idempotency key for this submission and save it with the request. Reuse both if you need to repeat the request after a lost response.
A successful submission returns HTTP 202, a Location header pointing to the batch, and a JSON response containing the batch id and jobs array. The job IDs appear in the same order as your inputs. Save this mapping so you can associate each result with its source video. Acceptance does not mean the videos have passed media validation or finished processing. After a successful response, extract the batch ID and the first job ID:
See the submit reference for the request and response schemas.

Choose annotation options

hand_tracking accepts false to disable tracking, true to use the default 2d output, or an object such as {"output": "2d"} or {"output": "3d"}. Omitting it enables 2d tracking. hand_activity is a boolean and defaults to true. The options field in the returned batch contains the choices fixed at acceptance, including defaults. For enabled tracking, it returns the explicit output setting. Disabled annotation outputs are absent from the result. Every successful job also includes a timeline of video segments with start and end times. The timeline cannot be disabled, even when both hand options are false.

Repeat a submission safely

Send exactly one Idempotency-Key header containing 1–255 visible ASCII characters, with no spaces. Keys are scoped to your organization; changing API keys within that organization does not create a separate key namespace. Repeating an accepted key with the same request returns 202, the same batch and job IDs, and the same Location. The response shows the batch’s current progress and timing. It does not create new jobs or restart failed ones. Reusing that key with a different request returns 409 with error.code: "idempotency_conflict". Keep the original input order, URLs, filenames, and option fields. Adding an explicit default to a request that originally omitted it also changes the request. JSON object property order does not matter. Every POST attempt counts toward the submit request limit, including replays. For a genuinely new batch, use a new key. See retry guidance.

Follow progress

Retrieve the batch to see its counts and done fields:
done becomes true when every job is either completed or failed. A finished batch can contain both successful and failed jobs. Ignore any future keys you do not recognize in counts, and use done to tell when the batch has finished. Use the batch’s job list to inspect individual outcomes. Retrieve a single job when you need its status, timing, or failure details:
queued and submitted do not establish whether execution has started. Use the timing fields when their values are known. Only completed and failed are final. Treat any future, unknown status as unfinished. Allow time between polls and respect the shared read limit; avoid a tight polling loop.

Read timing fields

Use timestamps rather than status changes to measure execution. created_at is acceptance time; started_at and execution_finished_at are actual execution times when known. A null execution timestamp can mean the job never ran or the time is unknown. A job retains its last unfinished status until its result and billing are finalized. Its finished_at records that final completion, which can be later than execution_finished_at. There is no guaranteed start time or exact completion time. By default, jobs have a 72-hour execution deadline from created_at, including time spent waiting. This does not guarantee completion within 72 hours: result and billing finalization can continue afterward. For a batch, started_at is the earliest known job start. execution_finished_at is the latest execution end only after every job has a known end or is confirmed never to have run; it is null if any end is unknown or no job ran. Batch finished_at is the last job’s final completion time and stays null until done is true.

Download a result

Once a job is completed, download its JSON annotations:
The result endpoint returns the JSON body directly. Only use the saved file after the command succeeds and the JSON parses; an interrupted download can leave an incomplete file. The job’s expires_at is 30 days after finished_at, not 30 days after submission or execution end. Download results before that timestamp. An expired completed result returns 410 with result_expired; an unfinished or failed job returns 409 with result_unavailable.

Understand billing

Acceptance creates pending usage, not a completed charge. Successful jobs are charged using their validated video duration, accepted options, and pricing in effect at acceptance. Billing includes the timeline even when both hand options are false. For videos shorter than one minute, each enabled output, including the timeline, is billed as one minute. Failed jobs are not charged and any reserved credits are released. Replaying an accepted submission does not create another charge.

List batches and jobs

List batches or list jobs across your organization. Both use creation-time order, newest first by default. Set order=asc for oldest first, or created_after to include items created at or after an RFC 3339 timestamp.
When has_more is true, pass the response’s last_id as after in the next request, keeping the other query parameters unchanged. Omit after on the first request. An empty page has empty first_id and last_id strings. All list endpoints default to 100 items per page. Batch pages allow up to 100 items; job pages allow up to 1,000. The batch-specific job list always follows the original input order and accepts only limit and after. Its cursor must identify a job in that batch. Invalid or unavailable cursors return 400.

Egocentric endpoint reference

Request and response schemas for batches, jobs and results.