Skip to main content

Version: 1.0 | Last Updated: April 2026 | Status: Draft

BYOK API Reference

Complete API reference for ASCEND BYOK/CMK encryption endpoints.

Authentication

All BYOK endpoints require a valid Bearer token. The authenticated user's ID (from the JWT sub claim) is used as the rate limit key.

Authorization: Bearer <your_jwt_token>

Base URL

https://pilot.owkai.app/api/v1/byok

Register Encryption Key

Register your AWS KMS Customer Managed Key with ASCEND.

POST /api/v1/byok/keys

Request Body

FieldTypeRequiredDescriptionValidation
cmk_arnstringYesFull ARN of your AWS KMS keyMust match arn:aws:kms:<region>:<account>:key/<key-id>
cmk_aliasstringNoFriendly alias for the keyNone

Example Request

curl -X POST https://pilot.owkai.app/api/v1/byok/keys \
-H "Authorization: Bearer $ASCEND_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"cmk_arn": "arn:aws:kms:us-east-2:<YOUR_AWS_ACCOUNT_ID>:key/12345678-1234-1234-1234-123456789012",
"cmk_alias": "ascend-production-key"
}'

Response (201 Created)

Returns KeyStatusResponse:

{
"organization_id": 4,
"cmk_arn": "arn:aws:kms:us-east-2:<YOUR_AWS_ACCOUNT_ID>:key/12345678-1234-1234-1234-123456789012",
"cmk_alias": "ascend-production-key",
"status": "active",
"status_reason": "Key validated successfully",
"last_validated_at": "2026-04-02T10:30:00Z",
"last_rotation_at": null,
"created_at": "2026-04-02T10:30:00Z"
}

Response Fields

FieldTypeDescription
organization_idintOrganization that owns this key
cmk_arnstringFull ARN of the registered CMK
cmk_aliasstring or nullFriendly alias
statusstringKey status: active, pending_waiver, disabled, revoked
status_reasonstring or nullHuman-readable status explanation
last_validated_atdatetime or nullLast successful CMK access validation
last_rotation_atdatetime or nullLast DEK rotation timestamp
created_atdatetimeRegistration timestamp

Errors

Error CodeHTTP StatusWhen
BYOK_001400cmk_arn does not match expected ARN format
BYOK_002403ASCEND cannot access the CMK (check key policy)
BYOK_003409Organization already has a registered key

Get Key Status

Get the current status of your registered encryption key.

GET /api/v1/byok/keys

Example Request

curl https://pilot.owkai.app/api/v1/byok/keys \
-H "Authorization: Bearer $ASCEND_TOKEN"

Response (200 OK)

Returns KeyStatusResponse if BYOK is configured, or null if no key is registered.

{
"organization_id": 4,
"cmk_arn": "arn:aws:kms:us-east-2:<YOUR_AWS_ACCOUNT_ID>:key/12345678-1234-1234-1234-123456789012",
"cmk_alias": "ascend-production-key",
"status": "active",
"status_reason": "Key validated successfully",
"last_validated_at": "2026-04-02T11:00:00Z",
"last_rotation_at": "2026-04-02T10:45:00Z",
"created_at": "2026-04-02T10:30:00Z"
}

See Register Encryption Key for field descriptions.


Revoke Encryption Key

Remove your BYOK key. The key record is marked as revoked (not deleted) to preserve the audit trail.

DELETE /api/v1/byok/keys

Example Request

curl -X DELETE https://pilot.owkai.app/api/v1/byok/keys \
-H "Authorization: Bearer $ASCEND_TOKEN"

Response (200 OK)

{
"status": "revoked",
"message": "Encryption key has been revoked"
}

Errors

Error CodeHTTP StatusWhen
BYOK_005404No key registered for this organization

Rotate Data Encryption Key

Trigger rotation of the Data Encryption Key (DEK) wrapped by your CMK. This generates a new DEK; old DEKs are kept for decrypting existing data. This does not rotate the CMK itself.

POST /api/v1/byok/keys/rotate

This endpoint takes no request body.

Example Request

curl -X POST https://pilot.owkai.app/api/v1/byok/keys/rotate \
-H "Authorization: Bearer $ASCEND_TOKEN"

Response (200 OK)

Returns KeyRotationResponse:

{
"success": true,
"message": "DEK rotated to version 3",
"new_dek_version": 3,
"rotated_at": "2026-04-02T10:45:00Z"
}

Response Fields

FieldTypeDescription
successboolWhether rotation completed
messagestringHuman-readable result
new_dek_versionint or nullNew DEK version number
rotated_atdatetimeRotation timestamp

