Skip to Content

Organization works

With POST /v1/works you send a description of a work (a spec). UpServe creates a new team in your organization (a team lead and one Assigned AI), then specializes that team for the work: it assembles a setup, tests it, and publishes it to the team. You follow this through a preparation until it is ready.

  • The result is a team in your organization’s UpServe screens, not a Deployment. This API does not yet hand work to that team.
  • Only organization Projects can use these paths. A Project in a personal space gets 404 NOT_FOUND on every work path.
  • As with every /v1 path, only approved Projects can call these during the Private Beta. When we approve a Project for works we also enable specialized setups for its organization. If a preparation ends with RECIPE_ACCESS_DENIED, ask us.

Before you start

scopeAllowed operations
works:readRead and list preparations
works:writeSubmit a work or a revised spec, and answer questions
works:approveAnswer a scope confirmation on behalf of a person in your service (explicit delegation, chosen per key)
  • A key with at least one works scope and nothing else but usage:read can be created without any Deployment. A key that mixes in any other scope still needs at least one Deployment.
  • The team’s manager is the OWNER who created the key. If that person stops being an OWNER, the key stops working.
  • Question texts in a preparation follow the manager’s language: Korean for a Korean user, otherwise English.
  • Preparation costs are paid like executions and count toward the Project’s daily and monthly spend limits. The team is created with autonomous wake-ups off, so it does not spend on its own.
  • With usage:read, GET /v1/usage reports preparation costs in preparations, apart from execution costs. See usage.

Flow

  1. Submit the work with POST /v1/works. (works:write, Idempotency-Key required)
  2. Read GET /v1/preparations/{preparation_id} until the status is final. (works:read)
  3. If the status is NEEDS_INPUT, answer the questions with POST /v1/preparations/{preparation_id}/answers.
  4. The work is ready when the status is SUCCEEDED and team_id is set.
curl -s -X POST "$BASE/v1/works" \ -H "Authorization: Bearer $UPSERVE_API_KEY" \ -H "Idempotency-Key: work-0001" \ -H "Content-Type: application/json" \ -d @work.json
{ "spec": { "purpose": "Turn each incoming quote request into a quote from the approved catalog.", "success_criteria": ["Every request line has a source or a question for a person."], "sources": [{"ref": "synthetic:catalog", "revision": "1"}], "allowed_actions": ["READ_APPROVED_CATALOG", "CREATE_QUOTE"], "delivery": {"channel": "EMAIL", "target_ref": "synthetic:approved-operator"} } }

The response is 202 with a Location: /v1/preparations/{preparation_id} header and the preparation itself.

{ "kind": "PREPARATION_VIEW", "contract_version": 1, "preparation_kind": "SPECIALIZE", "work_id": "22222222-2222-4222-8222-222222222222", "revision": 1, "preparation_id": "33333333-3333-4333-8333-333333333333", "preparation_revision": 2, "owner": {"kind": "ORGANIZATION", "id": "11111111-1111-4111-8111-111111111111"}, "status": "QUEUED", "stage": "CREATE", "support": "SUPPORTED", "reason_codes": [], "missing_fields": [], "questions": [], "next_actions": [], "retryable": false, "spec": {"purpose": "Turn each incoming quote request into a quote from the approved catalog."}, "usage": {"status": "PENDING", "cost_su": null} }
  • 202 and QUEUED mean accepted, not ready. Keep reading the preparation.
  • There are no webhooks or SSE events for preparations. Poll at a modest interval, for example every 10 to 30 seconds.
  • The full response schema is WorkPreparationPreparationView in the OpenAPI file.

The request body

FieldDescription
specThe work description. Only spec.purpose is required. Other fields (success criteria, inputs and outputs, examples, sources, connections, allowed actions, triggers, delivery, human decisions, facts, assumptions) make the result better.
work_id, expected_revisionOnly to revise a work this Project created. Send both or neither.
  • Unknown fields are rejected with 422 INVALID_INPUT. Do not send an owner, a support profile, or a recipe. The owner is always the key’s organization, and UpServe chooses the setup.
  • connections are reference names only. Never put credentials in a spec.
  • A spec that breaks a rule is 422 INVALID_SPEC with the field or rule in details.reason.

Preparation status

