Xity application records API: https://api.xityconnect.org Workspace: https://xityconnect.com/developer/apps Record browser: https://xityconnect.com/developer/records Guide: https://xityconnect.com/developer/reference/app-records JavaScript client: https://xityconnect.com/sdk/xity.mjs APPLICATION CONNECTION Create a Xity Connect application. Create a namespace from that application's workspace. Namespace client_id identifies the OAuth application. Assets linked through space_id must exist and have the same client_id in their app_id field. A reference grants no ownership or asset permissions. OAUTH AND WALLETS OAuth scopes: identity:read, spaces:read, spaces:write, coins:transfer, records:read, records:write. OAuth tokens never sign transactions. POST /v1/wallet-requests takes app_id, tx_type and payload. Open approval_path on Xity Connect, then poll GET /v1/wallet-requests/request_id with the original token. The user reviews and signs there. Requests expire in five minutes. Revoked consent, expired grants and deleted apps cannot continue. Namespace user_records must be enabled to let ordinary users write only inside users/their wallet address/. Namespace owner and delegated writers can write application wide. WRITE TYPES APP_REGISTER: app_id, signer_public_key, visibility (public or private), optional metadata, client_id, user_records. Workspace registration requires a client_id owned by the wallet. A native signed registration can omit client_id for standalone records. Reconnect an owned application before using the linked app workflow. Visibility and user_records are immutable. Metadata supports name, description, url. APP_UPDATE: app_id, signer_public_key, optional metadata, client_id. Only owner. APP_KEYS_UPDATE: app_id, signer_public_key, optional add and remove arrays. Each added key has public_key (raw lowercase Ed25519 hex) and role (writer or reader). Removal uses its key address. Only owner. APP_TRANSFER_OFFER: app_id, signer_public_key, to, expires_at (at most 30 days after transaction time). APP_TRANSFER_ACCEPT: app_id, signer_public_key. Only current unexpired offer recipient. APP_TRANSFER_CANCEL: app_id, signer_public_key. Only owner. APP_SUSPEND, APP_RESUME, APP_QUOTA_SET require sovereign authority. APP_RECORD_PUT: app_id, signer_public_key, key, value, optional expected_version and space_id. Set space_id to null to clear its link. APP_RECORD_DELETE: app_id, signer_public_key, key, optional expected_version. APP_RECORD_BATCH: app_id, signer_public_key, ops. One to 32 distinct keys. Each op has op (put or delete), key, value for put, optional expected_version and space_id for put. The whole batch is atomic. Use expected_version 0 for creation. Read the latest version before an edit or deletion. A tombstone retains its version. Restoring uses the tombstone's version and increments it. Never silently drop CAS protection after a conflict. READ ENDPOINTS GET /v1/apps?owner=address&client_id=client_id&limit=50&after=namespace GET /v1/apps/namespace GET /v1/apps/signers/address/nonce GET /v1/apps/namespace/record?key=record_name GET /v1/apps/namespace/records?prefix=folder/&after=record_name&limit=50&include_deleted=false&include_values=true&space_id=asset_id GET /v1/apps/namespace/record/history?key=record_name&limit=20&before_version=version GET /v1/apps/namespace/record/proof?key=record_name&version=version Public values and public history require no read credential. Private reads require an eligible session, a properly scoped OAuth grant from the linked application, or a signed read with an authorised key. Admin core access is explicit. A service key alone grants no private read permission. Private values are encrypted, but namespace metadata, record names, size, versions, authors and ciphertext remain on the chain. SIGNED READS Headers: X-Xity-App-Key-Id, X-Xity-App-Read-Ts, X-Xity-App-Read-Nonce, X-Xity-App-Read-Sig. Sign xity.app.read.v1, chain ID and canonical body {genesis_hash, endpoint, app_id, params, key_id, ts, nonce}. endpoint is record.get, records.list, record.history or record.proof. params contains the exact query fields as strings, without duplicate names. ts is integer Unix seconds, within 120 seconds. nonce is fresh 16 byte lowercase hex. Each signed request is accepted once. SIGNING Application transactions use domain xity.app.tx.v1. Signing body is {genesis_hash, tx:{tx_type,sender,nonce,timestamp,payload}}. Each payload includes signer_public_key. Canonical JSON sorts fields, uses ASCII escapes and has no extra whitespace. Signing bytes are 2 byte big endian domain length, domain UTF8, 2 byte big endian chain ID length, chain ID UTF8, canonical body UTF8. tx_id is SHA256 of the canonical tx body alone. Existing coin and NFT transactions retain xity.tx.v1 and their original format. POST /v1/transactions/prepare accepts app_id, tx_type, payload with a bearer credential. Review its exact transaction and reconstruct signing bytes locally. POST /v1/transactions/submit accepts app_id and the signed transaction. The owner workspace can use app_id xity-workspace for namespace repair and management. APP_REGISTER uses the owned OAuth client ID instead. POST /v1/app-transactions/submit accepts the transaction object directly for backend keys. It has no bearer token requirement: the signature, current delegation, nonce, chain binding, app connection and consensus rules are still required. Save the built signed transaction before the first submission. A retry sends the same object and signature. SDK buildAppTransaction and submitAppTransaction implement this flow. A signing key shares one chain nonce across its operations. ENCRYPTION Private namespaces require an authenticated version 1 envelope: {v:1,alg:A256GCM or C20P,nonce:base64url 12 bytes,ct:array of base64url chunks,key_id:optional string}. Encoded ciphertext chunks are up to 8192 characters, all except the last exactly 8192. Canonical base64url has no padding. AES GCM and ChaCha20 Poly1305 tags are 16 bytes. Associated data for reference clients is canonical {app_id,key,chain_id,genesis_hash}. Never send a content key to Xity. Back it up and deliver it only to intended readers. Signed read access does not decrypt a value. The browser SDK uses AES 256 GCM. The Python node client also supports ChaCha20 Poly1305. LIMITS Namespace name: 3 to 32 lowercase letters, numbers and single dashes; reserved names and xity prefix are unavailable. Record key: 1 to 128 ASCII characters using letters, digits, underscores, dots, colons, slashes and dashes. No empty folder segments, dot traversal or trailing slash. Public JSON: null, boolean, safe integer, string, list or object. No floats. Maximum depth 8, string length 8192, list length 1000, object fields 256. Field names are printable ASCII, 1 to 128 characters. Default quota per namespace: 10,000 record names including tombstones, 16,384 value bytes, 33,554,432 live value bytes, 536,870,912 lifetime written bytes. Lifetime counters also include record key bytes on every write or delete. Values use canonical JSON byte size. A wallet may own five namespaces. Each namespace supports 32 delegated keys. Chain limits are 10,000 namespaces and 100,000 record names. Sovereign quota ceilings are 100,000 records, 49,152 value bytes, 1,073,741,824 live bytes and 68,719,476,736 lifetime written bytes. HISTORY AND PROOFS Proof export requires block confirmation. Pending versions return version_not_sealed. A proof includes the full signed transaction, operation index, RFC6962 audit path, header, chain binding and optional operator seal. A member cannot export a private batch proof containing records outside their own area. The Python node client verify_proof checks transaction ID, signature, canonical path shape, Merkle root and pinned sealer signature or an independently trusted block hash. Pin chain ID, genesis hash and sealer public key outside the untrusted proof. With expected_version, claimed version is also checked. Without CAS the result is verified_inclusion_only. Inclusion does not establish current access or historical authorisation by itself. Existing unsigned blocks remain valid historical data and require a separately trusted block hash for offline proof trust. FAILURES AND CONFIRMATION app_cas_conflict: fetch latest version, compare and preserve the user's draft. app_nonce_conflict: another action used the signer nonce. Review a fresh transaction after checking the original status. app_suspended: contact the operator. Owner may still revoke keys or cancel an ownership offer. app_quota_*: inspect usage, contact the operator where appropriate. app_space_mismatch: choose an existing NFT from the same application. 401: sign in again or sign a fresh read with an authorised key. 403: the connection, scope or current signer lacks access. 503: storage or confirmation is temporarily unavailable. Retry the same signed transaction after checking its status. A timeout is not proof of failure. GET /v1/transactions/tx_id returns applied while waiting for a block, confirmed after sealing. Do not prepare a replacement payment or write until the original status is known. OWNERSHIP AND REPAIR Acceptance removes all delegated keys. The new owner reconnects an application they own and receives content keys separately. Deleting an OAuth app revokes its tokens and stops linked platform writes. The namespace owner can repair the client_id connection from workspace settings. Relinking does not transfer assets and does not rewrite old references. NODE OPERATORS Empty app state is omitted from checkpoint and root inputs, preserving existing ledgers. New APP state activates a consensus extension. Do not downgrade after the first APP transaction. Back up the live ledger before upgrading. Pin a dedicated block sealer public key for peer ingestion. Use a separate mode 0600 signing key on the authority; do not reuse a governance key. Receiving sealed internal bootstrap transactions also requires the explicit XITY_ACCEPT_SEALED_INTERNAL operator setting. Reserved senders can never authorise APP transactions. Existing governance quorum paths still verify validator signatures. TREASURY SGD funding is not connected. Signed verified settlement integration remains disabled until the operator configures a real provider and attestor. No synthetic deposit counts as treasury backing. Native Xity operations are available. Arbitrary uploaded application code is not executed.