# Arke API Operations Reference ## Base URL - https://arke-v1.arke.institute (Production) ## Authentication **JWT Bearer Token** (bearerAuth) - Header: `Authorization: Bearer ` - Supabase JWT token **API Key** (apiKeyAuth) - Header: `Authorization: ApiKey ` - API Key authentication. Format: `ApiKey ak_xxx` (agent) or `ApiKey uk_xxx` (user) ## Global Headers **X-Arke-Network** (main | test), default: main Target network. Use `test` for isolated test data with II-prefixed IDs. **X-On-Behalf-Of** (string) User entity ID for service accounts acting on behalf of a user. Only valid with `role: service` authentication. ## Auth Levels - `[required]` - Must be authenticated with registered user - `[optional]` - Can be authenticated or anonymous - `[jwt-only]` - Valid JWT required but user may not be registered - (no tag) - No authentication needed Required fields in request bodies are marked with `*`. --- ## Auth & Users POST /auth/register [jwt-only] - Register new user Creates a user entity from JWT claims. Idempotent - returns existing user if already registered. --- **Permission:** `user:create` **Auth:** jwt-only GET /users/me [required] - Get current user Returns the authenticated user's entity. --- **Permission:** `user:view` **Auth:** required GET /users/{id} [optional] - Get user by ID path: id Returns a user entity by ID. May require authentication depending on permissions. --- **Permission:** `user:view` **Auth:** optional PUT /users/{id} [required] - Update user profile path: id body: {expect_tip*:string, note:string, properties:object, properties_remove:any, relationships_add:object[], relationships_remove:object[], label:string} Updates a user's profile. Requires user:update permission (typically self-ownership). --- **Permission:** `user:update` **Auth:** required POST /users/me/keys [required] - Create API key body: {label:string, expires_in:integer} Creates a new API key for the authenticated user. The full key is only returned once - store it securely. --- **Permission:** `user:credentials` **Auth:** required GET /users/me/keys [required] - List API keys Lists all active API keys for the authenticated user. Returns prefixes only, not full keys. --- **Permission:** `user:credentials` **Auth:** required DELETE /users/me/keys/{prefix} [required] - Revoke API key path: prefix Revokes an API key by prefix. The key will be immediately invalid. --- **Permission:** `user:credentials` **Auth:** required GET /users/{id}/collections [optional] - List collections user has access to path: id query: predicate:string, limit:string, offset:string Returns all collections where the user has a role relationship (owner, editor, viewer, etc.). Queries GraphDB for collections with relationships pointing to this user where peer_type is 'user'. Results include the role predicate so clients know what access the user has to each collection. Supports filtering by predicate (role name) and pagination. --- **Permission:** `user:view` **Auth:** optional POST /users/me/search [required] - Search across user collections body: {query*:string, type:string, role:owner|editor|viewer, include_public:boolean, limit:integer, expand:preview|full|none} Performs semantic search across all collections the authenticated user has access to. ## Features - Searches all user's collections in parallel (up to 25) - Optionally includes public-domain entities - Filter by entity type or collection role - Results ranked by semantic relevance ## Performance - Collections are queried in parallel for speed - If user has more than 25 collections, queries first 25 (by created_at). Use role filter to narrow down. - Response includes metadata showing collections_queried vs collections_total ## Scoring - Results use cosine similarity scores (0-1) - Scores are comparable across collections ## Entity Expansion Use `expand` in the request body to fetch entity data inline with search results: - **`expand: "preview"` (default)**: Adds `entity_preview` with fresh lightweight data (id, type, label, timestamps) - **`expand: "full"`**: Adds `entity` with complete manifest including all properties and relationships - **`expand: "none"`**: Returns search metadata only (fastest, lowest bandwidth) Preview mode is recommended for most use cases. Full expansion can result in large payloads. Gracefully handles deleted or inaccessible entities (returns results without expansion data). --- **Permission:** `search:execute` **Auth:** required ## Collections POST /collections [required] - Create a new collection body: {note:string, id:string, label*:string, description:string, display_image_url:string, roles:object, properties:object, relationships:object[]} Creates a collection with the authenticated user as owner. --- **Permission:** `collection:create` **Auth:** required GET /collections/{id} [optional] - Get collection by ID path: id Returns a collection entity by ID. --- **Permission:** `collection:view` **Auth:** optional PUT /collections/{id} [required] - Update collection properties path: id body: {expect_tip*:string, note:string, properties:object, properties_remove:any, relationships_add:object[], relationships_remove:object[], label:string, description:string, display_image_url:string} Updates collection properties. Requires collection:update permission. --- **Permission:** `collection:update` **Auth:** required POST /collections/{id}/roles [required] - Add a new role path: id body: {role*:string, actions*:string[]} Adds a new role to the collection. Requires collection:manage permission. --- **Permission:** `collection:manage` **Auth:** required PUT /collections/{id}/roles/{role} [required] - Update role actions path: id, role body: {actions*:string[]} Updates the actions for an existing role. Requires collection:manage permission. --- **Permission:** `collection:manage` **Auth:** required DELETE /collections/{id}/roles/{role} [required] - Delete a role path: id, role Deletes a role from the collection. Requires collection:manage permission. --- **Permission:** `collection:manage` **Auth:** required GET /collections/{id}/members [optional] - List collection members path: id query: include_expired:true|false Returns all members of the collection grouped by type. By default, expired memberships are excluded. --- **Permission:** `collection:view` **Auth:** optional POST /collections/{id}/members [required] - Assign user to role path: id body: {user_id*:string, role*:string, expires_in:integer} Assigns a user to a role in the collection. Requires collection:manage permission. --- **Permission:** `collection:manage` **Auth:** required DELETE /collections/{id}/members/{userId} [required] - Remove user from role path: id, userId query: role*:string Removes a user from a role in the collection. Requires collection:manage permission. --- **Permission:** `collection:manage` **Auth:** required PUT /collections/{id}/root [required] - Set root entity path: id body: {expect_tip*:string, entity_id*:string} Links an entity as the root of this collection. **Prerequisites:** The entity must already have a 'collection' relationship pointing to this collection (typically set during entity creation via the `collection` field). **Recommended flow:** 1. Create entity with `collection` field set → entity is immediately protected 2. Call this endpoint to establish the root link from collection to entity This adds only the reverse relationship: - Collection → Entity (predicate: 'root') Requires collection:update permission on the collection. --- **Permission:** `collection:update` **Auth:** required GET /collections/{id}/entities [optional] - List entities in a collection path: id query: type:string, limit:integer, offset:integer, expand:preview|full Returns entities belonging to this collection from the graph database. Supports pagination and optional type filtering. Results are ordered by creation date (newest first). **Expansion Modes:** By default, returns lightweight summaries from GraphDB (pi, type, label, timestamps). Use the `expand` parameter to hydrate entity data from storage: - **`?expand=preview`**: Adds `preview` field with fresh lightweight data (label, truncated description/text, timestamps). ~5-10KB per entity. - **`?expand=full`**: Adds `entity` field with complete manifest (all properties, relationships, version history). ~20-50KB per entity. **Performance Note:** Expansion requires fetching each entity from storage. Limited to 100 entities per request. Use smaller `limit` values when expanding. --- **Permission:** `collection:view` **Auth:** optional ## Entities POST /entities [required] - Create a new entity body: {note:string, id:string, type*:string, properties:object, relationships:object[], collection:string} Creates a generic entity of any type. For type-specific validation, use type-specific endpoints. --- **Permission:** `entity:create` **Auth:** required POST /entities/batch [required] - Batch create entities body: {entities*:BatchCreateEntityItem[], default_collection:string} Creates multiple entities in a single request with bounded internal concurrency. Entities are created in chunks of 10 internally. Each entity follows the same permission model as single creates. Returns per-entity results. HTTP 201 if all succeed, 207 if some fail. **Max batch size:** 100 entities. --- **Permission:** `entity:create` **Auth:** required GET /entities/{id} [optional] - Get entity by ID path: id query: expand:string, expand_limit:integer Returns any entity by ID. Permission check uses parent collection if entity belongs to one. **Relationship Expansion:** Use the `expand=relationships[:mode]` query parameter to hydrate relationship peer data: - **No expansion (default)**: Returns relationships with stored `peer_label`/`peer_type` (may be stale) ```json { "predicate": "contains", "peer": "01KDOC...", "peer_label": "Old Label" } ``` - **`?expand=relationships:preview`**: Adds `peer_preview` with fresh lightweight data (id, type, label, truncated description/text, timestamps) ```json { "predicate": "contains", "peer": "01KDOC...", "peer_label": "Old Label", "peer_preview": { "id": "01KDOC...", "type": "document", "label": "Updated Label", "description_preview": "This is a document with...", "created_at": "2025-01-15T10:00:00Z", "updated_at": "2025-01-20T14:30:00Z" } } ``` - **`?expand=relationships:full`**: Adds `peer_entity` with complete entity manifest (all properties, relationships, version history) ```json { "predicate": "contains", "peer": "01KDOC...", "peer_label": "Old Label", "peer_entity": { "id": "01KDOC...", "cid": "bafyrei...", "type": "document", "properties": { "label": "Updated Label", "text": "..." }, "relationships": [...], "ver": 3, "created_at": "2025-01-15T10:00:00Z", "ts": 1737380000000, "edited_by": { "user_id": "01JUSER...", "method": "manual" } } } ``` **Performance:** Preview expansion is recommended for most use cases. Full expansion with many large entities can result in multi-MB payloads. **Expansion Limit:** Use `?expand_limit=N` to control maximum relationships expanded (1-500, default 100). When truncated, the response includes `_expansion_metadata` with counts. --- **Permission:** `entity:view` **Auth:** optional PUT /entities/{id} [required] - Update entity path: id body: {expect_tip*:string, note:string, properties:object, properties_remove:any, relationships_add:object[], relationships_remove:object[]} Updates an entity with merge semantics. **This is the recommended way to manage relationships.** - `relationships_add`: Upsert relationships (properties are merged if relationship exists) - `relationships_remove`: Remove by predicate/peer - `properties`: Deep merged with existing - `properties_remove`: Remove nested properties using nested object structure **properties_remove syntax:** - Top-level keys: `["field1", "field2"]` - Nested keys: `{ parent: { child: ["key_to_remove"] } }` - **Dot notation is NOT supported** - `["parent.child.key"]` will NOT work Example to remove `config.options.debug`: ```json { "properties_remove": { "config": { "options": ["debug"] } } } ``` Use `/relationships` only for bidirectional links updating two entities atomically. Note: entity:update on a collection requires collection:update permission. --- **Permission:** `entity:update` **Auth:** required DELETE /entities/{id} [required] - Delete entity path: id body: {expect_tip*:string, note:string, reason:string} Soft-deletes an entity by creating a tombstone version. The entity can be restored later via POST /entities/:id/restore. Note: entity:delete on a collection requires collection:delete permission. --- **Permission:** `entity:delete` **Auth:** required GET /entities/{id}/preview [optional] - Get entity preview path: id Returns lightweight preview data for an entity. Useful for: - Link previews and hover cards - Relationship metadata freshness (vs stale peer_label) - AI context management (smaller payloads) - Search result enhancement Returns: id, type, label, collection_pi, description_preview (200 chars), text_preview (200 chars), timestamps. **Performance:** Single KV fetch, ~40-60ms response time, typically <1KB payload. --- **Permission:** `entity:view` **Auth:** optional GET /entities/{id}/tip - Get entity tip CID path: id Returns only the current manifest CID (tip) for an entity. Lightweight endpoint for CAS operations - single Durable Object lookup, no manifest fetch, no permission check. --- **Permission:** `entity:tip` **Auth:** none DELETE /entities/{id}/cascade [required] - Cascade delete entity and related entities path: id body: {expect_tip*:string, note:string, collection_id*:string, cascade_predicates*:string[], edited_by_filter:string, max_depth:integer, reason:string} Deletes an entity and all related entities matching predicate patterns within a scoped collection. **Permission Model:** - Requires `entity:delete` permission on the specified `collection_id` - Single permission check at the start (not per-entity) - Individual entity type permissions are NOT checked during cascade **Cascade Rules:** - `collection` predicate NEVER cascades (hard rule - protects collection structure) - Only entities in the specified collection are deleted - Entities outside the collection are skipped (reported in `skipped` array) **Predicate Patterns:** - `"child"` - exact match only - `"has_*"` - matches has_document, has_image, etc. - `"*_copy"` - matches file_copy, document_copy, etc. - `"*"` - matches ALL predicates (except collection) **Traversal:** - BFS traversal with parallel processing per depth layer - Max depth: 20 (default: 10) - Optional `edited_by_filter` to only delete entities created by a specific actor (useful for agent cleanup) **CAS Handling:** - Root entity uses the provided `expect_tip` - Child entities use re-fetch + single retry strategy - CAS conflicts are reported as skipped (not failures) **Response:** - Lists all deleted entities with their depth from root - Lists skipped entities with reasons - Provides summary statistics --- **Permission:** `entity:delete` **Auth:** required POST /entities/{id}/restore [required] - Restore deleted entity path: id body: {expect_tip*:string, note:string} Restores a deleted entity by finding the last non-deleted version and creating a new version from it. Note: entity:restore on a collection requires collection:restore permission. --- **Permission:** `entity:restore` **Auth:** required GET /entities/{id}/collection [optional] - Get entity collection path: id Returns the collection ID that this entity belongs to. Returns null if the entity is not in any collection. If the entity IS a collection, returns its own ID. --- **Permission:** `entity:view` **Auth:** optional GET /entities/{id}/tree [optional] - Get entity tree path: id query: depth:integer, collection:string, predicates:string, limit:integer Returns a hierarchical tree of entities reachable from the source entity. Use this to browse collections and folders without making multiple API calls. The tree follows relationship edges (optionally filtered by predicate) and returns a nested structure suitable for tree UI rendering. Query parameters: - `depth`: Max tree depth (1-4, default 2) - `collection`: Constrain to entities in this collection - `predicates`: Comma-separated predicates to follow (e.g., "contains") - `limit`: Max nodes to return (default 100) --- **Permission:** `entity:view` **Auth:** optional GET /entities/{id}/diff [optional] - Get diff between entity versions path: id query: from:string, to:string, format:semantic|patch Computes the difference between two versions of an entity. Query parameters: - `from`: CID of the "from" version (defaults to prev of "to" version) - `to`: CID of the "to" version (defaults to current tip) - `format`: Output format - "semantic" (default) or "patch" (RFC 6902) Modes: - No params: Compare current tip with its previous version - `to` only: Compare that version with its prev - `from` only: Compare from that version to current tip - Both: Compare any two versions For version 1 entities (no previous version), "from" is null and all content appears as added. --- **Permission:** `entity:view` **Auth:** optional GET /entities/{id}/permissions [required] - Get your permissions for an entity path: id Returns the list of actions you can perform on this entity. The response includes: - `allowed_actions`: Concrete actions you can perform (no wildcards) - `resolution`: How permissions were determined Resolution methods: - `collection`: Permissions from your role in the parent collection - `self`: You are checking your own user entity (self-ownership) - `open_season`: Entity is not in any collection (publicly accessible) Actions are filtered to only those relevant to the entity type: - For files: entity:* and file:* actions - For collections: entity:* and collection:* actions - etc. --- **Permission:** `entity:view` **Auth:** required GET /entities/{id}/attestation [optional] - Get latest attestation path: id Returns the Arweave attestation for the current (latest) version of an entity. Returns 202 Accepted if the attestation upload is still pending. --- **Permission:** `entity:view` **Auth:** optional ## Relationships POST /relationships [required] - Add relationship between entities body: {note:string, source_id*:string, target_id*:string, source_predicate*:string, target_predicate:string, expect_source_tip*:string, expect_target_tip:string} Creates a relationship from source to target entity. **⚠️ For single-entity updates, prefer `PUT /entities/:id` with `relationships_add` - simpler API, one CAS guard, can update properties too.** Use this endpoint only for **bidirectional** relationships requiring atomic updates to TWO entities. If `target_predicate` is provided (bidirectional): - Updates both source and target entities - Requires `entity:update` on both, plus two CAS guards If `target_predicate` is omitted (unidirectional): - Use `PUT /entities/:id` instead --- **Permission:** `entity:update` **Auth:** required DELETE /relationships [required] - Remove relationship between entities body: {note:string, source_id*:string, target_id*:string, source_predicate*:string, target_predicate:string, expect_source_tip*:string, expect_target_tip:string} Removes a relationship from source to target entity. **⚠️ For single-entity updates, prefer `PUT /entities/:id` with `relationships_remove` - simpler API, one CAS guard, can update properties too.** Use this endpoint only for **bidirectional** relationships requiring atomic updates to TWO entities. If `target_predicate` is provided (bidirectional): - Updates both source and target entities - Requires `entity:update` on both, plus two CAS guards If `target_predicate` is omitted (unidirectional): - Use `PUT /entities/:id` instead --- **Permission:** `entity:update` **Auth:** required POST /connect [required] - Connect two entities body: {note:string, source_id*:string, target_id*:string, expect_tip*:string, predicate:string, label:string, description:string} Creates a unidirectional relationship from source to target entity. This is a shorthand for adding a relationship with sensible defaults: - Default predicate: `connects_to` (customizable) - Optional label and description stored in relationship properties - Only requires `entity:update` permission on source entity Use this for simple entity linking. For bidirectional relationships or advanced options, use the `/relationships` endpoint. --- **Permission:** `entity:update` **Auth:** required POST /connect/disconnect [required] - Disconnect two entities body: {note:string, source_id*:string, target_id*:string, expect_tip*:string, predicate:string} Removes a unidirectional relationship from source to target entity. This is a shorthand for removing a relationship: - Default predicate: `connects_to` (customizable) - Only requires `entity:update` permission on source entity For bidirectional removal, use the `/relationships` endpoint. --- **Permission:** `entity:update` **Auth:** required ## Files POST /files [required] - Create file entity body: {key*:string, filename*:string, content_type*:string, size*:integer, label:string, description:string, properties:object, relationships:object[], collection:string} Creates a new file entity. ## Flow 1. Call this endpoint with file metadata (key, filename, content_type, size) 2. Receive entity data (uploaded: false) 3. POST the file content to /{id}/content 4. Entity will be updated with uploaded: true and verified CID ## Key Best Practice Use a unique identifier as the key (e.g., version number, timestamp). The actual CID is computed during upload. --- **Permission:** `file:create` **Auth:** required GET /files/{id} [optional] - Get file metadata path: id Returns file entity metadata. Use /{id}/content to download the file content. --- **Permission:** `file:view` **Auth:** optional PUT /files/{id} [required] - Update file metadata path: id body: {expect_tip*:string, note:string, properties:object, properties_remove:any, relationships_add:object[], relationships_remove:object[], key:string, filename:string, content_type:string, size:integer, label:string, description:string} Updates file metadata without changing the file content. ## Key Changes The key can be changed, but ONLY to a key that already exists in R2. This allows "regressing" to a previous file version. To upload a new file, use POST /{id}/reupload instead. --- **Permission:** `file:update` **Auth:** required POST /files/{id}/content [required] - Upload file content path: id Uploads the binary content for a file entity. ## Request - Content-Type: The MIME type of the file (must match entity's content_type) - Body: Binary file content (streaming supported) ## Limits - Maximum file size: 500 MB ## Behavior - Streams content directly to R2 - Computes CID from file bytes - Updates entity with uploaded: true, verified size, and computed CID - Atomic operation - either fully succeeds or fails ## Idempotency Re-uploading content for an already-uploaded file will fail with 409 Conflict. Use POST /{id}/reupload first to create a new version. --- **Permission:** `file:upload` **Auth:** required GET /files/{id}/content [optional] - Download file content path: id Downloads the binary content of a file entity. ## Response Headers - Content-Type: The MIME type of the file - Content-Length: File size in bytes - Content-Disposition: attachment; filename="original_filename" ## Streaming Response is streamed directly from R2 storage. --- **Permission:** `file:download` **Auth:** optional POST /files/{id}/reupload [required] - Prepare for new file version path: id body: {expect_tip*:string, note:string, key*:string, content_type*:string, size*:integer, filename:string, label:string, description:string} Prepares the entity for uploading a new file version. ## Flow 1. Call this endpoint with new key and file metadata 2. Receive updated entity (uploaded: false) 3. POST the new file content to /{id}/content 4. Entity will be updated with uploaded: true and verified CID ## Key Requirement The new key must NOT already exist in R2 (no overwrites). Previous file versions remain accessible via manifest history. --- **Permission:** `file:reupload` **Auth:** required ## Folders POST /folders [required] - Create folder body: {note:string, label*:string, description:string, rich_description:string, metadata:object, properties:object, relationships:object[], collection:string, parent:string} Creates a new folder entity. Optionally sets parent for immediate hierarchy. If a parent folder is specified, a bidirectional relationship is created: - Parent folder contains this folder - This folder is in parent folder --- **Permission:** `folder:create` **Auth:** required GET /folders/{id} [optional] - Get folder path: id Returns folder metadata including children and parent relationships. --- **Permission:** `folder:view` **Auth:** optional PUT /folders/{id} [required] - Update folder path: id body: {expect_tip*:string, note:string, properties:object, properties_remove:any, relationships_add:object[], relationships_remove:object[], label:string, description:string, rich_description:string, metadata:object} Updates folder properties (label, description, metadata). Properties are merged. --- **Permission:** `folder:update` **Auth:** required POST /folders/{id}/children [required] - Add child to folder path: id body: {expect_tip*:string, note:string, child_id*:string, expect_child_tip:string} Adds a child entity (file or folder) to this folder. Creates bidirectional relationship: - Folder contains child - Child is in folder **Idempotent**: if relationship already exists, returns current state without error. --- **Permission:** `folder:update` **Auth:** required DELETE /folders/{id}/children/{childId} [required] - Remove child from folder path: id, childId body: {expect_tip*:string, note:string, expect_child_tip*:string} Removes a child entity from this folder (bidirectional). --- **Permission:** `folder:update` **Auth:** required POST /folders/{id}/children/bulk [required] - Bulk add children to folder path: id body: {expect_tip*:string, note:string, children*:object[]} Efficiently adds multiple children to a folder. **Limit**: Maximum 50 children per request. For larger batches, make multiple requests, refetching the folder's CID between each to satisfy the CAS guard. **Strategy**: 1. Updates folder once with all 'contains' relationships 2. Updates each child in parallel with 'in' back-link **Idempotent**: skips children that already have the relationship. Returns both added and skipped children in the response. --- **Permission:** `folder:update` **Auth:** required POST /folders/{id}/parents [required] - Add parent to folder path: id body: {expect_tip*:string, note:string, parent_id*:string, expect_parent_tip:string} Adds this folder to a parent folder. Creates bidirectional relationship: - Parent contains this folder - This folder is in parent **Idempotent**: if relationship already exists, returns current state without error. --- **Permission:** `folder:update` **Auth:** required DELETE /folders/{id}/parents/{parentId} [required] - Remove parent from folder path: id, parentId body: {expect_tip*:string, note:string, expect_parent_tip*:string} Removes this folder from a parent folder (bidirectional). --- **Permission:** `folder:update` **Auth:** required ## Versions GET /versions/{id} [optional] - List version history path: id query: limit:integer, from:string Returns version metadata for an entity (newest first). Use pagination for entities with many versions. --- **Permission:** `entity:view` **Auth:** optional GET /versions/manifest/{cid} [optional] - Get manifest by CID path: cid Returns the full manifest for any version by its CID. Permission is checked against the entity ID in the manifest. --- **Permission:** `entity:view` **Auth:** optional GET /versions/{id}/{ver}/attestation [optional] - Get version attestation path: id, ver Returns the Arweave attestation for a specific version of an entity. --- **Permission:** `entity:view` **Auth:** optional ## Agents POST /agents [required] - Create an agent body: {note:string, id:string, label*:string, endpoint*:string, actions_required*:string[], collection*:string, description:string, uses_agents:object[], input_schema:object, output_schema:object, properties:object, relationships:object[]} Creates a new agent entity. Requires agent:create permission in the target collection. --- **Permission:** `agent:create` **Auth:** required GET /agents/{id} [optional] - Get agent by ID path: id Returns an agent entity by ID. --- **Permission:** `agent:view` **Auth:** optional PUT /agents/{id} [required] - Update agent path: id body: {expect_tip*:string, note:string, properties:object, properties_remove:any, relationships_add:object[], relationships_remove:object[], label:string, description:string, endpoint:string, actions_required:string[], status:development|active|disabled, uses_agents:object[], input_schema:object, output_schema:object} Updates an agent. Requires agent:update permission. **Field placement:** Agent-specific fields (`label`, `endpoint`, `actions_required`, `input_schema`, etc.) must be at the root level, NOT inside `properties`. The `properties` bag is for additional custom data only. **properties_remove syntax:** Use nested objects, not dot notation. - Correct: `{ "input_schema": { "properties": ["field_to_remove"] } }` - Wrong: `["input_schema.properties.field_to_remove"]` --- **Permission:** `agent:update` **Auth:** required POST /agents/{id}/invoke [required] - Invoke an agent path: id body: {target*:string, job_collection:string, input:object, expires_in:integer, confirm:boolean} Invoke an agent to perform work on a target collection. **Note:** The `target` parameter must be a collection ID. Agents receive permissions scoped to collections, not individual entities. To process a specific entity, pass the collection it belongs to. **Two-phase interaction:** 1. `confirm: false` (default) - preview permissions that will be granted 2. `confirm: true` - execute the agent The agent receives temporal (time-limited) permissions on the target collection. --- **Permission:** `agent:invoke` **Auth:** required POST /agents/{id}/keys [required] - Create API key for agent path: id body: {label:string, expires_in_days:integer} Creates an API key for the agent. The full key is only returned once. --- **Permission:** `agent:manage` **Auth:** required GET /agents/{id}/keys [required] - List API keys for agent path: id Lists all active API keys for the agent (without the actual key values). --- **Permission:** `agent:manage` **Auth:** required DELETE /agents/{id}/keys/{prefix} [required] - Revoke API key path: id, prefix Revokes an API key for the agent. --- **Permission:** `agent:manage` **Auth:** required POST /agents/{id}/verify [required] - Verify agent endpoint ownership path: id body: {confirm:boolean} Verify that you control the agent's endpoint URL. This is required before activating an agent. **Two-phase flow:** 1. Call without `confirm` to get a verification token 2. Deploy `/.well-known/arke-verification` endpoint returning the token 3. Call with `confirm: true` to complete verification **Verification endpoint format:** Your endpoint must return JSON: ```json { "verification_token": "vt_xxx...", "agent_id": "IIxxx..." } ``` --- **Permission:** `agent:manage` **Auth:** required GET /agents/{id}/jobs/{job_id}/status [optional] - Get job status from agent path: id, job_id query: detail:full, errors:integer Proxies to the agent's `/status/:job_id` endpoint and returns the response. Use this endpoint to poll job status after invoking an agent. The `agent_id` and `job_id` are both returned in the invoke response. **Query Parameters (passed through to agent):** - `detail=full` - Include detailed sub-job/dispatch information (orchestrators/workflows) - `errors=N` - Include last N errors (orchestrators only) **Response:** Returns the agent's status response directly. Schema varies by agent type (service, workflow, orchestrator) but always includes: - `job_id` - Job identifier - `status` - Current status (pending/running/done/error) - `progress` - Progress counters (total/pending/done/error) - `started_at` - When the job started - `completed_at` - When the job completed (if done/error) - `updated_at` - Last state modification Agent-specific fields (phase, stages, sub_jobs, folders, dispatches) are also included when applicable. --- **Permission:** `agent:view` **Auth:** optional ## Graph & Query POST /graph/paths [required] - Find paths between entities query: expand:preview|full|none body: {source_pis*:string[], target_pis*:string[], max_depth:integer, direction:outgoing|incoming|both, limit:integer} Find shortest paths between source and target entity sets. Returns all paths up to the limit (default 100). Use this when you know both endpoints and want to discover how they connect - for example, finding the chain of relationships between a person and a document. **Entity Expansion (default: preview):** - Omit `expand` or use `?expand=preview` - Lightweight previews for all path entities - `?expand=full` - Complete entity manifests (use with caution) - `?expand=none` - Disable expansion (graph metadata only) **Performance Warning:** 100 paths can reference 400-800 unique entities, adding 5-10s latency with expansion. **Recommendations:** - Use `limit: 10-20` when using expansion - Prefer preview over full - Use `expand=none` for large result sets, then fetch specific entities separately --- **Permission:** `graph:query` **Auth:** required POST /graph/reachable [required] - Find reachable entities (exhaustive) query: expand:preview|full|none body: {source_pis*:string[], target_type*:string, max_depth:integer, direction:outgoing|incoming|both, limit:integer} Find all entities of a specific type reachable from source entities within N hops. Returns up to 100 results by default. **When to use this vs POST /query:** This endpoint returns exhaustive, unranked results - all reachable entities up to the limit. Use `POST /query` when you want relevance-ranked results combining semantic similarity with graph structure. Use this endpoint when you need comprehensive graph exploration from known entity IDs. **Target Expansion (default: preview):** - Omit `expand` or use `?expand=preview` - Lightweight target previews - `?expand=full` - Complete target manifests - `?expand=none` - Disable expansion (graph metadata only) **Performance:** With 100 targets, expansion adds ~1s. --- **Permission:** `graph:query` **Auth:** required GET /graph/entity/{id} [required] - Get entity from graph path: id query: expand:preview|full|none Get entity details with all relationships from the graph database. Unlike the entity manifest, this includes both outgoing and incoming relationships - showing not just what this entity links to, but also what links to it. **Peer Expansion (default: preview):** - Omit `expand` or use `?expand=preview` - Lightweight peer previews - `?expand=full` - Complete peer manifests - `?expand=none` - Disable expansion (graph metadata only) **Performance:** With 50 peers, expansion adds ~500ms. --- **Permission:** `graph:query` **Auth:** required POST /query [required] - Execute Argo query body: {path*:string, k:integer, k_explore:integer, collection:string, expand:none|preview|full} Execute an Argo DSL query for path-based graph traversal with relevance ranking. ## When to Use This Endpoint | Endpoint | Use Case | |----------|----------| | `POST /query` | Semantic search + graph traversal with **relevance-ranked** results (default k=25) | | `POST /graph/reachable` | **Exhaustive** graph exploration from known entities (default limit=100) | | `POST /graph/paths` | Find all shortest paths between two entity sets | This endpoint combines semantic similarity scores with path length to rank results. For exhaustive graph traversal without ranking, use the `/graph/*` endpoints directly. ## Query Syntax ``` [SCOPE_PREFIX] ENTRY_POINT [ENTRY_FILTER] [-[RELATION]{DEPTH}-> TARGET_FILTER]... ``` ## Scope Prefixes Control where semantic search looks for entry points. Default is discovery mode. | Prefix | Description | Example | |--------|-------------|---------| | (none) | **Discovery mode** (default) - find relevant collections, then search within each | `"medical notes"` | | `@:collections` | Search for collections themselves | `@:collections "columbia archives"` | | `@:collection(id)` | Search within a specific collection | `@:collection(01JCOLL123) "meeting"` | | `@:discover` | Explicit discovery mode | `@:discover "research papers"` | | `@:public` | Search public domain only | `@:public "orphaned data"` | **Note:** Graph traversal (hops) is always cross-collection regardless of scope. ### Entry Points | Syntax | Description | Example | |--------|-------------|---------| | `"text"` | Semantic search | `"george washington"` | | `@id` | Exact entity ID | `@01KE4ZY69F9R40E88PK9S0TQRQ` | | `type:X` | All entities of type | `type:person` | | `type:X ~ "text"` | Semantic search within type | `type:person ~ "physician"` | ### Edges (Hops) | Syntax | Direction | |--------|-----------| | `-[*]->` | Outgoing | | `<-[*]-` | Incoming | | `<-[*]->` | Both | | `-[*]{,4}->` | Variable depth (1-4) | ### Examples ``` "george washington" # Discovery mode (default) @:collections "columbia university" # Find collections @:collection(01JCOLL123) "faculty meeting" # Within specific collection @:discover "alice" -[*]{,2}-> type:person # Discover, then traverse @01KE4ZY... -[*]{,2}-> type:person # From exact entity ``` ## Entity Expansion Control how much entity data is included in results via the `expand` parameter. | Value | Description | Use Case | |-------|-------------|----------| | (omitted) | **Preview** (default) - lightweight preview data | Best balance of detail and payload size | | `preview` | Same as omitted - lightweight preview data | Explicit preview mode | | `full` | Complete entity manifest | When you need all properties, relationships, versions | | `none` | No expansion - Pinecone metadata only | Fastest response, smallest payload | **Preview mode** includes: label, truncated description/text (200 chars), created_at, updated_at. **Full mode** includes: all properties, relationships, version info, CID. Both result entities and path step entities are expanded. --- **Permission:** `query:execute` **Auth:** required ## Search POST /search/similar/collections [required] - Find similar collections body: {pi*:string, limit:number, refresh:boolean, expand:preview|full|none} Find collections that are semantically similar to a given collection. Uses the collection's weighted centroid vector (combination of description and entity embeddings) to find related collections. **Entity Expansion:** Use `expand` in the request body to fetch entity data inline with search results: - **`expand: "preview"` (default)**: Adds `entity_preview` with fresh lightweight data (id, type, label, timestamps) - **`expand: "full"`**: Adds `entity` with complete manifest including all properties and relationships - **`expand: "none"`**: Returns search metadata only (fastest, lowest bandwidth) Preview mode is recommended for most use cases. Full expansion can result in large payloads. Gracefully handles deleted or inaccessible entities (returns results without expansion data). --- **Permission:** `search:similar` **Auth:** required POST /search/similar/items [required] - Find similar items across collections body: {pi*:string, collection_pi*:string, limit:number, tier1_limit:number, tier2_limit:number, include_same_collection:boolean, refresh:boolean, expand:preview|full|none} Find entities that are semantically similar to a given entity, searching across multiple collections. This performs a two-tier search: 1. First finds collections similar to the entity's collection 2. Then searches within each collection for similar items 3. Aggregates and ranks results with diversity weighting **Entity Expansion:** Use `expand` in the request body to fetch entity data inline with search results: - **`expand: "preview"` (default)**: Adds `entity_preview` with fresh lightweight data (id, type, label, timestamps) - **`expand: "full"`**: Adds `entity` with complete manifest including all properties and relationships - **`expand: "none"`**: Returns search metadata only (fastest, lowest bandwidth) Preview mode is recommended for most use cases. Full expansion can result in large payloads. Gracefully handles deleted or inaccessible entities (returns results without expansion data). --- **Permission:** `search:similar` **Auth:** required POST /search/collections [required] - Search collections by text body: {query*:string, limit:number, types:string[], expand:preview|full|none} Search for collections using semantic text search. Use this endpoint to discover collections about a topic. Results are ranked by semantic similarity to your query. **Entity Expansion:** Use `expand` in the request body to fetch entity data inline with search results: - **`expand: "preview"` (default)**: Adds `entity_preview` with fresh lightweight data (id, type, label, timestamps) - **`expand: "full"`**: Adds `entity` with complete manifest including all properties and relationships - **`expand: "none"`**: Returns search metadata only (fastest, lowest bandwidth) Preview mode is recommended for most use cases. Full expansion can result in large payloads. Gracefully handles deleted or inaccessible entities (returns results without expansion data). --- **Permission:** `search:query` **Auth:** required POST /search/agents [required] - Search agents by text body: {query*:string, limit:number, expand:preview|full|none, scope:official|all} Search for agents using semantic text search. **Official Agents (Default):** By default, this endpoint searches only the official Arke agents collection (`01KFF0H1KSR4SHHDQ7T2HXQEK6`). These agents are pre-approved, actively maintained, and tested for security and reliability. **All Agents:** Set `scope: "all"` to search network-wide. This is not recommended as results may include duplicates, outdated agents, or unapproved implementations. Results are ranked by semantic similarity to your query based on agent descriptions and capabilities. **Entity Expansion:** By default, agent search returns **full entity manifests** (including `endpoint`, `input_schema`, `actions_required`, etc.) to make discovery results immediately useful. - **`expand: "full"` (default)**: Complete agent manifests with all properties - **`expand: "preview"`**: Lightweight previews (id, type, label, description_preview, timestamps) - **`expand: "none"`**: Search metadata only (fastest) --- **Permission:** `search:query` **Auth:** required POST /search/entities [required] - Search entities within collection(s) body: {collection_pi:string, collection_pis:string[], query*:string, limit:number, types:string[], per_collection_limit:number, expand:preview|full|none} Search for entities within one or more collections using semantic text search. Provide either `collection_pi` for a single collection or `collection_pis` for multiple collections (searched in parallel). Use `per_collection_limit` to ensure result diversity when searching multiple collections. **Entity Expansion:** Use `expand` in the request body to fetch entity data inline with search results: - **`expand: "preview"` (default)**: Adds `entity_preview` with fresh lightweight data (id, type, label, timestamps) - **`expand: "full"`**: Adds `entity` with complete manifest including all properties and relationships - **`expand: "none"`**: Returns search metadata only (fastest, lowest bandwidth) Preview mode is recommended for most use cases. Full expansion can result in large payloads. Gracefully handles deleted or inaccessible entities (returns results without expansion data). --- **Permission:** `search:query` **Auth:** required POST /search/discover [required] - Discover entities across all collections body: {query*:string, limit:number, types:string[], collection_limit:number, per_collection_limit:number, expand:preview|full|none} Two-step discovery search: first finds relevant collections, then searches within them. Use this endpoint when you don't know which collections to search. The system will: 1. Find collections semantically related to your query 2. Search within each collection in parallel 3. Aggregate and rank results across all collections Great for exploration and AI agents navigating the network. **Entity Expansion:** Use `expand` in the request body to fetch entity data inline with search results: - **`expand: "preview"` (default)**: Adds `entity_preview` with fresh lightweight data (id, type, label, timestamps) - **`expand: "full"`**: Adds `entity` with complete manifest including all properties and relationships - **`expand: "none"`**: Returns search metadata only (fastest, lowest bandwidth) Preview mode is recommended for most use cases. Full expansion can result in large payloads. Gracefully handles deleted or inaccessible entities (returns results without expansion data). --- **Permission:** `search:query` **Auth:** required ## Chat POST /chat [required] - Send chat message body: {messages*:ChatMessage[]} Send a message to the Arke chat agent and receive a streaming response. The agent can execute Arke API operations on your behalf using the authenticated user's permissions. ## Headers - `X-Chat-ID`: Optional. Specify to continue an existing chat session. If omitted, a new session is created. ## Response Format The response is a Server-Sent Events (SSE) stream in AI SDK v5 UIMessage format. Stream chunks include text deltas, tool calls, and usage information. ## Token Usage Tracking Usage information is included at the end of the stream in the format: ```json {"type":"message_delta","delta":{"usage":{"input_tokens":123,"output_tokens":456}}} ``` ## Storage Limits - **Single message**: 2 MB max (returns 413 with code `MESSAGE_TOO_LARGE`) - **Chat database**: 10 GB max (returns 507 with code `CHAT_STORAGE_FULL`) - **LLM context**: ~128K tokens (returns stream error) --- **Permission:** `chat:send` **Auth:** required GET /chat/sessions [required] - List user chats Returns a paginated list of the authenticated user's chats, sorted newest-first. Only returns chats owned by the authenticated user. Anonymous chats are not indexed. Query parameters: - `limit`: Max chats to return (1-100, default 20) - `offset`: Number of chats to skip for pagination (default 0) --- **Permission:** `chat:view` **Auth:** required GET /chat/sessions/{id} [required] - Get chat session Get information about a chat session including message history. Only the session owner can view their chat sessions. --- **Permission:** `chat:view` **Auth:** required DELETE /chat/sessions/{id} [required] - Delete chat session Delete a chat session. Only the session owner can delete it. --- **Permission:** `chat:delete` **Auth:** required ## Events & Attestations GET /permissions - Get permission system metadata Returns all registered actions, verbs, types, verb implications, wildcard patterns, and default roles. This endpoint is useful for: - Building dynamic role editors - Understanding available permissions - Validating actions client-side All data is auto-generated from the actual permission system, so it's always in sync with the code. --- **Permission:** `permissions:read` **Auth:** none GET /events - List entity change events query: cursor:integer, limit:integer, network:main|test Returns a cursor-based list of entity change events for client synchronization. **Usage:** - Call without cursor to get newest events - Use returned `cursor` as `?cursor=` to get older events - Poll without cursor periodically to check for new events **Sync flow:** 1. Initial: `GET /events` → get newest, save highest `id` as high-water mark 2. Paginate: `GET /events?cursor=X` → get older events until `has_more=false` 3. Poll: `GET /events` → if newest `id` > high-water mark, process new events **Event data:** - `id`: Auto-increment ID - `pi`: Entity ID that changed - `cid`: New manifest CID - `ts`: ISO timestamp Events are ephemeral (30-day rolling window) - for full sync, use snapshots. --- **Permission:** `events:list` **Auth:** none GET /attestations/head - Get chain head Returns the latest Arweave attestation transaction ID (network head). --- **Permission:** `attestation:view` **Auth:** none GET /attestations/verify/{tx} - Verify attestation path: tx Fetches an attestation from Arweave and verifies the CID matches the manifest content. This is a public endpoint - anyone can verify attestations. --- **Permission:** `attestation:verify` **Auth:** none ## Other GET /ops-reference - Get LLM-friendly API reference Returns a condensed, plain-text API operations reference optimized for LLM consumption. This endpoint provides the same information as the OpenAPI spec but in a format that: - Uses ~80% fewer tokens than the full OpenAPI JSON - Preserves full endpoint descriptions - Organizes operations by category - Marks required fields with `*` suffix - Includes auth requirements inline **Format example:** ``` ## Collections POST /collections [required] - Create a new collection body: {label*:string, description:string} Creates a collection with the authenticated user as owner. ``` Use this for injecting API knowledge into LLM system prompts.