8.9 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	Presence Activity API Documentation
Overview
The Presence Activity API allows users to manage their current activities (e.g., gaming, music, workouts) with automatic expiration through a lease-based system. Activities can be created, updated, and deleted, with support for flexible metadata and both system-generated and user-defined identifiers.
This service is handled by the DysonNetwork.Pass, when using with the gateway, replace the /api with the /pass
Key Features
- Lease-Based Expiration: Activities automatically expire within 1-60 minutes unless renewed
 - Flexible Identity: Support for both autogenerated GUIDs and user-defined ManualIds
 - Extensible Metadata: JSON-stored metadata dictionary for custom developer data
 - Soft Deletion: Activities are soft-deleted and filtered automatically
 - Performance Optimized: Cached active activities with 1-minute expiration
 - Authentication Required: All endpoints require valid user authentication
 
API Endpoints
Base URL: /api/activities
Authentication
All endpoints require [Authorize] header. User context is automatically extracted.
Get Active Activities
Retrieve all currently active (non-expired) presence activities for the authenticated user.
Endpoint: GET /api/activities
Response:
[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "Gaming",
    "manualId": "game-session-1",
    "title": "Playing Cyberpunk 2077",
    "subtitle": "Night City Exploration",
    "caption": "Missions completed: 15",
    "meta": {
      "appName": "Cyberpunk 2077",
      "platform": "Steam",
      "customProperty": "additional data"
    },
    "leaseMinutes": 10,
    "leaseExpiresAt": "2024-01-15T14:30:00Z",
    "accountId": "user-guid",
    "createdAt": "2024-01-15T14:25:00Z",
    "updatedAt": "2024-01-15T14:25:00Z",
    "deletedAt": null
  }
]
Common Response Codes:
200 OK- Success, returns array of active activities401 Unauthorized- Invalid or missing authentication
Create New Activity
Create a new presence activity with a configurable lease period.
Endpoint: POST /api/activities
Request Body:
{
  "type": "Gaming",
  "manualId": "my-game-session",
  "title": "Playing Cyberpunk 2077",
  "subtitle": "Night City Mission",
  "caption": "Currently exploring downtown",
  "meta": {
    "appName": "Cyberpunk 2077",
    "platform": "Steam",
    "difficulty": "Hard",
    "mods": ["mod1", "mod2"]
  },
  "leaseMinutes": 15
}
Response: Returns the created SnPresenceActivity object with populated fields.
Field Details:
type: PresenceType enum (Unknown, Gaming, Music, Workout)manualId: Optional user-defined string identifiertitle,subtitle,caption: Display strings (max 4096 chars each)meta: OptionalDictionary<string, object>for custom dataleaseMinutes: 1-60 minutes (default: 5)
Response Codes:
200 OK- Activity created successfully400 Bad Request- Invalid lease minutes or malformed data401 Unauthorized- Invalid authentication
Update Activity
Update an existing activity using either its GUID or ManualId. Only provided fields are updated.
Endpoint: PUT /api/activities
Query Parameters: (one required)
id- System-generated GUID (string)manualId- User-defined identifier (string)
Request Body: (all fields optional)
{
  "title": "Updated: Playing Cyberpunk 2077",
  "meta": {
    "appName": "Cyberpunk 2077",
    "platform": "Steam",
    "newProperty": "updated data"
  },
  "leaseMinutes": 20
}
Response: Returns the updated SnPresenceActivity object.
Response Codes:
200 OK- Activity updated successfully400 Bad Request- Missing or invalid ID parameters401 Unauthorized- Invalid authentication404 Not Found- Activity not found or doesn't belong to user
Example cURL:
# Update by ManualId
curl -X PUT "/api/activities?manualId=my-game-session" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"leaseMinutes": 20}'
# Update by GUID
curl -X PUT "/api/activities?id=550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"title": "Updated Title"}'
Delete Activity
Soft-delete an activity using either GUID or ManualId.
Endpoint: DELETE /api/activities
Query Parameters: (one required)
id- System-generated GUID (string)manualId- User-defined identifier (string)
Request Body: None
Response: No content (204)
Response Codes:
204 No Content- Activity deleted successfully400 Bad Request- Missing or invalid ID parameters401 Unauthorized- Invalid authentication404 Not Found- Activity not found or doesn't belong to user
Example cURL:
# Delete by ManualId
curl -X DELETE "/api/activities?manualId=my-game-session" \
  -H "Authorization: Bearer <token>"
