When interacting with the Hyperproof API, proof objects must always be owned by a real human user in the organization. This article explains the hp-proof-owned-by field, why it exists, and when you must use it — particularly when authenticating with service account credentials.
Hyperproof supports two types of API clients, each with distinct security and ownership implications:
- Inherits your roles and permissions in the organization.
- Objects created or updated via the API are attributed to you (the human user).
- The
hp-proof-owned-byfield is optional — if omitted, you are automatically set as the proof owner. - The client is private to you; no other user or admin can see it.
- Operates as a distinct, non-human service identity with an assigned organization role.
- Visible to all administrators in the organization.
- Service accounts cannot be owners or assignees on Hyperproof objects.
- The
hp-proof-owned-byfield is required when uploading proof — omitting it results in a 400 Bad Request with the message: "Service accounts cannot be proof owners."
For accountability and traceability, Hyperproof enforces that every object (proof, policy, etc.) is owned by a real user. This has several downstream consequences:
- Facepiles and UI attribution — The Hyperproof UI displays owner avatars (facepiles) on proof items, controls, and tasks. These must resolve to a real user. When a service account uploads proof with
hp-proof-owned-byset, the UI shows the designated user as the owner and the service account name in the "Uploaded By" column. - Audit trail integrity — The
createdByfield records who performed the action (the service account), whileownedByrecords who is responsible for the proof. This separation preserves a clear chain of custody. - Object lifecycle — Owners can be notified, assigned follow-up tasks, and are visible in compliance reporting. A non-human identity cannot fulfill these responsibilities.
This same restriction applies to other object types — e.g., service accounts cannot be policy owners either.
| Attribute | Detail |
|---|---|
| Field name | hp-proof-owned-by |
| Passed as | Multipart form-data field |
| Value | UUID of an active Hyperproof user |
| Required when | Authenticating with a service account token |
| Optional when | Authenticating with a personal API client token |
The target user must be an active user in the organization — inactive or deprovisioned users cannot be assigned as proof owners.
Use the Get Organization Users endpoint to retrieve a list of users and their UUIDs:
curl --silent \
--header "Authorization: Bearer $ACCESS_TOKEN" \
"https://api.hyperproof.app/v1/users"# 1. Obtain a token using client credentials flow
ACCESS_TOKEN=$(curl -s -d \
"grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET" \
https://accounts.hyperproof.app/oauth/token | jq -r '.access_token')
# 2. Upload proof with explicit owner (REQUIRED for service accounts)
curl --request POST \
--url https://api.hyperproof.app/v1/proof \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--form proof=@"./evidence/SOC2_Report.pdf" \
--form hp-proof-owned-by="$USER_UUID"curl --request POST \
--url "https://api.hyperproof.app/v1/controls/$CONTROL_ID/proof" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--form proof=@"./evidence/PrivacyPolicy.pdf" \
--form hp-proof-owned-by="$USER_UUID"| Concern | Personal API Client | Service Account API Client |
|---|---|---|
| Visibility | Private to the creator | Visible to all org admins |
| Permissions | Inherits your user roles | Has its own assigned role |
| Proof ownership | Automatic (you) | Must specify via hp-proof-owned-by |
createdBy attribution | Your user ID | Service account ID |
| UI facepile / owner display | Your avatar | Designated user's avatar |
| Blast radius if compromised | Limited to your permissions | Potentially broader; shared credential |
| Error | Cause | Fix |
|---|---|---|
| "Service accounts cannot be proof owners." (400) | hp-proof-owned-by omitted or set to the service account's own ID | Provide a valid human user UUID |
| 400 on owner validation | User UUID is inactive or invalid | Use the Users API to retrieve an active user's UUID |