POST /api/piston/sources
Register a source
Registers a source of the team by its digest: a tar.zst of the files that the tasks find in their working directory. Make it from the files, and send its SHA-256 digest and size. If upload_url isn't null, PUT the tar.zst's bytes to it, with no Motor credential, before upload_expires_at; then start a run with the source's id. If upload_url is null, Piston has the source already. Registering the same digest again is safe, and gives a new upload_url until the upload is done. Needs piston:run for an agent, and a team that can pay.
| Body field | Type | Description |
|---|---|---|
sha256required | string | The SHA-256 digest of the tar.zst, in lowercase hex. |
sizerequired | integer | The size of the tar.zst, in bytes. |
repo | string | Where the files came from, such as |
team_id | string | The team's ID. An agent token acts in its own team if you don't say; a session key or a user key must say. |
{
"repo": "motor/aragorn",
"sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"size": 1843200,
"team_id": "team_1BbA6sXxyUWHYvKqN5T3dM"
}
Responses
200The source, and where to upload it.
| Field | Type | Description |
|---|---|---|
source | object | |
upload_expires_at | string or null | When |
upload_url | string or null | The URL to |
{
"source": {
"created_at": "2026-10-22T09:00:00.000Z",
"id": "src_1BbA6sXxyUWHYvKqN5T3dM",
"repo": "motor/aragorn",
"sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
"size": 1843200,
"uploaded": false
},
"upload_expires_at": "2026-10-22T09:15:00.000Z",
"upload_url": "https://piston-data.s3.amazonaws.com/teams/team_1BbA6sXxyUWHYvKqN5T3dM/sources/9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08.tar.zst?X-Amz-Signature=…"
}
401The credential is missing, unknown, revoked, or expired, or a bound session key has no valid DPoP proof.
{
"error": {
"code": "unauthorized",
"message": "The credential is unknown, revoked, or expired.",
"retryable": false
}
}
402The team can't pay for new work: `billing_required` (the team needs a card: an admin adds one in the console) or `over_limit` (the team or the agent spent its spending limit for the month: an admin raises the team's limit, or the person or agent that started the agent starts one with a higher limit). Retrying doesn't help until that changes.
{
"error": {
"code": "over_limit",
"message": "The team spent its spending limit for this month, so Piston doesn't start new work for it. An admin raises the limit at https://new.motor.dev/console, or the work waits until next month.",
"retryable": false
}
}
403The credential can't do this: `insufficient_scope` (the agent needs the scope that the message names: ask for an agent with it), `forbidden`, or `team_suspended`.
{
"error": {
"code": "insufficient_scope",
"message": "The agent's scopes don't include piston:run.",
"retryable": false
}
}
404There is no such resource in the team, or the credential can't see it. Check the ID, and `team_id`.
{
"error": {
"code": "not_found",
"message": "There is no run run_1BbA6sXxyUWHYvKqN5T3dM in the team.",
"retryable": false
}
}
409The state of things doesn't allow the request, such as a run of a source that isn't uploaded yet: the message says what to do. `idempotency_conflict`: the Idempotency-Key was used with another request; use a new key. `request_in_progress`: the first request with the key hasn't ended; retry after `retry_after_seconds`.
{
"error": {
"code": "conflict",
"message": "The source src_1BbA6sXxyUWHYvKqN5T3dM isn't uploaded yet: PUT it to its upload_url first.",
"retryable": false
}
}
422A field or a parameter has a value that Motor or Piston can't accept: `field` names it, and the message says what to send.
{
"error": {
"code": "invalid_field",
"field": "sha256",
"message": "`sha256` must be the SHA-256 digest of the source's tar.zst, as 64 lowercase hex digits.",
"retryable": false
}
}
429The credential made more than 600 requests in a minute, or Piston is at its capacity. Wait `retry_after_seconds`, and retry.
{
"error": {
"code": "rate_limited",
"message": "Too many requests: the limit is 600 a minute.",
"retry_after_seconds": 12,
"retryable": true
}
}
503Piston can't answer now (`temporarily_unavailable`): wait `retry_after_seconds`, and retry the same request, with the same Idempotency-Key. `unavailable`: this Motor isn't set up to call Piston.
{
"error": {
"code": "temporarily_unavailable",
"message": "Piston can't answer now. Try again in a moment.",
"retry_after_seconds": 1,
"retryable": true
}
}