Fuscorrespondence API Reference

Documentation
Last updated August 2, 2025

Fuscorrespondence API Reference

Base URL

https://6nnj8no7u0.execute-api.us-east-1.amazonaws.com/dev/fuscorrespondence

Authentication

All endpoints require JWT authentication via the Authorization header:

Authorization: Bearer <jwt_token>

Token Source: Obtained from fuscauth authentication service integration.

Response Format

All API responses follow this consistent structure:

Success Response:

json
{
    "success": true,
    "data": { ... },
    "message": "Operation completed successfully"
    }

Error Response:

json
{
    "success": false,
    "error": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": "Additional error context (optional)"
    }

Data Models

Letter Model (Updated)

typescript
interface Letter {
    pk: string // LETTER#{letterId}
    senderUserId: string // ID of user who sent the letter
    senderMailboxId: string // Sender's mailbox ID
    recipientMailboxId: string // Recipient's mailbox ID
    status: "Draft" | "Sent" // Simplified status system
    isRead: boolean // Whether recipient has read the letter
    content: string // Letter content
    recipientName?: string // Optional recipient display name
    senderName?: string // Optional sender display name
    recipientFuscaddress?: string // Recipient's FuscAddress
    senderFuscaddress?: string // Sender's FuscAddress
    sentDate?: string // ISO string when letter was sent
    createdAt: string // ISO string when draft was created
    updatedAt: string // ISO string when last modified
    }

Mailbox Model

typescript
interface Mailbox {
    pk: string // USER#{userId}
    sk: string // MAILBOX#{mailboxId}
    fuscaddress: string // Unique address like "42 Quill Street, Lettertown"
    location: {
    latitude: number
    longitude: number
    }
    createdAt: string // ISO string
    updatedAt: string // ISO string
    }

API Endpoints

Mailbox Management

Create or Update Mailbox

POST /mailbox

Creates a new mailbox or updates an existing one for the authenticated user.

Request Body:

json
{
    "fuscaddress": "42 Quill Street, Lettertown",
    "location": {
    "latitude": 37.7749,
    "longitude": -122.4194
    }
    }

Response (200):

json
{
    "success": true,
    "data": {
    "pk": "USER#user123",
    "sk": "MAILBOX#mailbox456",
    "fuscaddress": "42 Quill Street, Lettertown",
    "location": {
    "latitude": 37.7749,
    "longitude": -122.4194
    },
    "createdAt": "2025-01-01T12:00:00.000Z",
    "updatedAt": "2025-01-01T12:00:00.000Z"
    },
    "message": "Mailbox created successfully"
    }

Error Cases:

  • 400: Missing required fields (fuscaddress, location)
  • 401: Invalid or missing JWT token

Get My Mailbox

GET /mailbox

Retrieves the current user's mailbox information.

Response (200):

json
{
    "success": true,
    "data": {
    "pk": "USER#user123",
    "sk": "MAILBOX#mailbox456",
    "fuscaddress": "42 Quill Street, Lettertown",
    "location": {
    "latitude": 37.7749,
    "longitude": -122.4194
    },
    "createdAt": "2025-01-01T12:00:00.000Z",
    "updatedAt": "2025-01-01T12:00:00.000Z"
    }
    }

Error Cases:

  • 404: User has no mailbox configured
  • 401: Invalid or missing JWT token

Letter Operations

Create Draft Letter

POST /letters

Creates a new draft letter for the authenticated user.

Request Body:

json
{
    "content": "Dear friend,\n\nHope this letter finds you well...",
    "status": "Draft",
    "recipientName": "Jane Doe",
    "senderName": "John Smith"
    }

Response (201):

json
{
    "success": true,
    "data": {
    "pk": "LETTER#letter789",
    "senderUserId": "user123",
    "senderMailboxId": "mailbox456",
    "recipientMailboxId": "",
    "status": "Draft",
    "isRead": false,
    "content": "Dear friend,\n\nHope this letter finds you well...",
    "recipientName": "Jane Doe",
    "senderName": "John Smith",
    "senderFuscaddress": "42 Quill Street, Lettertown",
    "createdAt": "2025-01-01T12:00:00.000Z",
    "updatedAt": "2025-01-01T12:00:00.000Z"
    },
    "message": "Draft created successfully"
    }