Additional Endpoint
Get Activities by Account ID
Endpoint: GET /api/activities/{accountId:guid}
For administrative or debugging purposes. Returns activities for the specified account ID, regardless of authentication.
Data Models
PresenceType Enum
public enum PresenceType
{
    Unknown,
    Gaming,
    Music,
    Workout
}
SnPresenceActivity
public class SnPresenceActivity : ModelBase
{
    public Guid Id { get; set; } // System-generated GUID
    public PresenceType Type { get; set; }
    public string? ManualId { get; set; } // User-defined ID
    public string? Title { get; set; }
    public string? Subtitle { get; set; }
    public string? Caption { get; set; }
    public Dictionary<string, object>? Meta { get; set; } // JSON metadata
    public int LeaseMinutes { get; set; } // Lease duration
    public Instant LeaseExpiresAt { get; set; } // Expiration timestamp
    // Inherited from ModelBase
    public Guid AccountId { get; set; }
    public Instant CreatedAt { get; set; }
    public Instant UpdatedAt { get; set; }
    public Instant? DeletedAt { get; set; } // Soft deletion
}
Behavior & Constraints
Lease Expiration
- Activities automatically expire when 
SystemClock.Instance.GetCurrentInstant() > LeaseExpiresAt - Expiry is checked in database queries, so expired activities are filtered out of GET operations
 - Clients must periodically update/renew leases to keep activities active
 
ID Flexibility
- ManualId: User-defined string, unique within a user's activities
 - GUID: System-generated, always unique, returned in API responses
 - Both can be used interchangeably for updates and deletion
 
Performance Optimizations
- Active activities are cached for 1 minute to handle frequent updates
 - Cache is invalidated on create/update/delete operations
 - Database queries filter expired activities automatically
 
Security
- All operations are scoped to the authenticated user's account
 - Users can only manage their own activities
 - Invalid or expired authentication tokens return 401 Unauthorized
 
Data Storage
- Activities are stored in PostgreSQL with JSONB metadata support
 - Soft deletion uses timestamp rather than hard removal
 - EF Core middleware automatically handles CreatedAt/UpdatedAt timestamps
 
Usage Examples
Gaming Session Management
// Start gaming session
const activity = await fetch('/api/activities', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    type: 'Gaming',
    manualId: 'game-session-1',
    title: 'Playing Cyberpunk 2077',
    meta: { appId: 'cyberpunk2077', mods: ['photorealistic'] },
    leaseMinutes: 15
  })
});
// Update progress (extend lease)
await fetch('/api/activities?manualId=game-session-1', {
  method: 'PUT',
  body: JSON.stringify({
    title: 'Playing Cyberpunk 2077 - Level 25',
    leaseMinutes: 15
  })
});
// End session
await fetch('/api/activities?manualId=game-session-1', {
  method: 'DELETE'
});
Metadata Extension
// Rich metadata support
const activity = {
  type: 'Music',
  manualId: 'spotify-session',
  title: 'Listening to Electronic',
  meta: {
    spotifyTrackId: '1Je1IMUlBXcx1FzbcXRuWw',
    artist: 'Purity Ring',
    album: 'Shrines',
    duration: 240000, // milliseconds
    custom: { userRating: 5, genre: 'Electronic' }
  },
  leaseMinutes: 30
};
Error Handling
Common error responses follow REST API conventions:
{
  "type": "Microsoft.AspNetCore.Mvc.ValidationProblemDetails",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "leaseMinutes": ["Lease minutes must be between 1 and 60."]
  }
}
Implementation Notes
- Built with ASP.NET Core and Entity Framework Core
 - Uses NodaTime for precise timestamp handling
 - PostgreSQL JSONB for flexible metadata storage
 - Integration with existing authentication and caching systems
 - Follows established project patterns for soft deletion and audit trails