{ "openapi": "3.0.0", "info": { "title": "Recover for Institutions API", "description": "Direct integration for institutions backing up their own digital asset wallets. Uses the standard /v1/* endpoints: organisation and package are optional, and key_environment selects HOT (online) or COLD (offline) generation and storage. HOT vs COLD is a request parameter, not a URL path segment. Self-service verification endpoints are available for keys and backups. Key generation and storage use AWS Nitro Enclaves for hardware-isolated cryptographic operations.", "version": "1.0.0" }, "servers": [ { "url": "https://service.uat-keys.coincover.com", "description": "Sandbox (UAT)" }, { "url": "https://service.keys.coincover.com", "description": "Production — confirm host with your account manager" } ], "security": [ { "bearerAuth": [] } ], "tags": [ { "name": "Keys", "description": "Generate, assign, and verify cryptographic keys." }, { "name": "Backups", "description": "Store and verify encrypted backup data and files." } ], "paths": { "/v1/keys": { "post": { "summary": "Assign a new key", "description": "Creates a new key pair with the enclave, shards the private key, and securely stores the encrypted key shards. organisation and package are optional; key_environment defaults to HOT if omitted.", "operationId": "assignKey", "tags": ["Keys"], "parameters": [ { "name": "Authorization", "in": "header", "description": "Bearer token for authentication. Can be either a JWT token or API key.", "required": true, "schema": { "$ref": "#/components/schemas/Authorization" } } ], "requestBody": { "description": "Key assignment details", "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignKeyRequest" } } } }, "responses": { "200": { "description": "Key successfully assigned", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignKeyResponse" } } } }, "400": { "description": "Invalid request parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/v1/keys/{keyId}/verify": { "get": { "summary": "Verify a key's integrity", "description": "Verifies that a key's shards can be reconstructed and that the key pair is valid.", "operationId": "verifyKey", "tags": ["Keys"], "parameters": [ { "name": "keyId", "in": "path", "description": "ID of the key to verify", "required": true, "schema": { "$ref": "#/components/schemas/keyId" } }, { "name": "Authorization", "in": "header", "description": "Bearer token for authentication. Can be either a JWT token or API key.", "required": true, "schema": { "$ref": "#/components/schemas/Authorization" } } ], "responses": { "200": { "description": "Key verification result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VerifyKeyResponse" } } } }, "400": { "description": "Invalid request parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Key not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/v1/secure/data": { "post": { "summary": "Store secure encrypted data", "description": "Stores base64-encoded encrypted data with optional checksum validation and padding type specification. The data is verified using the enclave before storage. Supplying the SHA-256 of the plaintext as the checksum is recommended.", "operationId": "storeSecureData", "tags": ["Backups"], "parameters": [ { "name": "Authorization", "in": "header", "description": "Bearer token for authentication. Can be either a JWT token or API key.", "required": true, "schema": { "$ref": "#/components/schemas/Authorization" } } ], "requestBody": { "description": "Secure data and metadata", "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SecureDataRequest" } } } }, "responses": { "200": { "description": "Secure data successfully stored", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SecureDataResponse" } } } }, "400": { "description": "Invalid request parameters or verification failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Key or user not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/v1/secure/file": { "post": { "summary": "Store secure encrypted files", "description": "Stores an already-encrypted file. CoinCover applies no additional server-side encryption.", "operationId": "storeSecureFile", "tags": ["Backups"], "parameters": [ { "name": "Authorization", "in": "header", "description": "Bearer token for authentication. Can be either a JWT token or API key.", "required": true, "schema": { "$ref": "#/components/schemas/Authorization" } } ], "requestBody": { "description": "Secure file and metadata", "required": true, "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/SecureFileRequest" } } } }, "responses": { "200": { "description": "Secure file successfully stored", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SecureFileResponse" } } } }, "400": { "description": "Invalid request parameters or verification failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } }, "/v1/backups/{backupId}/verify": { "get": { "summary": "Verify a backup's integrity", "description": "Verifies that a backup is valid by checking the encrypted data.", "operationId": "verifyBackup", "tags": ["Backups"], "parameters": [ { "name": "backupId", "in": "path", "description": "ID of the backup to verify", "required": true, "schema": { "$ref": "#/components/schemas/backupId" } }, { "name": "Authorization", "in": "header", "description": "Bearer token for authentication. Can be either a JWT token or API key.", "required": true, "schema": { "$ref": "#/components/schemas/Authorization" } } ], "responses": { "200": { "description": "Backup verification result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VerifyBackupResponse" } } } }, "400": { "description": "Invalid request parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "404": { "description": "Backup not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } } } } }, "components": { "schemas": { "AssignKeyRequest": { "type": "object", "required": [ "user_identifier", "key_type" ], "properties": { "user_identifier": { "type": "string", "description": "Unique identifier of the user" }, "key_type": { "type": "string", "enum": [ "rsa4096", "secp256k1", "ed25519" ], "description": "Type of cryptographic key to generate. rsa4096 for encrypting recovery material; secp256k1 or ed25519 for a blockchain backup signer." }, "key_environment": { "type": "string", "enum": [ "HOT", "COLD" ], "default": "HOT", "description": "Key environment specification - HOT (online generation) or COLD (offline generation)" }, "organisation": { "type": "object", "description": "Optional organisation metadata", "properties": { "customer_id": { "type": "string", "description": "Unique identifier for the organisation" }, "customer_name": { "type": "string", "description": "Name of the organisation customer" } } }, "package": { "type": "object", "description": "Optional package metadata", "properties": { "package_id": { "type": "string", "description": "External package ID assigned to the key" }, "package_name": { "type": "string", "description": "Name of the package" } } }, "sign_with": { "type": "array", "description": "Optional list of context fields to bind into the enclave signature. When present, the enclave signs a JCS-canonical (RFC 8785) JSON payload built from these fields plus the public_key (always included), returned as signed_payload, so a verified signature attests to the business context the key was issued for — not just the key bytes. Do not list public_key here; it is included implicitly.", "items": { "type": "string", "enum": [ "external_customer_id", "external_package_id", "pulled_by_id", "pulled_by_type", "user_id", "key_id", "key_fingerprint" ] } } } }, "AssignKeyResponse": { "type": "object", "properties": { "key_id": { "type": "string", "format": "uuid", "description": "Unique identifier for the key" }, "public_key": { "type": "string", "description": "Public key in hex format. For rsa4096 this is the encryption public key; for secp256k1 or ed25519 this is the compressed public key." }, "signature": { "type": "string", "description": "Signature of the key in base64 format, produced by the generating enclave. Verify against CoinCover's published JWKS before relying on the key. When sign_with is supplied the signature is computed over signed_payload; otherwise it covers the public key." }, "signed_payload": { "type": "string", "description": "JCS-canonical (RFC 8785) JSON string that was signed — object keys sorted, always including public_key alongside the requested context fields. Returned only when sign_with was supplied. Verify the signature over these exact bytes rather than a re-serialised copy." }, "signed_fields": { "type": "array", "description": "The sign_with field names that were included, in the order requested (public_key is not listed). Confirm this contains every field you expected before trusting the binding.", "items": { "type": "string" } }, "customer_id": { "type": "string", "nullable": true, "description": "External customer identifier (e.g. organisation customer ID)" }, "package_id": { "type": "string", "nullable": true, "description": "External package identifier (e.g. workspace/package ID)" }, "metadata": { "type": "object", "description": "Optional metadata describing the associated organisation and package", "properties": { "customer_name": { "type": "string", "nullable": true, "description": "Human-readable name of the customer or organisation" }, "package_name": { "type": "string", "nullable": true, "description": "Human-readable name of the associated package or workspace" } } } } }, "SecureDataRequest": { "type": "object", "required": [ "public_key", "data" ], "properties": { "public_key": { "type": "string", "pattern": "^[0-9a-fA-F]+$", "minLength": 32, "maxLength": 4096, "description": "Public key in hex format used to encrypt the data" }, "checksum": { "type": "string", "pattern": "^[a-fA-F0-9]{64}$", "description": "SHA-256 checksum of the original plaintext for verification (optional but recommended)" }, "data": { "type": "string", "format": "base64", "description": "Base64-encoded encrypted data" }, "padding_type": { "type": "string", "enum": [ "OAEP" ], "default": "OAEP", "description": "Padding type used for encryption" }, "metadata": { "type": "object", "description": "Optional metadata about the data", "properties": { "description": { "type": "string", "description": "Human-readable description of the data" }, "content_type": { "type": "string", "description": "MIME type of the original data" }, "original_filename": { "type": "string", "description": "Original filename of the data" } } } } }, "SecureDataResponse": { "type": "object", "properties": { "backup_id": { "type": "string", "format": "uuid", "description": "Unique identifier for the stored backup" }, "checksum": { "type": "string", "description": "SHA-256 checksum that was verified" }, "data_size": { "type": "integer", "description": "Size of the encrypted data in bytes" }, "backup_type": { "type": "string", "enum": [ "data" ], "description": "Type of backup (always 'data' for secure-data endpoint)" }, "metadata": { "type": "object", "description": "Combined metadata including original metadata" } } }, "SecureFileRequest": { "type": "object", "required": [ "public_key", "file" ], "properties": { "public_key": { "type": "string", "pattern": "^[0-9a-fA-F]+$", "minLength": 32, "maxLength": 4096, "description": "Public key in hex format used to encrypt the file" }, "file": { "type": "string", "format": "binary", "description": "Encrypted file to upload (e.g. a ZIP archive)" }, "metadata": { "type": "object", "description": "Optional metadata about the file", "properties": { "description": { "type": "string", "description": "Human-readable description of the file" }, "content_type": { "type": "string", "description": "MIME type of the original file" }, "original_filename": { "type": "string", "description": "Original filename of the file" } } } } }, "SecureFileResponse": { "type": "object", "properties": { "backup_id": { "type": "string", "format": "uuid", "description": "Unique identifier for the stored file" }, "backup_type": { "type": "string", "enum": [ "file" ], "description": "Type of backup (always 'file' for secure-file endpoint)" }, "metadata": { "type": "object", "description": "Combined metadata including original metadata" } } }, "VerifyKeyResponse": { "type": "object", "properties": { "message": { "type": "string", "description": "Verification status message" }, "is_key_valid": { "type": "boolean", "description": "Whether the key is valid and can be used" } } }, "VerifyBackupResponse": { "type": "object", "properties": { "is_backup_valid": { "type": "boolean", "description": "Whether the backup is valid and can be recovered" }, "message": { "type": "string", "description": "Message indicating the verification result" } } }, "ErrorResponse": { "type": "object", "properties": { "message": { "type": "string", "description": "Error message" }, "error": { "type": "string", "description": "Error type" } } }, "Authorization": { "type": "string" }, "keyId": { "type": "string", "format": "uuid" }, "backupId": { "type": "string", "format": "uuid" } }, "securitySchemes": { "bearerAuth": { "description": "Bearer token authentication. Can be either a JWT token or API key.", "type": "http", "scheme": "bearer" } } } }