Multi-Profile System
Create multiple public profiles with independent settings and verified assets
Overview
Users can create multiple public profiles, each with its own display name, bio, theme, and set of verified assets. This supports use cases like separating personal and business identities, or managing multiple brands under one account.
Each profile gets a unique shareable URL (/p/{profileId}) and can optionally claim a vanity username (/@{username}).
Endpoints
All profile endpoints require JWT authentication and are scoped to the authenticated user.
Base path: https://api.proof.holdings/api/v1/me
| Method | Endpoint | Purpose |
|---|---|---|
GET | /me/profiles | List all profiles |
POST | /me/profiles | Create new profile |
GET | /me/profiles/:profileId | Get specific profile |
PATCH | /me/profiles/:profileId | Update profile |
DELETE | /me/profiles/:profileId | Delete profile |
POST | /me/profiles/:profileId/primary | Set as primary profile |
One further endpoint manages which proofs a profile displays. It is not under the /me base path above — give it in full:
| Method | Endpoint | Purpose |
|---|---|---|
PUT | /api/v1/profiles/profiles/:profileId/proofs | Update profile's public proofs |
Create Profile
POST /api/v1/me/profiles
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
display_name | string | No | Display name (max 100 chars) |
bio | string | No | Profile bio (max 500 chars) |
avatar_url | string | No | HTTPS URL or base64 data URI |
business_name | string | No | Business name (max 100 chars) |
is_business | boolean | No | Whether this is a business profile |
is_public | boolean | No | Whether the profile is publicly visible |
is_primary | boolean | No | Set as the primary profile |
theme | object | No | Visual theme (see Theme Object) |
email_theme | string | No | dark or light — how this project's emails look (unset renders as dark) |
support_email | string | No | Where recipients of this project's messages can reach it; fills {{support_email}} |
curl -X POST https://api.proof.holdings/api/v1/me/profiles \
-H "Cookie: session=eyJ..." \
-H "Content-Type: application/json" \
-d '{
"display_name": "Acme Corp",
"bio": "Verified digital presence for Acme Corporation",
"is_business": true,
"business_name": "Acme Corp",
"is_public": true,
"theme": {
"primary_color": "#3B82F6",
"background_type": "gradient",
"gradient_start": "#1E3A5F",
"gradient_end": "#0F172A",
"font_style": "modern"
}
}'Response
{
"id": "64a1b2c3d4e5f6a7b8c9d0e1",
"profile_id": "k7x2m9p4",
"display_name": "Acme Corp",
"bio": "Verified digital presence for Acme Corporation",
"is_business": true,
"business_name": "Acme Corp",
"is_public": true,
"is_primary": false,
"email_theme": null,
"support_email": null,
"verification_level": "basic",
"public_proofs": [],
"custom_links": [],
"theme": {
"primary_color": "#3B82F6",
"background_type": "gradient",
"gradient_start": "#1E3A5F",
"gradient_end": "#0F172A",
"font_style": "modern"
},
"view_count": 0,
"created_at": "2026-02-06T12:00:00Z",
"updated_at": "2026-02-06T12:00:00Z"
}Update Profile
PATCH /api/v1/me/profiles/:profileId
Accepts any subset of the create fields, plus additional settings:
| Parameter | Type | Description |
|---|---|---|
show_verification_dates | boolean | Show when each asset was verified |
show_proof_channels | boolean | Show which channel was used |
custom_links | array | Up to 20 custom links (see below) |
support_email also accepts null, which clears it.
Custom Links
Each link in the custom_links array:
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Link title (max 100 chars) |
url | string | Yes | Link URL (max 500 chars) |
icon | string | No | Icon identifier (max 50 chars) |
is_visible | boolean | No | Whether link is shown publicly |
display_order | number | No | Sort order (0-based) |
curl -X PATCH https://api.proof.holdings/api/v1/me/profiles/64a1b2c3d4e5f6a7b8c9d0e1 \
-H "Cookie: session=eyJ..." \
-H "Content-Type: application/json" \
-d '{
"bio": "Updated bio for Acme",
"custom_links": [
{ "title": "Website", "url": "https://acme.com", "display_order": 0 },
{ "title": "Support", "url": "https://acme.com/support", "display_order": 1 }
]
}'Update Public Proofs
PUT /api/v1/profiles/profiles/:profileId/proofs
Control which verified assets appear on a profile and how they are displayed.
Request Body
| Parameter | Type | Description |
|---|---|---|
proofs | array | Up to 50 proof display settings |
Each proof in the array:
| Field | Type | Required | Description |
|---|---|---|---|
asset_id | string | Yes | ID of the verified asset |
is_visible | boolean | No | Whether to show on profile |
mask_level | string | No | full, partial, or hidden |
display_order | number | No | Sort order (0-based) |
label | string | No | Custom label (e.g., "Support Phone") |
curl -X PUT https://api.proof.holdings/api/v1/profiles/profiles/64a1b2c3d4e5f6a7b8c9d0e1/proofs \
-H "Cookie: session=eyJ..." \
-H "Content-Type: application/json" \
-d '{
"proofs": [
{
"asset_id": "507f1f77bcf86cd799439011",
"is_visible": true,
"mask_level": "partial",
"display_order": 0,
"label": "Main Phone"
},
{
"asset_id": "507f1f77bcf86cd799439012",
"is_visible": true,
"mask_level": "full",
"display_order": 1,
"label": "Business Domain"
}
]
}'Privacy Masking
| Level | Phone | Domain | |
|---|---|---|---|
full | +37069199199 | [email protected] | example.com |
partial | +3••••9199 | us•••@example.com | example.com |
hidden | Verified Phone | Verified Email | Verified Domain |
Theme Object
| Field | Type | Values |
|---|---|---|
primary_color | string | Hex color (e.g., #3B82F6) |
background_type | string | solid or gradient |
background_color | string | Hex color (solid backgrounds) |
gradient_start | string | Hex color (gradient start) |
gradient_end | string | Hex color (gradient end) |
font_style | string | default, modern, or classic |
Public Profile URLs
Profiles are publicly accessible without authentication:
| URL Pattern | Example |
|---|---|
/p/:profileId | https://proof.holdings/p/k7x2m9p4 |
/@:username | https://proof.holdings/@acmecorp |
Verification Levels
Profiles automatically earn verification badges based on verified asset count:
| Level | Requirement |
|---|---|
basic | Default for new profiles |
verified | Multiple verified asset types |
business | Business profile with verified domain |
Notes
- Each user can have multiple profiles, but only one can be primary
- Every outbound message carries exactly one project's branding — name, logo, colour, email theme, support email and message templates. A key bound to a project always uses that project; an account-wide key or a dashboard session uses the project it names, else the primary profile. There is no account-wide branding
- A key bound to a sub-account reads every profile but changes only its own; see Sub-accounts and API keys
- Deleting a profile does not revoke the underlying verified assets
- Profile IDs are cryptographically random 8-character strings
- Username claiming is rate-limited to 5 attempts per minute