User Management
Comprehensive user profile and account management operations.
User Operations
Manage user accounts across the De. platform:
- Create and update user profiles
- Search and discover users
- Manage user settings and preferences
- Handle account verification
- Control privacy settings
User Types: Client, Agent, LSP, CSP, DEV
Get User Profile
Retrieve authenticated user's profile information.
Get Current User
Fetch logged-in user profile
GET https://auth.dedot.io/v1/users/me
Headers:
Authorization: Bearer <access_token>Response:
{
"id": "usr_123456",
"email": "[email protected]",
"phone": "+1234567890",
"name": "John Doe",
"avatar": "https://cdn.dedot.io/avatars/usr_123456.jpg",
"userType": "client",
"verified": true,
"createdAt": "2026-01-10T10:00:00Z",
"updatedAt": "2026-01-16T11:00:00Z",
"metadata": {
"language": "en",
"timezone": "America/New_York",
"notifications": true
}
}Get User by ID
Fetch specific user profile
GET https://auth.dedot.io/v1/users/{userId}
Headers:
Authorization: Bearer <access_token>Response:
{
"id": "usr_789",
"name": "Jane Smith",
"avatar": "https://cdn.dedot.io/avatars/usr_789.jpg",
"userType": "agent",
"verified": true,
"public": {
"bio": "Professional delivery driver",
"rating": 4.8,
"completedDeliveries": 1250
}
}Update User Profile
Modify user information and settings.
PATCH https://auth.dedot.io/v1/users/me
Headers:
Authorization: Bearer <access_token>
Content-Type: application/json
Body:
{
"name": "John Smith",
"avatar": "https://cdn.dedot.io/avatars/new-avatar.jpg",
"metadata": {
"language": "es",
"timezone": "Europe/Madrid",
"notifications": false
}
}Response:
{
"success": true,
"user": {
"id": "usr_123456",
"name": "John Smith",
"avatar": "https://cdn.dedot.io/avatars/new-avatar.jpg",
"metadata": {
"language": "es",
"timezone": "Europe/Madrid",
"notifications": false
},
"updatedAt": "2026-01-16T11:30:00Z"
}
}React Profile Editor
import { useState, useEffect } from 'react'
function ProfileEditor({ accessToken }: { accessToken: string }) {
const [profile, setProfile] = useState<any>(null)
const [loading, setLoading] = useState(true)
const [saving, setSaving] = useState(false)
const [error, setError] = useState('')
useEffect(() => {
fetchProfile()
}, [])
const fetchProfile = async () => {
try {
const response = await fetch('https://auth.dedot.io/v1/users/me', {
headers: {
'Authorization': `Bearer ${accessToken}`
}
})
const data = await response.json()
setProfile(data)
} catch (err) {
setError('Failed to load profile')
} finally {
setLoading(false)
}
}
const updateProfile = async (updates: any) => {
setSaving(true)
setError('')
try {
const response = await fetch('https://auth.dedot.io/v1/users/me', {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(updates)
})
const data = await response.json()
if (data.success) {
setProfile(data.user)
} else {
setError(data.message || 'Failed to update profile')
}
} catch (err) {
setError('Network error')
} finally {
setSaving(false)
}
}
if (loading) return <div>Loading...</div>
return (
<div className="profile-editor">
<div className="profile-avatar">
<img src={profile.avatar} alt={profile.name} />
<button onClick={() => {/* Upload new avatar */}}>
Change Avatar
</button>
</div>
<form onSubmit={(e) => {
e.preventDefault()
updateProfile({
name: e.currentTarget.name.value,
metadata: {
language: e.currentTarget.language.value,
timezone: e.currentTarget.timezone.value
}
})
}}>
<input
name="name"
defaultValue={profile.name}
placeholder="Full Name"
/>
<select name="language" defaultValue={profile.metadata?.language}>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
</select>
<select name="timezone" defaultValue={profile.metadata?.timezone}>
<option value="America/New_York">Eastern Time</option>
<option value="America/Chicago">Central Time</option>
<option value="America/Los_Angeles">Pacific Time</option>
<option value="Europe/London">London</option>
</select>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={saving}>
{saving ? 'Saving...' : 'Save Changes'}
</button>
</form>
</div>
)
}Avatar Upload
Upload user avatar image to CDN.
POST https://auth.dedot.io/v1/users/me/avatar
Headers:
Authorization: Bearer <access_token>
Content-Type: multipart/form-data
Body:
file: <image_file>Response:
{
"success": true,
"avatarUrl": "https://cdn.dedot.io/avatars/usr_123456_1705401600.jpg",
"message": "Avatar uploaded successfully"
}Avatar Upload Implementation
async function uploadAvatar(file: File, accessToken: string) {
const formData = new FormData()
formData.append('file', file)
try {
const response = await fetch('https://auth.dedot.io/v1/users/me/avatar', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`
},
body: formData
})
const data = await response.json()
if (data.success) {
return data.avatarUrl
} else {
throw new Error(data.message || 'Upload failed')
}
} catch (error) {
console.error('Avatar upload error:', error)
throw error
}
}
// React component
function AvatarUpload({ accessToken, onUpload }: any) {
const [uploading, setUploading] = useState(false)
const [error, setError] = useState('')
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0]
if (!file) return
// Validate file
if (!file.type.startsWith('image/')) {
setError('Please select an image file')
return
}
if (file.size > 5 * 1024 * 1024) {
setError('File size must be less than 5MB')
return
}
setUploading(true)
setError('')
try {
const avatarUrl = await uploadAvatar(file, accessToken)
onUpload(avatarUrl)
} catch (err) {
setError(err instanceof Error ? err.message : 'Upload failed')
} finally {
setUploading(false)
}
}
return (
<div>
<input
type="file"
accept="image/*"
onChange={handleFileChange}
disabled={uploading}
/>
{uploading && <div>Uploading...</div>}
{error && <div className="error">{error}</div>}
</div>
)
}User Search
Search for users across the platform.
GET https://auth.dedot.io/v1/users/search?q={query}&type={userType}&limit={limit}
Headers:
Authorization: Bearer <access_token>Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | Yes | Search query (name, email, phone) |
type | string | No | Filter by user type |
limit | number | No | Max results (default: 20, max: 100) |
offset | number | No | Pagination offset |
Response:
{
"users": [
{
"id": "usr_123",
"name": "John Doe",
"avatar": "https://cdn.dedot.io/avatars/usr_123.jpg",
"userType": "client",
"verified": true
},
{
"id": "usr_456",
"name": "Jane Smith",
"avatar": "https://cdn.dedot.io/avatars/usr_456.jpg",
"userType": "agent",
"verified": true
}
],
"total": 2,
"limit": 20,
"offset": 0
}Search Implementation
function UserSearch({ accessToken }: { accessToken: string }) {
const [query, setQuery] = useState('')
const [results, setResults] = useState<any[]>([])
const [loading, setLoading] = useState(false)
const searchUsers = async (searchQuery: string) => {
if (!searchQuery.trim()) {
setResults([])
return
}
setLoading(true)
try {
const response = await fetch(
`https://auth.dedot.io/v1/users/search?q=${encodeURIComponent(searchQuery)}&limit=10`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
)
const data = await response.json()
setResults(data.users || [])
} catch (error) {
console.error('Search error:', error)
setResults([])
} finally {
setLoading(false)
}
}
// Debounced search
useEffect(() => {
const timer = setTimeout(() => {
searchUsers(query)
}, 300)
return () => clearTimeout(timer)
}, [query])
return (
<div className="user-search">
<input
type="text"
placeholder="Search users..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
{loading && <div>Searching...</div>}
<div className="results">
{results.map(user => (
<div key={user.id} className="user-result">
<img src={user.avatar} alt={user.name} />
<div>
<strong>{user.name}</strong>
<span>{user.userType}</span>
{user.verified && <span>✓ Verified</span>}
</div>
</div>
))}
</div>
</div>
)
}Account Settings
Manage account preferences and privacy settings.
Notification Preferences
PATCH https://auth.dedot.io/v1/users/me/settings/notifications
Headers:
Authorization: Bearer <access_token>
Body:
{
"email": {
"enabled": true,
"orderUpdates": true,
"marketing": false,
"security": true
},
"push": {
"enabled": true,
"orderUpdates": true,
"messages": true
},
"sms": {
"enabled": false,
"orderUpdates": false
}
}Privacy Settings
PATCH https://auth.dedot.io/v1/users/me/settings/privacy
Headers:
Authorization: Bearer <access_token>
Body:
{
"profileVisibility": "public", // public, friends, private
"showEmail": false,
"showPhone": false,
"allowMessages": true,
"shareLocation": true
}Account Verification
Verify user identity with documents.
POST https://auth.dedot.io/v1/users/me/verify
Headers:
Authorization: Bearer <access_token>
Content-Type: multipart/form-data
Body:
documentType: "passport" | "drivers_license" | "national_id"
documentFront: <file>
documentBack: <file> // Optional for passport
selfie: <file>Response:
{
"success": true,
"verificationId": "ver_abc123",
"status": "pending",
"message": "Verification documents submitted. Review typically takes 24-48 hours."
}Delete Account
Permanently delete user account and all associated data.
DELETE https://auth.dedot.io/v1/users/me
Headers:
Authorization: Bearer <access_token>
Body:
{
"password": "user_password",
"confirmation": "DELETE_MY_ACCOUNT"
}Response:
{
"success": true,
"message": "Account deletion scheduled. All data will be removed within 30 days.",
"deletionDate": "2026-02-15T00:00:00Z"
}Account Deletion
Account deletion is permanent and irreversible. All user data, orders, and history will be deleted after 30 days grace period.
Account Deletion Implementation
function DeleteAccount({ accessToken }: { accessToken: string }) {
const [password, setPassword] = useState('')
const [confirmation, setConfirmation] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const handleDelete = async () => {
if (confirmation !== 'DELETE_MY_ACCOUNT') {
setError('Please type DELETE_MY_ACCOUNT to confirm')
return
}
setLoading(true)
setError('')
try {
const response = await fetch('https://auth.dedot.io/v1/users/me', {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ password, confirmation })
})
const data = await response.json()
if (data.success) {
// Logout and redirect
localStorage.clear()
window.location.href = '/goodbye'
} else {
setError(data.message || 'Failed to delete account')
}
} catch (err) {
setError('Network error')
} finally {
setLoading(false)
}
}
return (
<div className="delete-account">
<h3>Delete Account</h3>
<p>This action cannot be undone. All your data will be permanently deleted.</p>
<input
type="password"
placeholder="Enter your password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<input
type="text"
placeholder='Type "DELETE_MY_ACCOUNT" to confirm'
value={confirmation}
onChange={(e) => setConfirmation(e.target.value)}
/>
{error && <div className="error">{error}</div>}
<button
onClick={handleDelete}
disabled={loading || !password || confirmation !== 'DELETE_MY_ACCOUNT'}
className="danger"
>
{loading ? 'Deleting...' : 'Delete My Account'}
</button>
</div>
)
}User Metadata
Store custom user data and preferences.
PATCH https://auth.dedot.io/v1/users/me/metadata
Headers:
Authorization: Bearer <access_token>
Body:
{
"preferences": {
"theme": "dark",
"mapStyle": "streets",
"units": "metric"
},
"customFields": {
"companyName": "Acme Corp",
"department": "Logistics",
"employeeId": "EMP-12345"
}
}Limits:
- Max metadata size: 10KB
- Max nesting depth: 3 levels
- String values only (JSON stringified)
Security Best Practices
Do
- Validate user input before updates
- Use HTTPS for all requests
- Implement password confirmation for sensitive operations
- Rate limit profile updates
- Sanitize user-generated content
- Verify file types for uploads
Don't
- Don't expose sensitive user data
- Don't allow arbitrary metadata keys
- Don't store PII in metadata
- Don't skip authentication checks
- Don't trust client-side validation only
- Don't log user passwords
Rate Limits
User management endpoints have rate limits:
- Profile Updates: 10 requests per hour
- Avatar Upload: 5 uploads per day
- User Search: 100 requests per hour
- Settings Updates: 20 requests per hour

