Skip to content
P
Personal workspaceYour services, together
WorkspaceDocumentation

DEVELOPER GUIDE

Durable Objects

Build persistent application state with JSON, SQLite, and small files.

Try your first object in the dashboard

  1. Create a namespace: one application’s objects, API keys, and lifetime spending cap.
  2. Open Objects & playground. Give the object a name, choose Save JSON, and run the command. Your first write creates the object. Wait for its confirmed result and charge.
  3. Choose Next: read saved value, then run Read JSON with the same object name and state key.
  4. Use Activity to see the latest 50 requests from the dashboard and your app. Processing requests show reserved credit; completed requests show their final charge. This history survives a page reload.
  5. Open Connect your app when you are ready for an API key and a connection example. The playground itself uses your signed-in account.

Results and command details expire after one hour. Older records still show the object, time, completion state, and charge. An expired result marked “Completed” does not tell you whether the command succeeded.

Open Durable Objects

Connect your application

  1. Open Durable Objects and sign in with your wallet.
  2. Add prepaid USDC credit, review the rates, and create a namespace with a total spending cap.
  3. Create a namespace API key. Save the secret when it appears; it is shown once.
  4. Send a command and poll its operation until it completes.
# Create a namespace and API key in the dashboard first.
export PIPE_DURABLE_KEY='your-namespace-api-key'
export PIPE_NAMESPACE='your-namespace-uuid'
export PIPE_REQUEST_ID="$(uuidgen)"

curl --fail-with-body \
  "https://api.pipedev.network/control-api/v1/durable/namespaces/$PIPE_NAMESPACE/execute" \
  -H "Authorization: Bearer $PIPE_DURABLE_KEY" \
  -H "Idempotency-Key: $PIPE_REQUEST_ID" \
  -H 'Content-Type: application/json' \
  -d '{"object":"room:general","action":{"op":"put_state","key":"profile","value":{"members":3}}}'

# Use operation_id from the response. Poll until status is complete.
curl --fail-with-body \
  "https://api.pipedev.network/control-api/v1/durable/requests/OPERATION_UUID" \
  -H "Authorization: Bearer $PIPE_DURABLE_KEY"

Keep keys on your application server. A key authorizes only its namespace and expires after 90 days. Revoke it from the dashboard. Read-only keys support JSON and file reads; SQL requires write permission.

Commands

Every request body contains an object name and an action. The first write creates the object. Names remain stable within the namespace.

ActionFields
put_statekey, value (any JSON)
get_state / delete_statekey
list_state / list_blobsOptional prefix and after; returns up to 100 keys and a cursor
sqlstatements: [{ sql, params? }]
migrateversion (next integer), statements: [SQL strings]
put_blobkey, data_base64
get_blob / delete_blobkey
delete_objectNo additional fields; removes access to this object

A SQL batch runs in one transaction. A failed statement rolls back the whole batch. Parameterize values with ? and params.

{
  "object": "counter",
  "action": {
    "op": "sql",
    "statements": [
      {
        "sql": "CREATE TABLE IF NOT EXISTS counter (id INTEGER PRIMARY KEY, value INTEGER NOT NULL)"
      },
      {
        "sql": "INSERT INTO counter VALUES (1, 1) ON CONFLICT(id) DO UPDATE SET value=value+1"
      },
      {
        "sql": "SELECT value FROM counter WHERE id=?",
        "params": [
          1
        ]
      }
    ]
  }
}

Successful polling returns status: complete, the exact charge_atoms, and response. Check response.status: 200 means the command succeeded; 400 means it was rejected and its changes rolled back. JSON reads of absent keys return found: false.

Credit and spending limits

The initial price is 1 USDC per million accepted requests plus 5 USDC per decimal TB of replicated checkpoint writes. One USDC equals 1,000,000 atoms. Each command, including a read or rejected SQL command, saves a receipt and checkpoint. Checkpoint charges use the full database image and publication metadata, rounded up to an atom per request. Replication is included. Object deletion has no request or checkpoint charge.

A small amount of credit is reserved before dispatch and unused credit is released on durable confirmation. Reusing the same request ID and body does not create another charge. A lost response retains its reservation until the server can determine the result. Shared credit cannot be spent simultaneously by another service.

Your total spending cap is cumulative, not a monthly allowance. Raise it explicitly to authorize additional use. Creating a namespace and managing keys has no fee; a namespace requires enough credit for an initial request reservation. There is no subscription or automatic top-up.

Retries and recovery

Generate a unique Idempotency-Key for each new command. After a timeout, retry the exact body with the same key. A different body with that key returns 409. Polling a request never executes it again. Only one request per object can be pending; other objects can proceed.

Do not submit a new ID to “retry” a counter increment. The receipt and application mutation commit together. Recovery can take several minutes after an interrupted storage connection. A completed response is retained for one hour; afterward its compact receipt still prevents that key from executing again and polling reports response_expired: true.

The browser console saves pending request details in this tab so navigation or a reload can recover them. Signing out clears those local details. Application clients should store their request ID and body until confirmation.

Initial limits

  • Four namespaces per customer; 100 active objects per namespace.
  • 16 MiB per object including internal metadata; up to 64 KiB per request and result. Base64 file data must fit within the request limit.
  • 60 commands per minute per namespace. SQL has a five-second execution limit.
  • 10 GiB of retained checkpoint allocation per namespace, with an additional shared service capacity limit.
  • Older checkpoints and immutable versions are retained for recovery. Deleting an object or disabling a namespace does not reclaim that allocation. Failed dispatch attempts retain a conservative allocation to cover uncertain writes.

A full checkpoint quota stops new work. Inspect allocation in the dashboard before planning sustained write-heavy workloads. Namespace disable revokes keys and stops new access; already accepted work still finishes. Deleting an object is permanent for its current identity; using its name again creates a new object.

Durable Objects provides storage primitives. Application classes, WebSockets, alarms, and hosted application-code execution are not part of this service. This customer API uses namespace keys; the older operator SDK endpoints remain separate.

Open Durable Objects