Error Cases:

  • 400: Missing required fields (content, status must be "Draft")
  • 400: User has no mailbox configured
  • 401: Invalid or missing JWT token

Update Draft Letter

PATCH /letters/{letterId}

Updates an existing draft letter. Only draft letters can be updated.

Request Body:

json
{
    "content": "Updated letter content...",
    "recipientName": "Jane Doe",
    "senderName": "John Smith"
    }

Response (200):

json
{
    "success": true,
    "data": {
    "pk": "LETTER#letter789",
    "senderUserId": "user123",
    "senderMailboxId": "mailbox456",
    "recipientMailboxId": "",
    "status": "Draft",
    "isRead": false,
    "content": "Updated letter content...",
    "recipientName": "Jane Doe",
    "senderName": "John Smith",
    "senderFuscaddress": "42 Quill Street, Lettertown",
    "createdAt": "2025-01-01T12:00:00.000Z",
    "updatedAt": "2025-01-01T12:05:00.000Z"
    },
    "message": "Draft updated successfully"
    }

Error Cases:

  • 404: Letter not found or not owned by user
  • 400: Letter is not in Draft status
  • 401: Invalid or missing JWT token

Send Letter

POST /letters/{letterId}/send

Sends a draft letter to a recipient. Converts the letter from Draft to Sent status.

Request Body:

json
{
    "recipientFuscaddress": "123 Oak Avenue, Mailford"
    }

Response (200):

json
{
    "success": true,
    "data": {
    "pk": "LETTER#letter789",
    "senderUserId": "user123",
    "senderMailboxId": "mailbox456",
    "recipientMailboxId": "mailbox999",
    "status": "Sent",
    "isRead": false,
    "content": "Dear friend,\n\nHope this letter finds you well...",
    "recipientName": "Jane Doe",
    "senderName": "John Smith",
    "recipientFuscaddress": "123 Oak Avenue, Mailford",
    "senderFuscaddress": "42 Quill Street, Lettertown",
    "sentDate": "2025-01-01T12:10:00.000Z",
    "createdAt": "2025-01-01T12:00:00.000Z",
    "updatedAt": "2025-01-01T12:10:00.000Z"
    },
    "message": "Letter sent successfully"
    }

Error Cases:

  • 404: Letter not found or not owned by user
  • 400: Letter is not in Draft status
  • 422: Invalid recipient FuscAddress (address does not exist)
  • 401: Invalid or missing JWT token

Get My Letters

GET /letters

Retrieves letters for the authenticated user with optional filtering.

Query Parameters:

  • status (optional): Draft or Sent
  • sent (optional): true for sent letters, false for received letters

Examples:

  • /letters - All letters (sent and received)
  • /letters?status=Draft - Only draft letters
  • /letters?sent=true - Only letters I've sent
  • /letters?sent=false - Only letters I've received
  • /letters?status=Sent&sent=true - Only letters I've sent that are in Sent status

Response (200):

json
{
    "success": true,
    "data": [
    {
    "pk": "LETTER#letter789",
    "senderUserId": "user123",
    "senderMailboxId": "mailbox456",
    "recipientMailboxId": "mailbox999",
    "status": "Sent",
    "isRead": false,
    "content": "Dear friend,\n\nHope this letter finds you well...",
    "recipientName": "Jane Doe",
    "senderName": "John Smith",
    "recipientFuscaddress": "123 Oak Avenue, Mailford",
    "senderFuscaddress": "42 Quill Street, Lettertown",
    "sentDate": "2025-01-01T12:10:00.000Z",
    "createdAt": "2025-01-01T12:00:00.000Z",
    "updatedAt": "2025-01-01T12:10:00.000Z"
    }
    ]
    }

Get Letter by ID

GET /letters/{letterId}

Retrieves a specific letter by ID. User can only access their own letters (sent or received).

Response (200):

json
{
    "success": true,
    "data": {
    "pk": "LETTER#letter789",
    "senderUserId": "user123",
    "senderMailboxId": "mailbox456",
    "recipientMailboxId": "mailbox999",
    "status": "Sent",
    "isRead": false,
    "content": "Dear friend,\n\nHope this letter finds you well...",
    "recipientName": "Jane Doe",
    "senderName": "John Smith",
    "recipientFuscaddress": "123 Oak Avenue, Mailford",
    "senderFuscaddress": "42 Quill Street, Lettertown",
    "sentDate": "2025-01-01T12:10:00.000Z",
    "createdAt": "2025-01-01T12:00:00.000Z",
    "updatedAt": "2025-01-01T12:10:00.000Z"
    }
    }