Errors

Error CodeHTTP StatusWhen
BYOK_002403Key status is not active (cannot rotate)
BYOK_005404No key registered for this organization
BYOK_006503Cannot access CMK for rotation

Health Check

Check the health status of your BYOK configuration.

GET /api/v1/byok/health

Example Request

curl https://pilot.owkai.app/api/v1/byok/health \
-H "Authorization: Bearer $ASCEND_TOKEN"

Response (200 OK) — BYOK Enabled

Returns KeyHealthResponse:

{
"byok_enabled": true,
"status": "active",
"cmk_accessible": true,
"last_validated_at": "2026-04-02T11:00:00Z",
"cmk_arn_prefix": "arn:aws:kms:us-east-2:<YOUR_AWS_AC...",
"dek_version": 3
}

Response (200 OK) — BYOK Not Configured

{
"byok_enabled": false,
"status": null,
"cmk_accessible": null,
"last_validated_at": null,
"cmk_arn_prefix": null,
"dek_version": null
}

Response Fields

FieldTypeDescription
byok_enabledboolWhether BYOK is configured for this organization
statusstring or nullKey status from database
cmk_accessiblebool or nullWhether ASCEND can currently access the CMK
last_validated_atdatetime or nullLast successful validation timestamp
cmk_arn_prefixstring or nullFirst 40 characters of CMK ARN (masked for security)
dek_versionint or nullCurrent DEK version number

Get Audit Log

Retrieve BYOK operation audit log.

GET /api/v1/byok/audit

Query Parameters

ParameterTypeDefaultMaxDescription
limitint50500Number of entries to return
offsetint0Pagination offset

Example Request

curl "https://pilot.owkai.app/api/v1/byok/audit?limit=50&offset=0" \
-H "Authorization: Bearer $ASCEND_TOKEN"

Response (200 OK)

Returns BYOKAuditResponse:

{
"entries": [
{
"id": 42,
"operation": "key_rotated",
"success": true,
"error_message": null,
"created_at": "2026-04-02T10:45:00Z"
},
{
"id": 41,
"operation": "health_check",
"success": true,
"error_message": null,
"created_at": "2026-04-02T10:30:00Z"
}
],
"total_count": 42
}

Audit Entry Fields

FieldTypeDescription
idintUnique audit entry ID
operationstringOperation type (see below)
successboolWhether the operation succeeded
error_messagestring or nullError detail if operation failed
created_atdatetimeWhen the operation occurred

Operation Types

OperationDescription
key_registeredCMK registration
key_revokedCMK revocation
key_rotatedDEK rotation
health_checkHealth check performed
legal_waiver_acknowledgedLegal waiver acknowledged

Pagination

FieldTypeDescription
entriesarrayAudit entries for this page
total_countintTotal entries across all pages

Retrieve the legal waiver text that must be acknowledged before BYOK activation.

GET /api/v1/byok/legal-waiver

Example Request

curl https://pilot.owkai.app/api/v1/byok/legal-waiver \
-H "Authorization: Bearer $ASCEND_TOKEN"

Response (200 OK)

{
"waiver_text": "## BYOK Data Sovereignty Acknowledgment\n\nBy enabling Bring Your Own Key (BYOK) encryption, you acknowledge:\n\n1. **Key Control**: You have sole control over your AWS KMS Customer Managed Key (CMK).\n\n2. **Permanent Data Loss Risk**: If you delete your CMK or revoke ASCEND's access without first disabling BYOK and exporting your data, YOUR DATA WILL BE PERMANENTLY UNRECOVERABLE...",
"required_acknowledgments": [
{
"field": "acknowledge_data_loss_risk",
"description": "I acknowledge the permanent data loss risk"
},
{
"field": "acknowledge_key_management_responsibility",
"description": "I accept responsibility for CMK management"
},
{
"field": "acknowledge_no_liability",
"description": "I understand OW-KAI is not liable for key mismanagement"
}
]
}

Response Fields

FieldTypeDescription
waiver_textstringFull waiver text in Markdown format
required_acknowledgmentsarrayList of fields that must be set to true in the acknowledge request
required_acknowledgments[].fieldstringField name for the POST request body
required_acknowledgments[].descriptionstringHuman-readable description of the acknowledgment

Acknowledge the legal waiver to activate BYOK encryption. All three acknowledgments must be true.

POST /api/v1/byok/legal-waiver

Request Body

FieldTypeRequiredDescription
acknowledge_data_loss_riskboolYesMust be true
acknowledge_key_management_responsibilityboolYesMust be true
acknowledge_no_liabilityboolYesMust be true

Example Request

