Sorcha Platform - API Documentation
Version: 2.2.0 Last Updated: 2026-03-16 Status: MVD Complete
Table of Contents
- Overview
- Getting Started
- Authentication
- Tenant Service API
- Platform Organisation Management API
- Organization Identity & Admin API
- Organisation Switching
- Platform Settings
- Peer Service API
- Blueprint Service API
- Wallet Service API
- Register Service API
- Action Workflow API
- Execution Helper API
- Real-time Notifications (SignalR)
- Error Handling
- Rate Limiting
- Code Examples
Overview
The Sorcha Platform provides a comprehensive REST API for building distributed ledger applications with blueprint-based workflows, secure wallet management, and transaction processing.
Base URLs:
- Development (Local):
http://localhost:5000 - Staging (Azure):
https://api-gateway.livelydune-b02bab51.uksouth.azurecontainerapps.io - Production:
https://sorcha.dev/api
API Gateway: All services are accessed through the API Gateway which provides:
- Unified routing to all microservices
- Health aggregation across services
- Load balancing and failover
- Request logging and observability
- Security headers (OWASP best practices)
Getting Started
Prerequisites
- .NET 10 SDK
- Docker (optional, for containerized deployment)
- Redis (for caching and SignalR backplane)
Quick Start
Clone the repository:
bashgit clone https://github.com/yourusername/Sorcha.git cd SorchaRun with .NET Aspire:
bashdotnet run --project src/Apps/Sorcha.AppHostAccess the API:
- API Gateway: http://localhost:5000
- Swagger UI: http://localhost:5000/scalar/v1 (Blueprint Service)
API Explorer
Visit the Scalar API documentation UI at /scalar/v1 to explore all endpoints interactively.
Authentication
OAuth 2.0 Token Endpoint
The Sorcha Platform uses OAuth 2.0 for authentication. All protected endpoints require a valid JWT Bearer token.
Token Endpoint: POST /api/service-auth/token
Supported Grant Types:
password- User credentials (email + password)client_credentials- Service principal authentication
User Authentication (Password Grant)
POST /api/service-auth/token
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=admin@sorcha.local&password=Dev_Pass_2025!Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "refresh_token_here"
}Service Principal Authentication (Client Credentials Grant)
POST /api/service-auth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=service-blueprint&client_secret=<secret>Using the Access Token
Include the access token in the Authorization header:
GET /api/organizations
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Default Credentials (Staging Environment)
Default Organization:
- Name: Sorcha Local
- Subdomain: sorcha-local
- ID:
00000000-0000-0000-0000-000000000001
Default Administrator:
- Email:
admin@sorcha.local - Password:
Dev_Pass_2025! - User ID:
00000000-0000-0000-0001-000000000001 - Roles: Administrator
⚠️ Security Warning: Change default credentials immediately in production!
Tenant Service API
The Tenant Service manages multi-tenant organizations, user identities, and service principals.
Base Path: /api/organizations
Endpoints
1. List Organizations
GET /api/organizations
Authorization: Bearer {token}Requires: Administrator role
Response: 200 OK
{
"organizations": [
{
"id": "00000000-0000-0000-0000-000000000001",
"name": "Sorcha Local",
"subdomain": "sorcha-local",
"status": "Active",
"createdAt": "2025-12-13T00:00:00Z",
"branding": {
"primaryColor": "#6366f1",
"secondaryColor": "#8b5cf6",
"companyTagline": "Distributed Ledger Platform"
}
}
]
}2. Get Organization by ID
GET /api/organizations/{id}
Authorization: Bearer {token}Response: 200 OK (same structure as above)
3. Get Organization by Subdomain
GET /api/organizations/by-subdomain/{subdomain}Note: This endpoint allows anonymous access for subdomain validation.
Response: 200 OK
4. Create Organization
POST /api/organizations
Authorization: Bearer {token}
Content-Type: application/json
{
"name": "Acme Corporation",
"subdomain": "acme",
"branding": {
"primaryColor": "#ff6600",
"secondaryColor": "#333333",
"companyTagline": "Innovation in Motion"
}
}Response: 201 Created
5. Add User to Organization
POST /api/organizations/{organizationId}/users
Authorization: Bearer {token}
Content-Type: application/json
{
"email": "john.doe@acme.com",
"displayName": "John Doe",
"password": "SecurePassword123!",
"roles": ["User"]
}Response: 201 Created
6. List Organization Users
GET /api/organizations/{organizationId}/users
Authorization: Bearer {token}Response: 200 OK
Platform Organisation Management API
Endpoints for platform-level organisation governance. Requires SystemAdmin role.
List Organisations
GET /api/platform/organizations?page=1&pageSize=25&status=Active
Authorization: Bearer <system-admin-token>Response (200):
{
"items": [
{
"id": "guid",
"name": "Acme Corp",
"subdomain": "acme-corp",
"status": "Active",
"orgType": "Private",
"isPlatformOrg": false,
"userCount": 12,
"createdAt": "2026-03-16T10:00:00Z"
}
],
"totalCount": 42,
"page": 1,
"pageSize": 25
}Update Organisation Status
PUT /api/platform/organizations/{orgId}/status
Authorization: Bearer <system-admin-token>
Content-Type: application/jsonRequest:
{ "status": "Suspended" }Response (204): No content on success.
Validation: Status must be Active or Suspended. Platform organisations (System Admin, Public) cannot be suspended.
Get Organisation Users
GET /api/platform/organizations/{orgId}/users?page=1&pageSize=25
Authorization: Bearer <system-admin-token>Response (200):
{
"items": [
{
"id": "guid",
"email": "user@example.com",
"displayName": "Jane Doe",
"roles": ["Administrator"],
"status": "Active",
"createdAt": "2026-03-16T10:00:00Z",
"lastLoginAt": "2026-03-16T12:00:00Z"
}
],
"totalCount": 12,
"page": 1,
"pageSize": 25
}Organization Identity & Admin API
Feature 054 adds comprehensive organization identity management, OIDC single sign-on, user authentication, two-factor authentication, invitations, domain restrictions, custom domains, audit logging, and admin dashboard capabilities to the Tenant Service.
IDP Configuration
Manages external identity provider configuration for OIDC-based single sign-on. Supports provider presets: MicrosoftEntra, Google, Okta, Apple, AmazonCognito, GenericOidc.
Base Path: /api/organizations/{orgId}/idpAuthorization: Administrator role required
| Method | Path | Description |
|---|---|---|
| GET | /api/organizations/{orgId}/idp | Get IDP configuration including discovered endpoints and enabled status |
| PUT | /api/organizations/{orgId}/idp | Create or update IDP configuration (triggers OIDC discovery) |
| DELETE | /api/organizations/{orgId}/idp | Delete IDP configuration (disables SSO) |
| POST | /api/organizations/{orgId}/idp/discover | Discover IDP endpoints via .well-known/openid-configuration |
| POST | /api/organizations/{orgId}/idp/test | Test IDP connection with client_credentials grant |
| POST | /api/organizations/{orgId}/idp/toggle | Enable or disable IDP without removing configuration |
OIDC Authentication
Handles the full OIDC authorization code + PKCE exchange, user provisioning, and Sorcha JWT issuance.
Base Path: /api/auth
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/oidc/initiate | Anonymous | Generate authorization URL for org's configured IDP |
| GET | /api/auth/callback/{orgSubdomain} | Anonymous | OIDC callback: exchange authorization code for Sorcha JWT |
| POST | /api/auth/oidc/complete-profile | Authenticated | Complete missing profile fields after OIDC provisioning |
Email Verification
Base Path: /api/auth
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/verify-email | Anonymous | Verify email address with token |
| POST | /api/auth/resend-verification | Authenticated | Resend verification email (rate limited: 3/hour) |
Authentication & Token Management
Local email/password authentication with progressive lockout, token lifecycle management, and self-registration.
Base Path: /api/auth
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/login | Anonymous | Login with email/password (returns JWT or 2FA challenge) |
| POST | /api/auth/verify-2fa | Anonymous | Verify TOTP code to complete login (rate limited) |
| POST | /api/auth/register | Anonymous | Self-register with email/password (public orgs only, NIST password policy) |
| POST | /api/auth/token/refresh | Anonymous | Exchange refresh token for new access token |
| POST | /api/auth/token/revoke | Authenticated | Revoke an access or refresh token |
| POST | /api/auth/token/introspect | Service | Introspect a token (service-to-service only) |
| POST | /api/auth/token/revoke-user | Administrator | Revoke all tokens for a specific user |
| POST | /api/auth/token/revoke-organization | Administrator | Revoke all tokens for all users in an organization |
| GET | /api/auth/me | Authenticated | Get current user information from token claims |
| POST | /api/auth/logout | Authenticated | Logout and revoke current access token |
TOTP Two-Factor Authentication
TOTP-based 2FA with authenticator app support, QR code provisioning, and backup codes.
Base Path: /api/totp
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/totp/setup | Authenticated | Initiate TOTP setup (generates secret, QR URI, backup codes) |
| POST | /api/totp/verify | Authenticated | Verify initial TOTP code to complete enrollment |
| POST | /api/totp/validate | Anonymous | Validate TOTP code during login (requires loginToken, rate limited) |
| POST | /api/totp/backup-validate | Anonymous | Validate and consume backup code during login (rate limited) |
| DELETE | /api/totp | Authenticated | Disable TOTP 2FA for current user |
| GET | /api/totp/status | Authenticated | Get TOTP 2FA status for current user |
Passkey Authentication (Feature 055)
FIDO2/WebAuthn passkey authentication for both organizational users (2FA) and public users (primary auth).
Org User Passkey 2FA
Base Path: /api/passkeyAuthorization: Authenticated org user
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/passkey/register/options | Authenticated | Get passkey registration options (Fido2NetLib creation options) |
| POST | /api/passkey/register/verify | Authenticated | Complete passkey registration with attestation response |
| GET | /api/passkey/credentials | Authenticated | List user's passkey credentials |
| DELETE | /api/passkey/credentials/{id} | Authenticated | Revoke a passkey credential |
Org User Passkey 2FA Login
Base Path: /api/auth
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/verify-passkey/options | Anonymous | Get passkey assertion options for 2FA verification (requires loginToken) |
| POST | /api/auth/verify-passkey | Anonymous | Verify passkey assertion to complete 2FA login |
Public User Passkey Signup
Base Path: /api/auth/public/passkey
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/public/passkey/register/options | Anonymous | Get registration options for new public user (display name + optional email) |
| POST | /api/auth/public/passkey/register/verify | Anonymous | Verify attestation, create PublicIdentity, issue tokens |
Public User Passkey Sign-in (Discoverable)
Base Path: /api/auth/passkey
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/passkey/assertion/options | Anonymous | Get assertion options (discoverable credentials, no email needed) |
| POST | /api/auth/passkey/assertion/verify | Anonymous | Verify assertion and issue tokens |
Public User Social Login
Base Path: /api/auth/public/social
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /api/auth/public/social/initiate | Anonymous | Initiate OAuth flow for provider (Google, Microsoft, GitHub, Apple) |
| POST | /api/auth/public/social/callback | Anonymous | Handle OAuth callback, provision user, issue tokens |
Public User Auth Method Management
Base Path: /api/auth/publicAuthorization: Authenticated public user (JWT with sub claim)
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/auth/public/methods | Authenticated | List passkeys and social links for current user |
| POST | /api/auth/public/social/link | Authenticated | Link a new social account |
| DELETE | /api/auth/public/social/{linkId} | Authenticated | Unlink social account (last-method guard prevents removing only auth method) |
| POST | /api/auth/public/passkey/add/options | Authenticated | Get options for adding passkey to existing account |
| POST | /api/auth/public/passkey/add/verify | Authenticated | Complete adding passkey to existing account |
Invitations
Organization invitation management for onboarding users with specific roles.
Base Path: /api/organizations/{organizationId}/invitationsAuthorization: Administrator role required
| Method | Path | Description |
|---|---|---|
| POST | /api/organizations/{organizationId}/invitations | Send invitation with role (generates 32-byte token, 1-30 day expiry) |
| GET | /api/organizations/{organizationId}/invitations | List invitations (optional status filter: Pending, Accepted, Expired, Revoked) |
| POST | /api/organizations/{organizationId}/invitations/{invitationId}/revoke | Revoke a pending invitation |
Domain Restrictions
Controls which email domains are allowed for OIDC auto-provisioning and self-registration.
Base Path: /api/organizations/{organizationId}/domain-restrictionsAuthorization: Administrator role required
| Method | Path | Description |
|---|---|---|
| GET | /api/organizations/{organizationId}/domain-restrictions | Get allowed email domains and restriction status |
| PUT | /api/organizations/{organizationId}/domain-restrictions | Update allowed domains (empty array disables restrictions) |
Organization Settings
Manage organization type, self-registration, and audit retention configuration.
Base Path: /api/organizations/{orgId}/settingsAuthorization: Administrator role required
| Method | Path | Description |
|---|---|---|
| GET | /api/organizations/{orgId}/settings | Get org type, self-registration status, allowed domains, audit retention |
| PUT | /api/organizations/{orgId}/settings | Update self-registration and audit retention (1-120 months) |
Custom Domain
Configure custom domains with CNAME verification for organization URL resolution.
Base Path: /api/organizations/{organizationId}/custom-domainAuthorization: Administrator role required
| Method | Path | Description |
|---|---|---|
| GET | /api/organizations/{organizationId}/custom-domain | Get custom domain configuration and verification status |
| PUT | /api/organizations/{organizationId}/custom-domain | Configure custom domain (returns CNAME instructions) |
| DELETE | /api/organizations/{organizationId}/custom-domain | Remove custom domain configuration |
| POST | /api/organizations/{organizationId}/custom-domain/verify | Verify custom domain DNS/CNAME resolution |
Audit Log
Query audit events and manage retention policy for the organization.
Base Path: /api/organizations/{organizationId}/audit
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/organizations/{organizationId}/audit | Auditor | Query audit events (filter by date, event type, user; max 200/page) |
| GET | /api/organizations/{organizationId}/audit/retention | Administrator | Get audit retention period (months) |
| PUT | /api/organizations/{organizationId}/audit/retention | Administrator | Update audit retention period (1-120 months) |
Admin Dashboard
Base Path: /api/organizations/{organizationId}/dashboardAuthorization: Administrator role required
| Method | Path | Description |
|---|---|---|
| GET | /api/organizations/{organizationId}/dashboard | Get aggregated stats: user counts, role distribution, recent logins, pending invitations, IDP status |
Organisation Switching
List My Organisations
GET /api/auth/me/organizations
Authorization: Bearer <token>Response (200):
{
"items": [
{
"organizationId": "guid",
"organizationName": "Acme Corp",
"subdomain": "acme-corp",
"role": "Administrator",
"isCurrent": true
}
]
}Switch Organisation
POST /api/auth/switch-org
Authorization: Bearer <token>
Content-Type: application/jsonRequest:
{ "organizationId": "target-org-guid" }Response (200): Returns new TokenResponse scoped to the target organisation.
Platform Settings
Get Platform Settings
GET /api/platform/settings
Authorization: Bearer <system-admin-token>Update Public Org Status
PUT /api/platform/settings/public-org
Authorization: Bearer <system-admin-token>
Content-Type: application/jsonRequest:
{ "enabled": true }Peer Service API
The Peer Service manages P2P networking, system register replication, and peer discovery.
Base Path: /api/peers
Endpoints
1. Get All Peers
GET /api/peersResponse: 200 OK
[
{
"peerId": "peer-123",
"address": "192.168.1.100",
"port": 8080,
"supportedProtocols": ["gRPC", "HTTP"],
"firstSeen": "2025-12-14T10:00:00Z",
"lastSeen": "2025-12-14T17:00:00Z",
"failureCount": 0,
"isBootstrapNode": true,
"averageLatencyMs": 15.5
}
]2. Get Peer by ID
GET /api/peers/{peerId}Response: 200 OK (same structure as single peer above)
3. Get Peer Statistics
GET /api/peers/statsResponse: 200 OK
{
"totalPeers": 10,
"healthyPeers": 8,
"averageLatency": 25.3,
"throughput": 1500,
"networkHealth": "Good"
}4. Get Peer Health
GET /api/peers/healthResponse: 200 OK
{
"totalPeers": 10,
"healthyPeers": 8,
"unhealthyPeers": 2,
"healthPercentage": 80.0,
"peers": [
{
"peerId": "peer-123",
"address": "192.168.1.100",
"port": 8080,
"lastSeen": "2025-12-14T17:00:00Z",
"averageLatencyMs": 15.5
}
]
}Hub Node URLs:
- n0.sorcha.dev - Primary hub node (Priority 0)
- n1.sorcha.dev - Secondary hub node (Priority 1) - Coming soon
- n2.sorcha.dev - Tertiary hub node (Priority 2) - Coming soon
Blueprint Service API
Base Path: /api/blueprints
Endpoints
1. Get All Blueprints
GET /api/blueprintsQuery Parameters:
page(integer): Page number (default: 1)pageSize(integer): Items per page (default: 20, max: 100)search(string): Search in title/descriptionstatus(string): Filter by status
Response: 200 OK
{
"items": [
{
"id": "bp-123",
"title": "Purchase Order Workflow",
"description": "Multi-party purchase order process",
"createdAt": "2025-11-17T10:30:00Z",
"updatedAt": "2025-11-17T10:30:00Z",
"participantCount": 2,
"actionCount": 3
}
],
"page": 1,
"pageSize": 20,
"totalCount": 42,
"totalPages": 3
}2. Get Blueprint by ID
GET /api/blueprints/{id}Headers:
Accept: application/ld+json(optional, for JSON-LD format)
Response: 200 OK
{
"id": "bp-123",
"title": "Purchase Order Workflow",
"description": "Multi-party purchase order process",
"version": "1.0.0",
"participants": [
{
"id": "buyer",
"name": "Buyer Organization",
"organisation": "ORG-001"
},
{
"id": "seller",
"name": "Seller Organization",
"organisation": "ORG-002"
}
],
"actions": [
{
"id": "0",
"title": "Submit Purchase Order",
"description": "Buyer submits PO",
"sender": "buyer",
"data": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"itemName": { "type": "string" },
"quantity": { "type": "integer" },
"unitPrice": { "type": "number" }
},
"required": ["itemName", "quantity", "unitPrice"]
}
}
]
}3. Create Blueprint
POST /api/blueprintsRequest Body:
{
"title": "Invoice Approval Workflow",
"description": "Multi-step invoice approval",
"version": "1.0.0",
"participants": [
{
"id": "submitter",
"name": "Invoice Submitter"
},
{
"id": "approver",
"name": "Finance Approver"
}
],
"actions": [
{
"id": "0",
"title": "Submit Invoice",
"sender": "submitter"
}
]
}Response: 201 Created
{
"id": "bp-456",
"title": "Invoice Approval Workflow",
...
}4. Publish Blueprint
POST /api/blueprints/{id}/publishResponse: 200 OK
{
"isSuccess": true,
"publishedBlueprint": {
"blueprintId": "bp-123",
"version": 1,
"publishedAt": "2025-11-17T11:00:00Z"
},
"errors": []
}Wallet Service API
Base Path: /api/wallets
Endpoints
1. Create Wallet
POST /api/walletsRequest Body:
{
"title": "My Secure Wallet",
"description": "Personal wallet for transactions",
"keyType": "ED25519"
}Key Types:
ED25519: EdDSA using Curve25519 (recommended)NISTP256: ECDSA using NIST P-256RSA: RSA-4096
Response: 201 Created
{
"id": "wallet-789",
"walletAddress": "0x1234567890abcdef",
"title": "My Secure Wallet",
"keyType": "ED25519",
"createdAt": "2025-11-17T12:00:00Z"
}2. Sign Transaction
POST /api/wallets/{id}/signRequest Body:
{
"data": "SGVsbG8gV29ybGQ=", // Base64-encoded data
"algorithm": "ED25519"
}Response: 200 OK
{
"signature": "3045022100...", // Base64-encoded signature
"algorithm": "ED25519",
"timestamp": "2025-11-17T12:05:00Z"
}3. Encrypt Payload
POST /api/wallets/{id}/encryptRequest Body:
{
"data": "Sensitive information to encrypt",
"recipientWalletId": "wallet-999"
}Response: 200 OK
{
"encryptedData": "LS0tLS1CRUdJTi...",
"recipientWalletId": "wallet-999",
"algorithm": "AES-256-GCM"
}4. Decrypt Payload
POST /api/wallets/{id}/decryptRequest Body:
{
"encryptedData": "LS0tLS1CRUdJTi..."
}Response: 200 OK
{
"data": "Decrypted sensitive information",
"timestamp": "2025-11-17T12:10:00Z"
}Register Service API
Base Path: /api/registers
Endpoints
1. Initiate Register Creation
POST /api/registers/initiateAuthorization: Requires CanManageRegisters policy (org_id claim + Administrator or SystemAdmin role). Anonymous access is not permitted.
Request Body:
{
"title": "Production Register",
"description": "Main production ledger",
"purpose": "General"
}purpose(optional):General(default) orSystem. SettingSystemrequires theCanCreateSystemRegisterspolicy (SystemAdmin org + SystemAdmin role).
Response: 201 Created
{
"id": "register-101",
"title": "Production Register",
"purpose": "General",
"createdAt": "2025-11-17T13:00:00Z"
}1b. Finalize Register Creation
POST /api/registers/finalizeAuthorization: Requires authentication. Anonymous access is not permitted.
Response: 200 OK
1c. List Registers
GET /api/registersReturns only registers the caller's organization is subscribed to, plus system registers. Scope is derived from the org_id JWT claim. The tenantId query parameter has been removed.
Response: 200 OK
{
"items": [
{
"id": "register-101",
"title": "Production Register",
"purpose": "General",
"createdAt": "2025-11-17T13:00:00Z"
}
]
}1d. Delete Register
DELETE /api/registers/{id}Authorization is based on control record attestations: the wallet_address JWT claim is matched against Owner/Admin attestations on the register. System registers cannot be deleted. The tenantId query parameter has been removed.
Response: 204 No Content
#### 2. Submit Transaction
```http
POST /api/registers/{id}/transactionsRequest Body:
{
"transactionType": "Action",
"senderAddress": "wallet-789",
"payload": "eyJkYXRhIjoid...", // Base64-encoded
"metadata": {
"blueprintId": "bp-123",
"actionId": "0"
}
}Response: 202 Accepted
{
"transactionId": "tx-abc123",
"status": "pending",
"timestamp": "2025-11-17T13:05:00Z"
}3. Get Transaction
GET /api/registers/{id}/transactions/{txId}Response: 200 OK
{
"transactionId": "tx-abc123",
"transactionType": "Action",
"senderAddress": "wallet-789",
"timestamp": "2025-11-17T13:05:00Z",
"docketId": "docket-001",
"status": "confirmed"
}4. Query Transactions
GET /api/registers/{id}/transactionsQuery Parameters:
senderAddress(string): Filter by senderstartTime(ISO 8601): Start of time rangeendTime(ISO 8601): End of time rangepage(integer): Page numberpageSize(integer): Items per page$filter(OData): OData V4 filter expression
Example:
GET /api/registers/reg-101/transactions?senderAddress=wallet-789&startTime=2025-11-17T00:00:00ZResponse: 200 OK
{
"items": [...],
"page": 1,
"totalCount": 150
}5. Transaction Graph (Register Map)
GET /api/registers/{registerId}/transactions/graphReturns a lightweight transaction graph for DAG visualization in the Transaction Explorer UI.
Query Parameters:
limit(int, default 200, max 1000) — maximum nodes to returnbefore(string, optional) — cursor TxId for pagination
Response: 200 OK
{
"nodes": [
{
"txId": "tx-abc123",
"prevTxId": "tx-abc122",
"senderWallet": "wallet-789",
"timeStamp": "2025-11-17T13:05:00Z",
"docketNumber": 1,
"blueprintId": "bp-123",
"instanceId": "inst-456",
"transactionType": "Action"
}
],
"totalCount": 150,
"hasMore": true
}6. Seal Docket (Create Block)
POST /api/registers/{id}/dockets/sealResponse: 201 Created
{
"docketId": "docket-002",
"previousHash": "0000abc123...",
"merkleRoot": "def456...",
"transactionCount": 25,
"timestamp": "2025-11-17T14:00:00Z"
}6. Register Policy API (Feature 048)
Get Register Policy
GET /api/registers/{registerId}/policyResponse: 200 OK
{
"registerId": "aabbccdd11223344aabbccdd11223344",
"policy": {
"version": 1,
"governance": { "quorumFormula": "strict-majority", "proposalTtlDays": 7 },
"validators": { "registrationMode": "public", "minValidators": 1, "maxValidators": 100, "operationalTtlSeconds": 60 },
"consensus": { "signatureThresholdMin": 2, "signatureThresholdMax": 10, "maxTransactionsPerDocket": 1000 },
"leaderElection": { "mechanism": "rotating", "heartbeatIntervalMs": 1000, "leaderTimeoutMs": 5000 }
},
"isDefault": false
}Propose Policy Update
POST /api/registers/{registerId}/policy/updateRequest Body:
{
"policy": { "version": 2, "governance": { "quorumFormula": "supermajority" }, "..." : "..." },
"updatedBy": "did:sorcha:w:addr123",
"transitionMode": "immediate"
}Response: 202 Accepted
{
"txId": "aabbcc...64hex",
"registerId": "aabbccdd11223344aabbccdd11223344",
"newVersion": 2,
"status": "submitted"
}Get Policy History
GET /api/registers/{registerId}/policy/history?page=1&pageSize=20List Approved Validators
GET /api/registers/{registerId}/validators/approvedResponse: 200 OK
{
"registerId": "aabbccdd11223344aabbccdd11223344",
"registrationMode": "consent",
"validators": [
{ "did": "did:sorcha:w:validator1", "publicKey": "base64...", "approvedAt": "2026-03-01T00:00:00Z" }
],
"count": 1
}List Operational Validators
GET /api/registers/{registerId}/validators/operationalResponse: 200 OK
{
"registerId": "aabbccdd11223344aabbccdd11223344",
"validators": [
{ "validatorId": "val-001", "did": "did:sorcha:w:validator1", "status": "active", "ttlRemainingSeconds": 45 }
],
"count": 1
}7. System Register API (Feature 048)
Get System Register
GET /api/system-registerResponse: 200 OK
{
"registerId": "00000000000000000000000000000001",
"name": "Sorcha System Register",
"status": "online",
"blueprintCount": 1,
"createdAt": "2026-03-01T00:00:00Z"
}List System Blueprints
GET /api/system-register/blueprints?page=1&pageSize=20Get System Blueprint
GET /api/system-register/blueprints/{blueprintId}Get System Blueprint Version
GET /api/system-register/blueprints/{blueprintId}/versions/{version}6. Query Blueprint Version History (Feature 059)
Returns semantic version history for a published blueprint.
GET /api/system-register/blueprints/{blueprintId}/versionsResponse: 200 OK — Array of version entries with major, minor, changeType (structural/documentation), structuralHash, publishedAt, publishedBy, transactionId.
7. Classify Blueprint Change (Feature 059)
Compares a new blueprint against the latest published version to determine change type.
POST /api/system-register/blueprints/{blueprintId}/classify-change
Content-Type: application/json
{ "newBlueprint": { /* full blueprint JSON */ } }Response: 200 OK — changeType, currentVersion, proposedVersion, structuralHashCurrent, structuralHashNew, structuralFieldsChanged.
Action Workflow API
Base Path: /api/actions
Endpoints
1. Get Available Blueprints
GET /api/actions/{walletAddress}/{registerAddress}/blueprintsResponse: 200 OK
{
"walletAddress": "wallet-789",
"registerAddress": "register-101",
"blueprints": [
{
"blueprintId": "bp-123",
"title": "Purchase Order Workflow",
"version": 1,
"availableActions": [
{
"actionId": "0",
"title": "Submit Purchase Order",
"isAvailable": true
}
]
}
]
}2. Submit Action
POST /api/actionsRequest Body:
{
"blueprintId": "bp-123",
"actionId": "0",
"instanceId": "instance-abc", // Optional, auto-generated if omitted
"senderWallet": "wallet-789",
"registerAddress": "register-101",
"previousTransactionHash": null, // For first action
"payloadData": {
"itemName": "Widget Pro",
"quantity": 100,
"unitPrice": 49.99
},
"files": [ // Optional file attachments
{
"fileName": "invoice.pdf",
"contentType": "application/pdf",
"contentBase64": "JVBERi0xLjQK..."
}
]
}Response: 200 OK
{
"transactionHash": "0xabc123def456",
"instanceId": "instance-abc",
"serializedTransaction": "{...}",
"fileTransactionHashes": ["0xfile001", "0xfile002"],
"timestamp": "2025-11-17T15:00:00Z"
}3. Get Action Details
GET /api/actions/{walletAddress}/{registerAddress}/{transactionHash}Response: 200 OK
{
"transactionHash": "0xabc123def456",
"blueprintId": "bp-123",
"actionId": "0",
"instanceId": "instance-abc",
"senderWallet": "wallet-789",
"registerAddress": "register-101",
"payloadData": {...},
"timestamp": "2025-11-17T15:00:00Z"
}Execution Helper API
Base Path: /api/execution
Client-side helpers for validating and processing actions before submission.
Endpoints
1. Validate Action Data
POST /api/execution/validateRequest Body:
{
"blueprintId": "bp-123",
"actionId": "0",
"data": {
"itemName": "Widget Pro",
"quantity": 100,
"unitPrice": 49.99
}
}Response: 200 OK
{
"isValid": true,
"errors": []
}2. Apply Calculations
POST /api/execution/calculateRequest Body:
{
"blueprintId": "bp-123",
"actionId": "0",
"data": {
"quantity": 100,
"unitPrice": 49.99
}
}Response: 200 OK
{
"processedData": {
"quantity": 100,
"unitPrice": 49.99,
"totalPrice": 4999.00 // Calculated field
},
"calculatedFields": ["totalPrice"]
}3. Determine Routing
POST /api/execution/routeRequest Body:
{
"blueprintId": "bp-123",
"actionId": "0",
"data": {
"amount": 75000
}
}Response: 200 OK
{
"nextActionId": "2",
"nextParticipantId": "director",
"isWorkflowComplete": false,
"matchedCondition": "amount > 50000"
}4. Apply Disclosure Rules
POST /api/execution/discloseRequest Body:
{
"blueprintId": "bp-123",
"actionId": "0",
"data": {
"itemName": "Widget Pro",
"quantity": 100,
"unitPrice": 49.99,
"internalNotes": "Confidential"
}
}Response: 200 OK
{
"disclosures": [
{
"participantId": "seller",
"disclosedData": {
"itemName": "Widget Pro",
"quantity": 100,
"unitPrice": 49.99
// "internalNotes" not disclosed to seller
},
"fieldCount": 3
}
]
}Encrypted Action Flow
Async Encryption Pipeline
When an action has disclosure rules with encryption, the submission returns 202 Accepted with an operation ID for tracking progress.
Submit Encrypted Action
POST /api/actionsRequest Body (same as standard action, encryption is automatic when blueprint has disclosure rules):
{
"blueprintId": "bp-123",
"actionId": "0",
"senderWallet": "wallet-789",
"registerAddress": "register-101",
"payloadData": { "itemName": "Widget Pro", "quantity": 100 },
"externalRecipientKeys": {
"wallet-abc": { "publicKey": "base64...", "algorithm": "ED25519" }
}
}Response: 202 Accepted
{
"operationId": "op-uuid-123",
"isAsync": true,
"instanceId": "instance-abc"
}Poll Operation Status
GET /api/operations/{operationId}
Authorization: Bearer {token}Response: 200 OK
{
"operationId": "op-uuid-123",
"status": "Encrypting",
"currentStep": 2,
"totalSteps": 4,
"stepName": "Encrypting payloads",
"percentComplete": 30,
"transactionHash": null,
"error": null,
"createdAt": "2026-03-02T10:00:00Z"
}Status values: Pending, ResolvingKeys, Encrypting, BuildingTransaction, Submitting, Complete, Failed
List Operations (Feature 052)
GET /api/operations?wallet={walletAddress}&page={page}&pageSize={pageSize}
Authorization: Bearer {token}Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
wallet | string | required | Wallet address to filter operations |
page | int | 1 | Page number (1-based) |
pageSize | int | 10 | Items per page (max 50) |
Response: 200 OK
{
"items": [
{
"operationId": "op-uuid-123",
"status": "complete",
"blueprintId": "bp-001",
"actionTitle": "Submit Disclosure",
"instanceId": "inst-001",
"walletAddress": "did:sorcha:w:abc123",
"recipientCount": 3,
"transactionHash": "a1b2c3...",
"errorMessage": null,
"createdAt": "2026-03-02T10:00:00Z",
"completedAt": "2026-03-02T10:00:15Z"
}
],
"page": 1,
"pageSize": 10,
"totalCount": 25,
"hasMore": true
}Authorization: JWT wallet_address claim must match the requested wallet address (403 if mismatch).
Batch Public Key Resolution
POST /api/registers/{registerId}/participants/resolve-public-keys
Authorization: Bearer {token}
Content-Type: application/json
{
"walletAddresses": ["wallet-abc", "wallet-def"],
"algorithm": "ED25519"
}Response: 200 OK
{
"resolved": {
"wallet-abc": {
"participantId": "part-1",
"walletAddress": "wallet-abc",
"publicKey": "base64...",
"algorithm": "ED25519",
"status": "Active"
}
},
"notFound": ["wallet-xyz"],
"revoked": []
}Real-time Notifications (SignalR)
Hub Endpoint: /actionshub
Events
1. Subscribe to Actions
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5000/actionshub")
.build();
// Subscribe to actions for specific wallet/register
await connection.invoke("SubscribeToActions", "wallet-789", "register-101");
// Listen for action confirmed events
connection.on("ActionConfirmed", (notification) => {
console.log("Action confirmed:", notification);
});2. Notification Format
{
"transactionHash": "0xabc123def456",
"walletAddress": "wallet-789",
"registerAddress": "register-101",
"blueprintId": "bp-123",
"actionId": "0",
"instanceId": "instance-abc",
"timestamp": "2025-11-17T16:00:00Z",
"message": "Transaction confirmed"
}Error Handling
Standard Error Response
{
"error": "Invalid blueprint ID",
"code": "BLUEPRINT_NOT_FOUND",
"timestamp": "2025-11-17T17:00:00Z",
"path": "/api/blueprints/invalid-id"
}Common Error Codes
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST | Malformed request body |
| 401 | UNAUTHORIZED | Authentication required |
| 403 | FORBIDDEN | Insufficient permissions |
| 404 | NOT_FOUND | Resource not found |
| 409 | CONFLICT | Resource conflict |
| 429 | RATE_LIMITED | Too many requests |
| 500 | INTERNAL_ERROR | Server error |
| 503 | SERVICE_UNAVAILABLE | Service temporarily unavailable |
Rate Limiting
Current Status: Not enforced in MVP
Future Implementation:
- 100 requests per minute per client
- 1000 requests per hour per client
- Burst allowance: 20 requests
Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1700000000Code Examples
Complete Workflow Example (C#)
using System.Net.Http.Json;
var client = new HttpClient { BaseAddress = new Uri("http://localhost:5000") };
// 1. Create wallet
var walletResponse = await client.PostAsJsonAsync("/api/wallets", new
{
title = "My Wallet",
keyType = "ED25519"
});
var wallet = await walletResponse.Content.ReadFromJsonAsync<dynamic>();
var walletId = wallet.id;
// 2. Create register
var registerResponse = await client.PostAsJsonAsync("/api/registers", new
{
title = "My Register"
});
var register = await registerResponse.Content.ReadFromJsonAsync<dynamic>();
var registerId = register.id;
// 3. Create and publish blueprint
var blueprint = new
{
title = "Simple Workflow",
participants = new[] { new { id = "p1", name = "Participant 1" } },
actions = new[] { new { id = "0", title = "Action 1", sender = "p1" } }
};
var bpResponse = await client.PostAsJsonAsync("/api/blueprints", blueprint);
var bp = await bpResponse.Content.ReadFromJsonAsync<dynamic>();
await client.PostAsync($"/api/blueprints/{bp.id}/publish", null);
// 4. Submit action
var action = new
{
blueprintId = bp.id,
actionId = "0",
senderWallet = walletId,
registerAddress = registerId,
payloadData = new { message = "Hello World" }
};
var actionResponse = await client.PostAsJsonAsync("/api/actions", action);
var result = await actionResponse.Content.ReadFromJsonAsync<dynamic>();
Console.WriteLine($"Transaction Hash: {result.transactionHash}");SignalR Real-time Notifications (JavaScript)
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5000/actionshub")
.withAutomaticReconnect()
.build();
// Handle disconnection
connection.onclose(async () => {
console.log("Connection closed. Attempting to reconnect...");
});
// Subscribe to actions
await connection.start();
await connection.invoke("SubscribeToActions", "wallet-789", "register-101");
// Listen for notifications
connection.on("ActionConfirmed", (notification) => {
console.log("Action confirmed:", notification);
updateUI(notification);
});
connection.on("ActionPending", (notification) => {
console.log("Action pending:", notification);
});
// Encryption progress events (sent to wallet:{address} group)
connection.on("EncryptionProgress", (notification) => {
console.log(`Step ${notification.step}/${notification.totalSteps}: ${notification.stepName} (${notification.percentComplete}%)`);
});
connection.on("EncryptionComplete", (notification) => {
console.log("Encryption complete, tx:", notification.transactionHash);
});
connection.on("EncryptionFailed", (notification) => {
console.error("Encryption failed:", notification.error);
});API Versioning
Current Version: v1 (implicit)
Future Versioning Strategy:
- URL-based:
/api/v2/blueprints - Header-based:
X-API-Version: 2
Support and Resources
- GitHub: https://github.com/yourusername/Sorcha
- Documentation: https://docs.sorcha.io
- API Explorer: http://localhost:5000/scalar/v1
Last Updated: 2026-03-16 Document Version: 2.2.0 Feature: 058 - Platform Organisation Topology