Sharing API
SyVault supports secure one-time sharing of individual records. A share link grants temporary, limited access to a single secret without requiring the recipient to have a SyVault account.
Create a Share Link
POST /api/share/one-time
Create a one-time share link for a record. The share payload is encrypted by the client before transmission.
curl -X POST https://vault.example.com/api/share/one-time \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record_id": "record-uuid-1",
"record_type": 1,
"share_token": "a1b2c3d4e5f6g7h8i9j0",
"encrypted_payload": "base64-client-encrypted-payload",
"expires_in_hours": 24,
"max_access_count": 1
}'
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
record_id | string | Yes | UID of the record being shared. |
record_type | integer | Yes | RecordType enum variant (1 = Login, 2 = Secure Note, etc.). |
share_token | string | Yes | Client-generated random token — forms the path component of the public URL. The decryption key is kept in the URL fragment and never sent to the server. |
encrypted_payload | string | Yes | Base64 ciphertext. The record's content is re-encrypted on the client under a fresh one-time share key before upload. |
expires_in_hours | integer | No | Hours until the link expires. Omit for server default. |
max_access_count | integer | No | Maximum number of retrievals before the share is deleted. Omit for 1 (default one-time). |
Response (201):
{
"id": "share-uuid-1",
"share_token": "a1b2c3d4e5f6g7h8i9j0",
"expires_at": "2026-04-06T13:00:00Z",
"max_access_count": 1,
"created_at": "2026-04-06T12:00:00Z"
}
Compose the recipient URL client-side as https://vault.example.com/share/{share_token}#{decryption_key_base64}. The fragment (after #) is never transmitted to the server — only the URL path hits GET /api/share/public/{share_token}.
Retrieve a Shared Secret
GET /api/share/public/{token}
This endpoint does not require authentication. It is the only public endpoint in the SyVault API.
curl https://vault.example.com/api/share/public/a1b2c3d4e5f6g7h8i9j0
Response (200):
{
"id": "share-uuid-1",
"encrypted_payload": "base64-client-encrypted-payload",
"created_at": "2026-04-06T12:00:00Z",
"expires_at": "2026-04-06T13:00:00Z"
}
The client decrypts encrypted_payload using the key from the URL fragment.
Response (404) — expired or used:
{
"error": "share_not_found",
"message": "This share link has expired or has already been viewed."
}
View Limits
The max_access_count counter is decremented on each successful retrieval. When it reaches zero, the share is permanently deleted from the server. Even if the expiration time has not elapsed, the share cannot be accessed again.
Listing Your Shares
Authenticated users can list their active share links:
GET /api/share/my-shares
curl https://vault.example.com/api/share/my-shares \
-H "Authorization: Bearer $TOKEN"
Response:
{
"data": [
{
"id": "share-uuid-1",
"record_id": "record-uuid-1",
"created_at": "2026-04-06T12:00:00Z",
"expires_at": "2026-04-06T13:00:00Z",
"max_access_count": 1,
"views": 0
}
]
}
Revoking a Share
Delete a share link before it expires or is used:
DELETE /api/share/{id}
curl -X DELETE https://vault.example.com/api/share/share-uuid-1 \
-H "Authorization: Bearer $TOKEN"
Returns 204 No Content. The link is immediately invalid.
Security Model
- The encrypted payload is stored on the server, but the decryption key is embedded in the URL fragment (
#key=...). URL fragments are never sent to the server by browsers. - The server cannot decrypt shared secrets.
- Share links are one-time by default. Even if a link is intercepted, the attacker races with the legitimate recipient — the first viewer consumes the link.
- All share access is logged and visible in the organization audit log (Enterprise plan).
Organization Sharing
In addition to one-time share links, SyVault supports persistent sharing of records and folders with individual users or teams within your organization. Unlike one-time shares, organization shares remain active until explicitly revoked and support granular permission levels.
Permission Levels
| Value | Label | Description |
|---|---|---|
0 | View | Grantee can read the record or folder contents. |
1 | View + Edit | Grantee can read and modify the record or folder contents. |
2 | Manage | Grantee can read, modify, and re-share the record or folder with other users or teams. |
Share a Folder
POST /api/share/folder
Share an entire folder with a user or team. All current and future records in the folder are accessible to the grantee at the specified permission level.
curl -X POST https://vault.example.com/api/share/folder \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"folder_id": "folder-uuid-1",
"target_type": "team",
"target_id": "team-uuid-1",
"permission": 1
}'
| Field | Type | Required | Description |
|---|---|---|---|
folder_id | string | Yes | The UUID of the folder to share. |
target_type | string | Yes | "user" or "team". |
target_id | string | Yes | The UUID of the target user or team. |
permission | integer | Yes | 0 (view), 1 (view + edit), or 2 (manage). |
Response (201):
{
"grant_id": "grant-uuid-1",
"folder_id": "folder-uuid-1",
"target_type": "team",
"target_id": "team-uuid-1",
"permission": 1,
"created_at": "2026-04-06T12:00:00Z"
}
Share a Record
POST /api/share/record-org
Share an individual record with a user or team. This is a persistent grant, not a one-time link.
curl -X POST https://vault.example.com/api/share/record-org \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"record_id": "record-uuid-1",
"target_type": "user",
"target_id": "user-uuid-1",
"permission": 0
}'
Response (201):
{
"grant_id": "grant-uuid-2",
"record_id": "record-uuid-1",
"target_type": "user",
"target_id": "user-uuid-1",
"permission": 0,
"created_at": "2026-04-06T12:00:00Z"
}
List Folder Access Grants
GET /api/share/folder/{id}/grants
curl https://vault.example.com/api/share/folder/folder-uuid-1/grants \
-H "Authorization: Bearer $TOKEN"
Response (200):
{
"data": [
{
"grant_id": "grant-uuid-1",
"target_type": "team",
"target_id": "team-uuid-1",
"target_name": "Engineering",
"permission": 1,
"created_at": "2026-04-06T12:00:00Z"
}
]
}
List Record Access Grants
GET /api/share/record/{id}/grants
curl https://vault.example.com/api/share/record/record-uuid-1/grants \
-H "Authorization: Bearer $TOKEN"
Response (200):
{
"data": [
{
"grant_id": "grant-uuid-2",
"target_type": "user",
"target_id": "user-uuid-1",
"target_name": "bob@example.com",
"permission": 0,
"created_at": "2026-04-06T12:00:00Z"
}
]
}
Revoke a Sharing Grant
DELETE /api/share/grant/{id}
curl -X DELETE https://vault.example.com/api/share/grant/grant-uuid-1 \
-H "Authorization: Bearer $TOKEN"
Returns 204 No Content. The grantee loses access immediately. Any cached folder keys for the grantee are invalidated.
Organization Sharing Security Model
- Key re-encryption. When a folder or record is shared, the server re-encrypts the folder/record DEK with the grantee's public key (or the team's shared key). The server never sees plaintext data.
- Permission enforcement. Permissions are checked on every API call. A grantee with
viewpermission who attempts aPUTreceives403 Forbidden. - Manage permission propagation. A grantee with
manage(level 2) can create new grants, but cannot grant a higher permission level than they hold. - Revocation cascades. Revoking a team grant removes access for all members of that team. Revoking a folder grant removes access to all records within it.
- Audit logging. All grant creation, modification, and revocation events are recorded in the organization audit log.