curl -X POST https://pilot.owkai.app/api/v1/byok/legal-waiver \
-H "Authorization: Bearer $ASCEND_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"acknowledge_data_loss_risk": true,
"acknowledge_key_management_responsibility": true,
"acknowledge_no_liability": true
}'

Response (200 OK)

Returns LegalAcknowledgmentResponse:

{
"acknowledged": true,
"acknowledged_at": "2026-04-02T10:35:00Z",
"acknowledged_by_user_id": 15,
"message": "Legal waiver acknowledged. BYOK encryption is now fully enabled."
}

Response Fields

FieldTypeDescription
acknowledgedboolAlways true on success
acknowledged_atdatetimeWhen the waiver was acknowledged
acknowledged_by_user_idintUser ID of the person who acknowledged
messagestringConfirmation message

Errors

Error CodeHTTP StatusWhen
BYOK_004400Not all acknowledgments were set to true
BYOK_005404No BYOK key registered (register a key first)

Get Waiver Status

Check if the legal waiver has been acknowledged.

GET /api/v1/byok/legal-waiver/status

Example Request

curl https://pilot.owkai.app/api/v1/byok/legal-waiver/status \
-H "Authorization: Bearer $ASCEND_TOKEN"

Response (200 OK) — Acknowledged

{
"byok_configured": true,
"waiver_acknowledged": true,
"acknowledged_at": "2026-04-02T10:35:00Z",
"acknowledged_by_user_id": 15
}

Response (200 OK) — No BYOK Key

{
"byok_configured": false,
"waiver_acknowledged": false,
"acknowledged_at": null,
"acknowledged_by_user_id": null
}

Response Fields

FieldTypeDescription
byok_configuredboolWhether a BYOK key is registered
waiver_acknowledgedboolWhether the legal waiver has been acknowledged
acknowledged_atdatetime or nullWhen the waiver was acknowledged
acknowledged_by_user_idint or nullUser ID of acknowledger

Error Codes

All BYOK errors return a structured JSON response:

{
"error_code": "BYOK_002",
"message": "KMS key access denied",
"detail": "Unable to access the provided KMS key: AccessDeniedException. Please verify the key policy grants ASCEND access.",
"timestamp": "2026-04-02T10:30:00Z",
"request_id": "req-abc-123"
}
FieldTypeDescription
error_codestringUnique BYOK error identifier
messagestringShort error description
detailstringSpecific context for this occurrence
timestampstringISO 8601 UTC timestamp
request_idstring or nullValue of X-Request-ID header if provided

Error Code Registry

CodeHTTP StatusMessageWhen It Occurs
BYOK_001400Invalid KMS ARN formatcmk_arn fails regex validation
BYOK_002403KMS key access deniedASCEND cannot access CMK, or key status is not active
BYOK_003409Key already registeredOrganization already has a registered key
BYOK_004400Legal waiver not acknowledgedNot all 3 acknowledgment fields set to true
BYOK_005404No key registeredNo encryption key registered for this organization
BYOK_006503KMS service unavailableCMK inaccessible during rotation or health check
BYOK_007500Encryption operation failedData encryption using CMK/DEK failed
BYOK_008500Decryption operation failedData decryption using CMK/DEK failed

Rate Limiting

All BYOK endpoints enforce per-user rate limits. Limits are keyed on the authenticated user's ID (extracted from the JWT sub claim). Rate limit state is stored in Redis with in-memory fallback if Redis is unavailable.

Limits by Endpoint

EndpointMethodDefault LimitEnvironment Variable
/keysPOST5/hourBYOK_RATE_LIMIT_REGISTER
/keysGET100/minuteBYOK_RATE_LIMIT_GET
/keysDELETE1/hourBYOK_RATE_LIMIT_DELETE
/keys/rotatePOST10/hourBYOK_RATE_LIMIT_ROTATE
/healthGET60/minuteBYOK_RATE_LIMIT_HEALTH
/auditGET60/minuteBYOK_RATE_LIMIT_AUDIT
/legal-waiverGET60/minuteBYOK_RATE_LIMIT_WAIVER_GET
/legal-waiverPOST10/hourBYOK_RATE_LIMIT_WAIVER_POST
/legal-waiver/statusGET60/minuteBYOK_RATE_LIMIT_WAIVER_STATUS

Rate Limit Exceeded Response (429)

{
"detail": "Too many requests. Please try again later.",
"retry_after": "60 seconds"
}

The response includes a Retry-After HTTP header with the number of seconds to wait.

Rate Limit Headers

All responses include standard rate limit headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait (only on 429 responses)

Next Steps