API
API quickstart
Create a billing account over HTTP, then register a storage key with the SDK.
This is the HTTP API. For the supported CLI, use the CLI quickstart.
Create an account
POST /api/v1/agents needs an X-Altcha solution. Fetch GET /api/v1/auth/altcha-challenge, find the decimal n from 0 through maxnumber where sha256(salt + n) equals challenge, and send the base64 of that JSON. The CLI is not required.
ALTCHA=$(python3 - <<'PY'
import base64, hashlib, json, urllib.request
with urllib.request.urlopen("https://tessera.storage/api/v1/auth/altcha-challenge") as res:
challenge = json.load(res)
number = None
for n in range(challenge["maxnumber"] + 1):
digest = hashlib.sha256(f"{challenge['salt']}{n}".encode()).hexdigest()
if digest == challenge["challenge"].lower():
number = n
break
if number is None:
raise SystemExit("no solution")
payload = json.dumps({
"algorithm": challenge["algorithm"],
"challenge": challenge["challenge"],
"number": number,
"salt": challenge["salt"],
"signature": challenge["signature"],
}, separators=(",", ":")).encode()
print(base64.b64encode(payload).decode())
PY
)
curl -fsS -X POST https://tessera.storage/api/v1/agents \
-H 'content-type: application/json' \
-H "X-Altcha: $ALTCHA" \
-d '{"name":"build-box"}'
{ "account_id": "…", "api_key": "tsk_…_…" }
That call creates the billing account. The API key is shown once. Send it as Authorization: Bearer.
Storage credential
curl -fsS -X POST https://tessera.storage/api/v1/credentials \
-H 'authorization: Bearer tsk_…' \
-H 'content-type: application/json' \
-d '{}'
The response includes a one-time connect_key. A second identity returns 409 identity_exists.
Register that key with the indexer. This is go.sia.tech/siastorage v0.2.1 (context, fmt, net/http, strings). The billing API does not return the storage private key.
appID := siastorage.GenerateAppID() // keep it; it identifies this app
builder := siastorage.NewBuilder("https://index.tessera.storage", siastorage.AppMetadata{
ID: appID,
Name: "build-box",
})
responseURL, err := builder.RequestConnection(ctx)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, responseURL, strings.NewReader(`{"approve":true}`))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth("", connectKey) // username empty, password is the connect key
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return fmt.Errorf("approve connection: HTTP %d", resp.StatusCode)
}
if err := builder.WaitForApproval(ctx); err != nil {
return err
}
phrase := siastorage.NewSeedPhrase() // save these 12 words
sdk, err := builder.Register(ctx, phrase)
if err != nil {
return err
}
appKey := sdk.AppKey() // save it; Tessera does not
sdk.Close()
Then link the identity:
curl -fsS -X POST https://tessera.storage/api/v1/credentials/activate \
-H 'authorization: Bearer tsk_…'
Storage requests are signed per call at https://index.tessera.storage with that app key. See
Authentication. Billing calls stay on https://tessera.storage/api/v1 with
the bearer key. Prices are on Pricing. Adding funds from the CLI is
Wallet and top-ups.