# UpServe Agent Runtime API > Server-to-server REST API that runs an organization's published AI employees (Deployments) and published workflows, then returns status, events, and JSON, file, and URL results. Private Beta: only approved Projects can call it; every other Project gets 404 on every path. It is not OpenAI compatible. This file is a short entry point for AI tools. The contract source is the OpenAPI file. When this file and the OpenAPI file differ, the OpenAPI file wins. - Base URL: https://api.upserve.app/v1 - Auth: `Authorization: Bearer up_...` (API key of one Project, kept on a server only) - Contract: https://docs.upserve.app/runtime-api/openapi.json - A key cannot create Projects, publish Deployments, issue keys, or register webhooks. A person with organization OWNER permission does that in the web app (Settings > Developer). ## Core loop: run an AI employee 1. `GET /v1/deployments`: list the Deployments this key may call. 2. `POST /v1/deployments/{deployment_id}/sessions` with header `Idempotency-Key` and body `{"input":[{"type":"TEXT","text":"..."}]}`: creates a Session and its first Turn. Answers 202 with `session_id`, `turn_id`, `status_url`, `events_url`. 3. `GET /v1/sessions/{session_id}/turns/{turn_id}`: poll until `status` is terminal (`SUCCEEDED`, `FAILED`, `CANCELED`, `EXPIRED`). Results are in `outputs`, the failure reason in `error.code`. 4. Follow-up input in the same conversation: `POST /v1/sessions/{session_id}/turns` with a new `Idempotency-Key`. One Turn runs at a time per Session (`409 SESSION_BUSY` otherwise). 5. Stop: `POST /v1/sessions/{session_id}/turns/{turn_id}/cancel` with `Idempotency-Key`. ## Core loop: run a published workflow 1. `GET /v1/workflows/{workflow_id}`: read `published_version`, `input_schema`, and `available`. When the workflow cannot take a Run, this still answers 200, with `available: false` and the reason in `error.code` (for example `WORKFLOW_UNAVAILABLE`). Do not start a Run then. 2. Optional input file: `POST /v1/files` (multipart, `Idempotency-Key`) returns a `file_id`. It expires 24 hours after upload unless used as input. 3. `POST /v1/workflows/{workflow_id}/runs` with `Idempotency-Key` and body `{"published_version":3,"input":{...},"file_ids":[...]}`: answers 202 with `run_id`. `409 WORKFLOW_UNAVAILABLE` means the workflow is unpublished, stopped, or cannot start through the API. 4. `GET /v1/runs/{run_id}`: poll status and progress. A finished step is not a finished Run. 5. After the Run ends: `GET /v1/runs/{run_id}/outputs` (follow `next_cursor`). 6. FILE output: `POST /v1/artifacts/{artifact_id}/download` issues a 60 second URL. Download right away. 7. Stop: `POST /v1/runs/{run_id}/cancel` with `Idempotency-Key`. Instead of polling you may stream `GET /v1/sessions/{session_id}/events` or `GET /v1/runs/{run_id}/events` (SSE, resume with `Last-Event-ID`), or receive a signed webhook and then re-read the state. ## Core loop: build an organization work Needs a key with `works:` scopes (a key whose scopes are works scopes plus at most `usage:read` needs no Deployment). `GET /v1/usage` reports preparation spend in `preparations`. Only organization Projects; a personal space Project gets 404. 1. `POST /v1/works` with header `Idempotency-Key` and body `{"spec":{"purpose":"..."}}`: UpServe creates an organization team and specializes it. Answers 202 with the preparation and `Location`. 2. `GET /v1/preparations/{preparation_id}`: poll until `status` is final (`SUCCEEDED` with `team_id`, `FAILED`, `CANCELED`). 202 and `QUEUED` mean accepted, not ready. There are no webhooks for preparations. 3. `NEEDS_INPUT`: relay a person's answers with `POST /v1/preparations/{preparation_id}/answers` and `expected_preparation_revision`. 4. `REQUIRES_ACTION` with `CONFIRM_SCOPE`: a person must decide. Send the decision only with `works:approve`, `actor.subject`, and the question's `package_hash`. Never decide for the person. 5. `FAILED` is not retried: read `reason_codes`, fix the cause, then send again with a new `Idempotency-Key`. List with `GET /v1/preparations`. ## Rules that prevent duplicate work and cost - Unanswered request (timeout, dropped connection, `retryable: true`): resend the same body with the same `Idempotency-Key`. The same receipt comes back and nothing runs twice. Honor `Retry-After`. - Never resend an unanswered request under a new key. The work can run twice. - Finished execution (`FAILED`, `CANCELED`, `EXPIRED`): it does not come back. A new attempt is a new Turn or Run with a new key and costs again. Decide by `error.code` using the table "What to do after a failed execution" on the errors page. - `EXTERNAL_EFFECT_UNKNOWN`: do not run again before a person checks the external system. - Result rule failures (`OUTPUT_URL_INVALID`, `OUTPUT_CONTAINS_CREDENTIALS`, `INVALID_FILENAME`, `UNSUPPORTED_FILE_TYPE` as a Turn or Run `error.code`): a result the AI employee made broke a public result rule and the execution ended there. Check that your input did not ask for an internal address, a credential, or a disallowed file type or name, then try at most once more with corrected input. If the same code comes back, tell the publisher. - Publisher-side failures (`OUTPUT_SCHEMA_MISMATCH`, `OUTPUT_LIMIT_EXCEEDED`, `OUTPUT_MISSING`, `OUTPUT_PATH_DENIED`, `CAPABILITY_DENIED`, `WORKFLOW_UNAVAILABLE` as a Turn or Run `error.code`): do not repeat the same input. Tell the person who published the Deployment or workflow. A Run whose workflow was stopped mid-run ends `CANCELED` with `WORKFLOW_UNAVAILABLE`. - Some of these codes also come as an HTTP 4xx answer to your own request: `INVALID_FILENAME` on upload, `UNSUPPORTED_FILE_TYPE` on upload or Turn input, `OUTPUT_SCHEMA_MISMATCH` and `OUTPUT_LIMIT_EXCEEDED` when Run `input` breaks `input_schema` or JSON limits, `409 WORKFLOW_UNAVAILABLE` on Run creation. Then fix that request (or wait until the workflow is published again); nothing ran. - `retryable: false`: the same request gives the same result. Fix the request or stop. - Unknown error code: do not run again. Stop and tell a person. - Ask a person before spending decisions (raising budgets, topping up SU) and before running again after a costly failure. ## Not available through this API now - Creating or editing AI employees, workflows, schedules, keys, or webhooks. The one exception is building a new organization team from a work description (`POST /v1/works` above). - Answering a question or approval in the middle of an execution (RequiredAction). Its contract is documented in advance but it is not offered in the current Private Beta. A workflow with approval steps is rejected with 422 before acceptance, and one that comes to need a human answer during execution ends with `ACTION_REQUIRED_UNSUPPORTED`. ## Reference pages - Overview: https://docs.upserve.app/en/developers (Korean: https://docs.upserve.app/ko/developers) - Quickstart: https://docs.upserve.app/en/developers/quickstart - Authentication and keys: https://docs.upserve.app/en/developers/authentication - Sessions and Turns: https://docs.upserve.app/en/developers/sessions-and-turns - Workflows and Runs: https://docs.upserve.app/en/developers/workflows-and-runs - Organization works: https://docs.upserve.app/en/developers/works - Events and SSE: https://docs.upserve.app/en/developers/events - Webhooks: https://docs.upserve.app/en/developers/webhooks - Errors and retries: https://docs.upserve.app/en/developers/errors - Limits and data: https://docs.upserve.app/en/developers/limits-and-data - Versioning and changelog: https://docs.upserve.app/en/developers/changelog - Client examples: https://docs.upserve.app/runtime-api/examples/runtime_client.py, https://docs.upserve.app/runtime-api/examples/runtime_client.ts