Side Effect: If the user is the recipient and the letter status is "Sent", this endpoint automatically marks the letter as read (isRead: true).

Error Cases:

  • 404: Letter not found or not accessible by user
  • 401: Invalid or missing JWT token

Address Validation

Validate FuscAddress

POST /address/validate

Validates if a FuscAddress exists in the system (i.e., belongs to a user with a configured mailbox).

Request Body:

json
{
    "fuscaddress": "123 Oak Avenue, Mailford"
    }

Response (200) - Valid Address:

json
{
    "success": true,
    "data": {
    "valid": true
    }
    }

Response (200) - Invalid Address:

json
{
    "success": true,
    "data": {
    "valid": false
    }
    }

Error Cases:

  • 400: Missing fuscaddress field
  • 401: Invalid or missing JWT token

HTTP Status Codes

Status Code Description When It Occurs
200 OK Successful GET, PATCH, or POST operations
201 Created Successful resource creation (e.g., new draft letter)
400 Bad Request Missing required fields, invalid input format, or business rule violations
401 Unauthorized Invalid, missing, or expired JWT token
403 Forbidden User attempting to access resources they don't own
404 Not Found Letter, mailbox, or other resource not found
422 Unprocessable Entity Valid request format but failed business validation (e.g., invalid FuscAddress)
500 Internal Server Error Unexpected server error or database failure

Error Response Examples

400 Bad Request:

json
{
    "success": false,
    "error": "MISSING_REQUIRED_FIELDS",
    "message": "content is required and status must be 'Draft'"
    }

401 Unauthorized:

json
{
    "success": false,
    "error": "UNAUTHORIZED",
    "message": "Invalid or missing authentication token"
    }

404 Not Found:

json
{
    "success": false,
    "error": "LETTER_NOT_FOUND",
    "message": "Letter not found or not accessible"
    }

422 Unprocessable Entity:

json
{
    "success": false,
    "error": "INVALID_ADDRESS",
    "message": "Recipient FuscAddress does not exist",
    "details": "The address '999 Nonexistent St' was not found in the system"
    }

Letter Status System (Simplified)

The letter status system has been simplified for better user experience:

Status Flow

  1. Draft: Letter is being written and can be edited
  2. Sent: Letter has been sent to recipient (replaces InTransit/Delivered)

Read Tracking

  • isRead: Boolean field indicating if recipient has viewed the letter
  • Automatically set to true when recipient accesses the letter via GET /letters/{id}

Benefits of Simplified System

  • Easier to understand: Clear draft vs sent distinction
  • Better UX: No confusion about intermediate states
  • Simpler implementation: Reduces backend complexity
  • Still informative: Users can track if their sent letters have been read

Authentication Integration

JWT Token Management

  • Tokens are obtained from the fuscauth authentication service
  • Include in all requests: Authorization: Bearer <token>
  • Tokens should be stored securely (e.g., localStorage in web apps)
  • Handle token expiration gracefully with re-authentication

User Context

  • All operations are scoped to the authenticated user
  • Users can only access their own letters and mailbox
  • User ID is extracted from JWT token for authorization

Rate Limiting

Currently no rate limiting is implemented, but consider:

  • Reasonable request limits per user per minute
  • Protection against abuse of address validation endpoint
  • Monitoring for unusual usage patterns

Database Design Notes

DynamoDB Monotable Pattern

  • Table: fuscapp-monotable-dev
  • Mailbox Items: PK = USER#{userId}, SK = MAILBOX#{mailboxId}
  • Letter Items: PK = LETTER#{letterId}, SK = LETTER#{letterId}

Query Patterns

  • Get user mailbox: Query by PK = USER#{userId}
  • Get user's letters: Filter by senderUserId or recipientMailboxId
  • Address validation: Scan for fuscaddress (future: consider GSI optimization)

Considerations for Scale

  • Current design works well for moderate usage
  • For high scale, consider:
    • Global Secondary Index for address lookups
    • Separate tables for different entity types
    • Read replicas for query optimization

Last Updated: July 2025
API Version: 1.0
Status: Production Ready