Skip to main content

API Philosophy

New Expensify’s API is designed around these core principles:
  1. 1:1:1 Ratio: One user action → One API command → One database operation
  2. Optimistic First: UI updates before server confirmation
  3. Offline Support: All requests work offline and sync later
  4. No Client Logic: API responses contain data, not instructions
  5. Pusher Integration: Real-time updates via WebSocket
For complete API details, see contributingGuides/API.md in the repository.

API Structure

Location

API code is organized in src/libs/API/:

Command Types

All API commands are defined in src/libs/API/types.ts:

Making API Calls

API.write() - WRITE Requests

For actions that modify data. Requests are queued and retried if needed.
When to use:
  • Creating new data
  • Updating existing data
  • Deleting data
  • Any action that should work offline

API.read() - READ Requests

For fetching data without modifying server state.
When to use:
  • Loading initial data
  • Refreshing data
  • Data that’s not persisted
  • Commands that don’t need offline support

API.makeRequestWithSideEffects() - Side Effect Requests

For requests that need the response data immediately.
Use sparingly: makeRequestWithSideEffects is discouraged. Only use when you absolutely need the response data to proceed. Discuss in Slack before using.
When to use (rare cases):
  • Third-party integration (Plaid, Onfido)
  • Redirects based on response
  • Cannot proceed without server data

Response Handling

HTTPS Response

Data returned directly to the requesting client:
Used for:
  • READ responses
  • Client-specific data
  • Error messages

Pusher Events

Data broadcast to all connected clients:
Used for:
  • WRITE responses (when successful)
  • Real-time updates
  • Multi-user data sync

Command Naming Conventions

API commands follow strict naming rules:

Format

Examples:
  • RequestMoney
  • OpenReport
  • AcceptTask
  • SignIn

Rules

  1. Unique verbs: Use descriptive verbs (Request, Open, Accept)
  2. Standard verbs only if unique fails: Update, Add, Delete
  3. No parameter names: Bad: SignInWithPassword, Good: SignIn
  4. No implementation details: Bad: AddVBBA, Good: AddBankAccount
  5. No UI terms: Bad: OpenReportPage, Good: OpenReport
  6. One command per action: Not StartAppWhileSignedInAndOpenWorkspace

Examples

Onyx Data Updates

Update Types

Three types of Onyx updates in API calls:

When to Include Each Data Type

Example: Complete Onyx Updates

Error Handling

Error Structure

Errors are stored with timestamps:

Displaying Errors

Use OfflineWithFeedback component:

Middleware

API requests pass through middleware in src/libs/Middleware/:
  1. Logging: Log request details
  2. RecheckConnection: Verify connectivity
  3. Reauthentication: Handle expired auth (jsonCode 407)
  4. HandleDeletedAccount: Handle account deletion (jsonCode 408)
  5. SupportalPermission: Handle permission denials
  6. HandleUnusedOptimisticID: Update IDs in queued requests
  7. Pagination: Handle paginated responses
  8. SentryServerTiming: Track server performance
  9. SaveResponseInOnyx: Apply success/failure data
  10. FraudMonitoring: Tag requests for fraud detection

Pusher Integration

Real-time updates via Pusher WebSocket:

Pusher Socket ID

WRITE requests include pusherSocketID to prevent echo:

Best Practices

1. One API Call Per User Action

2. Always Provide Failure Data

3. Use Correct Request Type

Next Steps

Authentication

Learn about API authentication

Endpoints

Explore available API endpoints

State Management

Understand Onyx integration

Offline-First

Learn offline patterns