Conventions

API Design Principles

The Fortress API follows consistent conventions to ensure predictability and ease of use:

  • RESTful design - Standard HTTP methods (GET, POST, PUT, PATCH, DELETE)
  • Resource-oriented - Clear URL structure around business entities
  • Minimal nesting - Paths are nested only for truly hierarchical relationships
  • Consistent naming - Predictable patterns across all endpoints
  • Idempotent operations - Safe to retry requests using idempotencyId for most of our endpoints

Resource Naming

URL Structure

  • Plural resources: Collection endpoints use plural names (e.g., /properties, /units, /workOrders)
  • Singular identifiers: Individual resources accessed via ID (e.g., /properties/{propertyId}, /units/{unitId})
  • Nested resources: Sub-resources nested when they represent true parent-child relationships:
    • /applications/{applicationId}/customers - Customers belong to applications
    • /applications/{applicationId}/pets - Pets belong to applications
    • /workOrders/{workOrderId}/timeEntries - Time entries belong to work orders

Identifiers

  • All resource IDs use UUIDv4 format
  • Path parameters follow pattern: {resourceName}Id (e.g., {propertyId}, {customerId})
  • Foreign key properties suffixed with Id (e.g., propertyId, householdId)

HTTP Methods and Status Codes

Standard Operations

  • GET - Retrieve resource(s) → Returns 200 OK
  • POST - Create new resource → Returns 201 Created (or 200 OK for some operations)
  • PUT - Update entire resource → Returns 200 OK
  • PATCH - Partial update or state change → Returns 200 OK or 204 No Content
  • DELETE - Remove resource → Returns 200 OK with message

Status Code Patterns

  • 200 OK - Successful operation with response body
  • 201 Created - Resource created successfully (POST operations)
  • 204 No Content - Successful operation, already in desired state (idempotent state transitions)
  • 400 Bad Request - Invalid request parameters or body
  • 401 Unauthorized - Missing or invalid API key
  • 404 Not Found - Resource does not exist
  • 500 Internal Server Error - Server error (safe to retry with same idempotencyId)

Query Parameters

All list endpoints support the following query parameters:

Pagination

  • page - Page number (starts at 1, defaults to 1)
  • limit - Items per page (defaults to 100)

Example:

GET /properties?page=2&limit=25

Filtering

  • filter - FQL (Fortress Query Language) expressions for filtering results

Example:

GET /workOrders?filter=status=OPEN&propertyId=123e4567-e89b-12d3-a456-426614174000

See the Filtering with FQL page for detailed filtering syntax.

Sorting

  • sort - Order results by field(s), prefix with - for descending

Examples:

GET /transactions?sort=date
GET /transactions?sort=-createdAt

Field Selection and Relations

  • fields - Select specific fields or include related entities

Examples:

GET /households?fields=id,name,property.*
GET /units?fields=*,floorPlan.name,property.name

Response Formats

List Responses

List endpoints return arrays directly with pagination metadata in headers:

1// Response Headers
2x-total-count: 157
3
4// Response Body
5[
6 {
7 "id": "123e4567-e89b-12d3-a456-426614174000",
8 "name": "Sunset Apartments",
9 "status": "ACTIVE",
10 "createdAt": "2024-01-15T10:30:00Z"
11 }
12]

Single Resource Responses

Individual resource endpoints return the entity object:

1{
2 "id": "123e4567-e89b-12d3-a456-426614174000",
3 "name": "Sunset Apartments",
4 "status": "ACTIVE",
5 "createdAt": "2024-01-15T10:30:00Z",
6 "updatedAt": "2024-01-15T10:30:00Z"
7}

Create/Update Responses

Most POST operations return 201 Created with the created resource or a wrapper object:

1{
2 "message": "Application created successfully",
3 "data": {
4 "id": "123e4567-e89b-12d3-a456-426614174000",
5 "propertyId": "987e4567-e89b-12d3-a456-426614174999"
6 }
7}

Delete Responses

DELETE operations return 200 OK with a message:

1{
2 "message": "Customer deleted successfully"
3}

Property Conventions

Standard Fields

All entities include these common properties:

  • id (UUID) - Unique identifier
  • createdAt (ISO-8601 datetime) - When the record was created
  • updatedAt (ISO-8601 datetime) - When the record was last modified
  • deletedAt (ISO-8601 datetime, nullable) - Soft delete timestamp

Additional common fields:

  • readableId (string, nullable) - Human-readable identifier
  • idempotencyId (UUID, nullable) - For idempotent operations

Property Naming

  • camelCase - All property names use camelCase (e.g., firstName, phoneNumber)
  • Foreign keys - Suffixed with Id (e.g., propertyId, customerId, householdId)
  • Booleans - Prefixed with is, has, or similar (e.g., isActive, hasBalcony, isServiceAnimal)
  • Dates - Suffixed with At or Date:
    • *At for timestamps (e.g., createdAt, deletedAt, offboardedAt)
    • *Date for dates only (e.g., moveInDate, birthDate, scheduledDate)

Data Types

  • Dates and Times - ISO-8601 format strings, UTC timezone by default
  • UUIDs - Standard UUIDv4 format strings
  • Enums - ALL_CAPS with underscores (e.g., VACANT_READY, OCCUPIED_NO_NOTICE)
  • Phone Numbers - String format, country codes allowed (e.g., "+1234567890")
  • Amounts - Numeric with decimal precision for currency values

Authentication

All API requests require authentication via the x-api-key header:

$curl https://api.fortresstech.io/v1/properties \
> -H "x-api-key: YOUR_API_KEY"

The API key automatically maps requests to your organization, ensuring data isolation.

See the Authentication page for more details.

Error Handling

Errors follow RFC 7807 Problem Details format with standard HTTP status codes:

1{
2 "type": "https://api.fortresstech.io/errors/validation-error",
3 "title": "Validation Error",
4 "status": 400,
5 "detail": "Invalid property ID format"
6}

Operations are safe to retry on 5xx errors when using the same idempotencyId.

Idempotency

To ensure safe retries, include an idempotencyId in your request body for create operations:

1{
2 "idempotencyId": "unique-uuid-per-operation",
3 "propertyId": "123e4567-e89b-12d3-a456-426614174000",
4 "name": "New Work Order"
5}

The same idempotencyId will always produce the same result, preventing duplicate operations.