OriginChainDB
SQL

Use the transaction HTTP API

Read records, prepare changes and commit them together on supported instances.

A transaction lets you prepare several row changes before committing them. This preview HTTP API uses a tx_id to keep those operations together.

Use the transaction endpoint lifecycleThese scoped transaction APIs differ from SQL sessions; check their supported operations and isolation limits.
  1. Begin and keep tx_idUse the returned transaction ID for its operations.
  2. Read supported keysStay within the endpoint’s documented read behavior.
  3. Buffer supported writesInspect errors before attempting to finish the transaction.
  4. Commit or roll backVerify the final result; a buffered write is not yet committed.

Choose the interface

Use this page for /v1/tenants/:tenant/tx/*. For SQL statements using a shared session, use SQL transactions instead. They are separate interfaces with different limits.

Before you begin

  • Confirm the instance supports the requested mode in /v1/capabilities.
  • Complete the quickstart, including the product-001 record in quickstart.products.
  • Use the engine connection values expected by this example: OC_BASE_URL, OC_TENANT and OC_BEARER.

Read, change, commit

Python example: increase a sample price by 100 cents
import json
import os
from urllib.request import Request, urlopen

base = os.environ["OC_BASE_URL"].rstrip("/")
tenant = os.environ["OC_TENANT"]
headers = {"Authorization": f"Bearer {os.environ['OC_BEARER']}",
           "Content-Type": "application/json"}

def call(method, path, body=None):
    request = Request(f"{base}/v1/tenants/{tenant}{path}", method=method,
                      headers=headers,
                      data=None if body is None else json.dumps(body).encode())
    with urlopen(request, timeout=30) as response:
        return json.load(response)

opened = call("POST", "/tx/begin?isolation=snapshot_isolation")
tx_id = opened["tx_id"]
print("Transaction:", tx_id, "isolation:", opened["isolation"])
try:
    if opened["isolation"] != "snapshot_isolation":
        raise RuntimeError("Unexpected isolation level")
    current = call("GET", f"/tx/{tx_id}/rows/quickstart.products/product-001")["row"]
    call("POST", f"/tx/{tx_id}/rows/quickstart.products", {
        "id": current["id"], "name": current["name"],
        "price_cents": current["price_cents"] + 100,
    })
except Exception:
    try:
        call("POST", f"/tx/{tx_id}/rollback")
    except Exception:
        pass
    raise

# A lost commit response needs reconciliation, not an unconditional retry.
print(call("POST", f"/tx/{tx_id}/commit"))

Transaction reads return a row wrapper and see their own buffered writes. Other clients see changes after a successful commit.

Know what each mode checks

ModeWhat to expect
snapshot_isolationChecks recorded point reads and conflicting writes at commit. A second read is not guaranteed to match the first.
serializablePreview; requires a supported single-shard configuration. Read the begin receipt's scope.

On supported single-writer instances, serializable validation can cover supported scan predicates. On RaftQuorum, serializable_scope: point_reads_only excludes scan and range reads. A lagging replica does not guarantee the most recent value acknowledged elsewhere.

Read several rows

POST /tx/:id/query takes a supported native scan plan, not SQL text. Unsupported plan leaves are refused. If you found keys outside the transaction, read those keys again inside it before deciding what to change.

SQL sessions have their own buffering and isolation restrictions. Do not use their higher-isolation INSERT support as proof that this HTTP workflow is available on every instance.

Handle failures

OutcomeNext step
Confirmed tx_conflict or serialization_failureStart a fresh transaction, re-read and recalculate. Bound the number of retries.
Lost commit response or timeoutCheck whether the change happened before repeating it.
Constraint or permission errorCorrect the request or permission; repeating it is not a fix.

Buffer and open-transaction limits have their own error codes. serializable_sharded_unsupported and serializable_scan_raft_unsupported mean the requested access pattern is unavailable. HTTP 409 alone is not enough to decide whether to retry.

Keep the transaction small

Keep transactions short, handle expiry and check the final commit. Constraints can fail at commit even when individual buffered writes were accepted. Schema changes use a separate lifecycle. Trigger external side effects only after the transaction's outcome is confirmed.

© 2026 Silicoyn Technologies Pvt Ltd

On this page