statusMeaning
NEEDS_INPUTSomething is missing. Answer questions.
READYThe spec is complete. It is queued right away.
QUEUED, RUNNINGAccepted and in progress. stage shows the step: CREATE, ASSEMBLE, VALIDATE, BIND, PUBLISH.
REQUIRES_ACTIONA person must confirm a wider scope (see below).
CANCEL_REQUESTEDClosing, for example after a scope confirmation was declined.
SUCCEEDEDReady. team_id is the team.
FAILEDEnded. The reason is in reason_codes.
CANCELEDEnded without publishing.
  • next_actions lists what can happen next at the time you read it. It is not a permission. Every request is checked again.
  • Organization preparations have no retry or cancel path, so next_actions never contains RETRY or CANCEL.
  • unsupported_actions lists the allowed_actions UpServe cannot do when the work is not supported.

Answering questions

{ "expected_preparation_revision": 1, "answers": [{"question_id": "delivery-target", "value": "synthetic:approved-recipient"}] }
  • expected_preparation_revision is the preparation_revision you read. If the preparation changed since, the answer is 409 REVISION_CONFLICT. Read again and answer the current questions.
  • Up to 20 answers go in one request. They are applied together or not at all.
  • An answer to a question that is not open is 409 QUESTION_NOT_FOUND. An answer to a preparation that no longer takes answers is 409 INVALID_TRANSITION.
  • The response is 200 with the updated preparation. When the spec becomes complete it is queued in the same request.

Scope confirmation

A scope confirmation appears only when you revise a work that is already published and the new setup can do more than the current one (new tools, new external actions, or higher cost). The first publication of a new work does not ask. The preparation is then REQUIRES_ACTION with one question Q_SCOPE_EXPANSION that carries changes and package_hash, and next_actions is CONFIRM_SCOPE.

Show the changes to a person in your service and send their decision.

{ "expected_preparation_revision": 7, "answers": [{"question_id": "Q_SCOPE_EXPANSION", "value": {"decision": "APPLY", "package_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}}], "actor": {"subject": "customer-user-42"} }
  • The key needs works:write and works:approve. Without works:approve the answer is 403 ACTION_NOT_RESOLVABLE_BY_CALLER.
  • Send it as the only answer, with actor.subject (an opaque id of the person your service confirmed) and the package_hash from the question. Otherwise it is 422 INVALID_INPUT.
  • APPLY resumes the same preparation (QUEUED, step PUBLISH). KEEP keeps the current setup and closes the preparation.
  • If the candidate changed after the person saw it, the answer is 409 PACKAGE_CHANGED. Show the new question again. After the 7 day deadline the answer is 409 INVALID_TRANSITION.
  • UpServe records the decision subject apart from the key. It is not returned in responses.

Listing preparations

GET /v1/preparations returns this Project’s preparations, newest first, as items and next_cursor. (works:read)

  • limit is 1 to 100 (default 20). Pass the previous next_cursor as cursor for the next page.
  • work_id narrows the list to one work.
  • Preparations of another Project are never listed, even within the same organization.

Revising a work

Send POST /v1/works again with work_id and the expected_revision you read, together with the new spec.

  • Only works this Project created can be revised. Any other work_id is 404 NOT_FOUND.
  • If the work changed since you read it, the answer is 409 REVISION_CONFLICT.
  • An open preparation that is still NEEDS_INPUT or READY is replaced. If one is already QUEUED or later, the answer is 409 PREPARATION_IN_PROGRESS with details.preparation_id. Wait for it to finish.

Idempotency and limits

  • Every write needs an Idempotency-Key. Resending the same key with the same body returns the same response. The same key with a different body is 409 IDEMPOTENCY_CONFLICT.
  • Keys are scoped to the Project. Another Project of the same organization can use the same key value without collision.
  • Writes count against the acceptance rate limit, like Turn and Run submissions. Reads count against the read limit. See limits and data.

When a preparation fails

A preparation that ends as FAILED is not retried. Fix the cause, then send the work again with a new Idempotency-Key, or revise it with work_id.

reason_codesMeaningWhat to do
PROJECT_BUDGET_EXCEEDEDThe Project’s daily or monthly spend limit was reached. It stops before any team is created.Send again after the limit window, or ask for a higher limit.
AUTHORIZATION_REVOKEDThe key was revoked, or the person who created it is no longer an organization OWNER.Send again with a valid key.
TEAM_CREATE_REFUSEDThe team or its Assigned AI could not be created, for example because the organization reached its Assigned AI limit.Fix it in the organization’s UpServe screens, then send again.
RECIPE_ACCESS_DENIEDSpecialized setups are not enabled for the organization.Ask us to enable it, then send again.

A spec UpServe cannot support ends with support UNSUPPORTED, and unsupported_actions shows which actions. HTTP errors on these paths are in errors and retries.