Matches in other apps
uw — the drafting page and the scoreboard
mount /uw · base https://zpe.vc/uw · v1.0.0 · 5 operations · 2 write · 0 need no account · beta
archived: committed 2026-11-01, from 69440287. Contract: https://zpe.vc/uw/_/api/v1/openapi.json
GET
/_/api/v1/state
The scoreboard, the published snapshot's job list, and one job's two panes and history.
uwState
One read for the page and for a client: the HTML at /uw/p and this answer are built from the same state, so the two cannot disagree about a number. The drafted body is included, because the client's job is to show it.
Parameters
| name | in | required | type | notes |
|---|---|---|---|---|
job | query | no | string | A job's short ref. Omitted, the newest live proposal answers. |
Request body
None: this operation takes its arguments in the path and the query.
Responses
| status | meaning | body |
|---|---|---|
200 | The read. | object |
401 | No door session, or a session the door would not name. | object |
503 | The door did not answer, or nobody has published a snapshot yet. | object |
Example
The scoreboard, the published snapshot's job list, and one job's two panes and history., with a token from the door.
curl -X GET 'https://zpe.vc/uw/_/api/v1/state?job=string' \ -H 'Authorization: Bearer $ZPE_TOKEN'
{
"ok": false,
"schema": "string",
"published_at": "2026-10-31T09:00:00Z",
"snapshot_id": 0,
"window": {},
"scoreboard": {},
"corpus": {},
"jobs": [
{}
],
"job": null,
"agent": null,
"owner": null,
"history": [
{}
],
"against_agent": null,
"scope": {
"account_id": null,
"organization_id": null,
"organization_name": null,
"role": "string",
"reads": "organisation"
}
}The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.
POST
/_/api/v1/save
Append his version of one job's letter, once per idempotency key.
uwSaveDraft
The only write on this surface. It appends a row and never updates one: a version that can be edited is a version that can be made to agree with whatever happened afterwards. The page's own button posts the same fields as a form and is answered with a 303 back to the pane; a client posting JSON is answered 201 with the row it wrote.
Parameters
| name | in | required | type | notes |
|---|---|---|---|---|
Idempotency-Key | header | no | string | The caller's retry handle. The same key twice replays the first answer and writes nothing. |
Request body application/json · required
| field | type | required | notes |
|---|---|---|---|
job_ref | string | yes | A short ref the snapshot lists. Any other ref is refused. |
body | string | yes | The letter, as plain text. |
note | string | no | What changed and why, in one line. |
idempotency_key | string | no | The same handle as the header, for a client that cannot set one. |
Responses
| status | meaning | body |
|---|---|---|
201 | The version this call appended, and what it changed against the suggestion. | object |
303 | The form's answer: the pane, with the saved version printed under the button. | |
400 | The body names no job this snapshot lists, or carries no letter. | object |
401 | No door session. | object |
Example
Append his version of one job's letter, once per idempotency key., with a token from the door.
curl -X POST 'https://zpe.vc/uw/_/api/v1/save' \
-H 'Authorization: Bearer $ZPE_TOKEN' \
-H 'content-type: application/json' \
-d '{
"job_ref": "string",
"body": "string",
"note": "string",
"idempotency_key": "string"
}'{
"id": "string",
"version": null,
"words": 0,
"at": "2026-10-31T09:00:00Z",
"against_agent": null
}The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.
GET
/_/api/v1/drafts
The drafts this session may read, oldest first.
uwDrafts
The session's own shelf: the organisation the door named and the role it gave decide which rows answer, so a second organisation sees none of the first's. A client reading this sees exactly the versions the page would draw. `make pull` uses the token-only pull at `/_/publish/drafts`, which is scoped to the deployment's own publisher.
Parameters
| name | in | required | type | notes |
|---|---|---|---|---|
job | query | no | string | One job's short ref. Omitted, every job's drafts answer. |
since | query | no | integer | Only rows with an id greater than this, for a pull that keeps its place. |
Request body
None: this operation takes its arguments in the path and the query.
Responses
| status | meaning | body |
|---|---|---|
200 | The rows. | object |
401 | No door session. | object |
Example
The drafts this session may read, oldest first., with a token from the door.
curl -X GET 'https://zpe.vc/uw/_/api/v1/drafts?job=string&since=0' \ -H 'Authorization: Bearer $ZPE_TOKEN'
{
"ok": false,
"drafts": [
{
"id": 0,
"job_ref": "string",
"body": "string",
"words": 0,
"note": null,
"account_id": "string",
"organization_id": null,
"created_at": "2026-10-31T09:00:00Z"
}
]
}The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.
GET
/_/api/v1/send
One send request's state, for the page and for a client polling it.
uwSendRequestState
The row the page writes is the row the page polls. `state` is `pending`, `claimed`, `done` or `refused`, and it is written only by the runner: a client that reads `done` is reading what the machine reported, never a guess made here. A refused row carries the sentence that refused it (`result.reason`) and no preview.
Parameters
| name | in | required | type | notes |
|---|---|---|---|---|
id | query | no | integer | One request's id. Omitted, the newest for `job` answers. |
job | query | no | string | A job's short ref: the newest request for it. |
Request body
None: this operation takes its arguments in the path and the query.
Responses
| status | meaning | body |
|---|---|---|
200 | The request, as the queue holds it. | object |
401 | No door session. | object |
404 | This account wrote no request at that address. | object |
Example
One send request's state, for the page and for a client polling it., with a token from the door.
curl -X GET 'https://zpe.vc/uw/_/api/v1/send?id=0&job=string' \ -H 'Authorization: Bearer $ZPE_TOKEN'
{
"ok": false,
"request": {
"id": 0,
"kind": "prepare",
"state": "pending",
"job_ref": "string",
"requested_by": "string",
"at": "2026-10-31T09:00:00Z",
"claimed_at": null,
"run_by": null,
"rate": null,
"body": null,
"terms": null,
"preview": null,
"result": null,
"prepare_id": null,
"wait_seconds": 0
}
}The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.
POST
/_/api/v1/send
Queue a send request: a prepare (Upwork's preview) or a confirm (the submit).
uwSendRequest
THE WORKER CANNOT SEND, AND THAT IS THE DESIGN. The Upwork credential lives on the machine that owns the ledger, so this route records an INTENTION. A `prepare` asks the machine for Upwork's preview — the exact text, the Connects, and any screening questions — and a `confirm` names the prepare row whose preview the person saw. A runner on the machine claims the oldest pending row, calls Upwork, and writes `done` or `refused` back; the state is asynchronous by construction and is answered within about a minute (`wait_seconds` names the wait). Nothing here submits anything. A confirm carries no letter: the text a person authorised is the preview's, and a body posted with a confirm is refused.
Parameters
No parameters.
Request body application/json · required
| field | type | required | notes |
|---|---|---|---|
kind | "prepare" | "confirm" | yes | |
job_ref | string | yes | A short ref the snapshot lists. |
rate | number | no | The bid, in whole USD. |
body | string | no | The letter. Omitted, the newest version saved here is prepared. |
answers | array of object | no | Screening answers, as Upwork takes them. |
estimated_duration | string | no | How long the work will take. One of the snapshot's `send_terms.durations`; required with `payment_mode`. |
payment_mode | string | no | How it is paid. One of the snapshot's `send_terms.payment_modes`; required with `estimated_duration`. |
milestones | array of object | no | For the milestone payment mode: `{description, amount, due_date?}` rows whose amounts add up to the bid. |
prepare_id | integer | no | The prepare row this confirm belongs to. Required for `confirm`. |
Responses
| status | meaning | body |
|---|---|---|
201 | Queued. The row's id, its state (`pending`), and the wait the page prints. | object |
303 | The page's own form answer: the pane, with this request's state drawn under it. | |
400 | The ref is not in the published snapshot, the rate is missing, half a fixed-price pair is named, there is no letter, or a confirm carries a body. | object |
401 | No door session. | object |
Example
Queue a send request: a prepare (Upwork's preview) or a confirm (the submit)., with a token from the door.
curl -X POST 'https://zpe.vc/uw/_/api/v1/send' \
-H 'Authorization: Bearer $ZPE_TOKEN' \
-H 'content-type: application/json' \
-d '{
"kind": "prepare",
"job_ref": "string",
"rate": 0,
"body": "string",
"answers": [
{}
],
"estimated_duration": "string",
"payment_mode": "string",
"milestones": [
{}
],
"prepare_id": 0
}'{
"ok": false,
"id": 0,
"kind": "prepare",
"state": "pending",
"job_ref": "string",
"wait_seconds": 0
}The example is generated from the schema in the contract: the shape is the document's, the values are placeholders.