API reference

Placement

POST /prepare-write — get the providers, contracts, and access tokens for writing a slab's shards.

prepare-write is the first call of every upload. It returns a set of providers with funded contracts and an access token for each, ready to receive shards.

POST /prepare-write

curl -X POST "$TESSERA_API/prepare-write?$AUTH" \
  -H 'content-type: application/json' \
  -d '{"totalShards": 15, "minShards": 10}'

Request body

FieldTypeDefaultDescription
totalShardsinteger15How many providers you want, one shard each.
minShardsinteger10How many shards must survive to reconstruct.

Both fields may be omitted; the defaults are the 10-of-15 geometry.

Response200 OK

{
  "hosts": [
    {
      "publicKey": "ed25519:9f3c1a4b...",
      "address": "provider-1.example:9984",
      "accountToken": "{\"hostKey\":\"ed25519:9f3c1a4b…\",\"account\":\"\",\"validUntil\":1775212800,\"signature\":\"\"}",
      "contractID": "a1b2c3d4..."
    }
  ]
}
FieldDescription
publicKeyThe provider's identity. ed25519: followed by 64 hex characters. Record this in the slab's sectors[].host.
addressNetwork address to connect to, host:port.
accountTokenAn opaque, time-limited authorisation for your writes to this provider. Pass it to the transfer protocol unmodified.
contractIDThe storage contract the shard is written under. Record this in sectors[].contractID.

The response contains exactly totalShards entries, each a different provider. Provider uniqueness within a slab is enforced here and again when the slab is registered, so a slab can never end up with two shards in one place.

Geometry constraints

totalShards / minShards is the redundancy factor, and it is validated:

RuleValue
Minimum redundancy1.5×
Maximum redundancy4.0×
minShardsmust be ≤ totalShards
GeometryRedundancyToleratesAccepted
10-of-151.5×5 lossesyes — the default
10-of-202.0×10 lossesyes
6-of-122.0×6 lossesyes
10-of-141.4×4 lossesno — below 1.5×
4-of-205.0×16 lossesno — above 4.0×

Why there is a maximum

The lower bound protects durability. The upper bound exists because past a point you are paying for storage that buys almost nothing: going from 1.5× to 4.0× multiplies your cost by 2.7 for a reduction in an already-small failure probability. If you have a workload that genuinely justifies more, the answer is a second independent copy, not a wider stripe.

Choosing a geometry

Widen totalShards while holding minShards if you want more failure tolerance for the same reconstruction threshold. Widening minShards too makes each shard smaller and each read touch more providers, which usually costs you latency for no durability gain.

The default is the right answer for almost everything. Deviate when you can state why.

Errors

StatusBodyCause
400{"error": "invalid request body: ..."}Malformed JSON.
400{"error": "minShards must be <= totalShards"}Self-explanatory.
400{"error": "redundancy 1.400 < 1.5"}Below the redundancy floor.
401plain textSignature or credential problem.
402{"error": "storage cap exceeded", "capBytes": …, "incomingBytes": …}The write would exceed your storage cap.
405method not allowedNot a POST.
503{"error": "no contracted hosts available"}No provider pool currently available. Retry with backoff.
503{"error": "contracts manager not configured"}Placement is unavailable on this deployment.
503{"error": "no hosts with valid tokens available"}Providers were found but tokens could not be derived. Retry.

`503` is transient — treat it as such

Provider availability fluctuates. A 503 from this endpoint means try again shortly, not that your request was wrong. Use exponential backoff with jitter, and do not fail a user-facing upload on the first one.

Provider failures mid-upload

Some shard writes will fail. This is normal, not exceptional, and your client should treat it as a routine branch rather than an error path:

  1. Attempt the write to the assigned provider.
  2. On failure, do not retry indefinitely — call prepare-write again and take a provider you have not used in this slab.
  3. Place the shard there and continue.
  4. Register the slab once you have totalShards successful placements.

Which specific providers hold your shards does not matter. That there are totalShards of them, all distinct, does.

Token lifetime

accountToken is time-limited. For a long upload, request placement in batches close to when you will use it rather than fetching all tokens up front and working through them slowly. If a token expires mid-upload, re-request placement for the remaining shards.

GET /hosts

Lists providers currently considered good for upload. Informational — prepare-write already selects for you, and does it better, because it also accounts for contract state and fill level.

curl "$TESSERA_API/hosts?$AUTH"
[
  {
    "publicKey": "ed25519:9f3c1a4b...",
    "addresses": ["provider-1.example:9984"],
    "countryCode": "",
    "latitude": 0,
    "longitude": 0,
    "goodForUpload": true
  }
]

Always an array, never null.

Geography fields are not populated

countryCode, latitude, and longitude are present in the response shape but are currently returned empty or zero — geo-location of providers is not yet wired up. Do not build jurisdiction logic on these fields. If you need jurisdiction constraints, that is an Enterprise configuration applied at selection time.