Skip to main content
The Sure API supports two authentication methods to suit different use cases:
  1. API Key Authentication - Simple header-based authentication for server-to-server integrations
  2. OAuth 2.0 - Industry-standard OAuth for user-facing applications

API Key Authentication

API key authentication is the recommended method for server-to-server integrations, scripts, and backend services.

Overview

  • Simple header-based authentication
  • No token expiration by default
  • Supports read and read_write scopes
  • Rate limited based on API key tier
  • One active API key per source (web, mobile, monitoring)

Creating an API Key

1

Navigate to Settings

Log in to your Sure instance and go to SettingsAPI Key.
2

Generate New Key

Click Create API Key and select your desired scope:
  • read - Read-only access to all resources
  • read_write - Full read and write access
3

Save Your API Key

Copy and securely store your API key immediately. You won’t be able to see it again.
API keys are stored encrypted and cannot be retrieved after creation. If you lose your key, you’ll need to create a new one.

Using API Keys

Pass your API key in the X-Api-Key header with every request:
curl https://your-domain.com/api/v1/accounts \
  -H "X-Api-Key: your_api_key_here" \
  -H "Content-Type: application/json"

Python Example

import requests

api_key = "your_api_key_here"
base_url = "https://your-domain.com/api/v1"

headers = {
    "X-Api-Key": api_key,
    "Content-Type": "application/json"
}

response = requests.get(f"{base_url}/accounts", headers=headers)
accounts = response.json()

JavaScript Example

const apiKey = 'your_api_key_here';
const baseUrl = 'https://your-domain.com/api/v1';

const response = await fetch(`${baseUrl}/accounts`, {
  headers: {
    'X-Api-Key': apiKey,
    'Content-Type': 'application/json'
  }
});

const accounts = await response.json();

API Key Scopes

API keys support hierarchical scopes:
read
string
Read-only access to all endpoints. GET requests only.Allowed operations:
  • List and view accounts
  • List and view transactions
  • List and view all other resources
Denied operations:
  • Creating, updating, or deleting resources
read_write
string
Full access to all endpoints. Includes all read permissions plus write access.Allowed operations:
  • All read operations
  • Create, update, and delete transactions
  • Create, update, and delete tags
  • Create valuations
  • Trigger account syncs
  • All other write operations
The read_write scope includes all read permissions. You don’t need both.

API Key Management

Viewing Usage

API key usage is tracked automatically:
curl https://your-domain.com/api/v1/usage \
  -H "X-Api-Key: your_api_key_here"
Response includes:
  • Last used timestamp
  • Request count in current hour
  • Rate limit information

Revoking an API Key

To revoke an API key:
  1. Go to SettingsAPI Key
  2. Click Revoke Key
  3. Confirm the revocation
Revoked keys cannot be reactivated. You’ll need to create a new key.
Revoking an API key immediately invalidates it. All requests using the revoked key will fail with a 401 Unauthorized error.

API Key Sources

Sure tracks API keys by source to support different use cases:
  • web - For web-based integrations
  • mobile - For mobile app integrations
  • monitoring - For system monitoring and health checks
You can have one active API key per source.

OAuth 2.0 Authentication

OAuth 2.0 is the recommended method for user-facing applications that need to access Sure on behalf of users.

Overview

  • Industry-standard OAuth 2.0 protocol
  • Access tokens expire after 1 year
  • Refresh tokens for obtaining new access tokens
  • Supports PKCE for enhanced security
  • Hierarchical scopes (read, read_write)

OAuth Scopes

Sure implements two OAuth scopes:
read
string
default:true
Default scope providing read-only access to all resources.
read_write
string
Optional scope providing full read and write access. Includes all read permissions.

Token Endpoints

Sure provides dedicated endpoints for token management:

Signup

Create a new user account and obtain access tokens:
POST /api/v1/auth/signup
Content-Type: application/json

{
  "user": {
    "email": "[email protected]",
    "password": "SecureP@ssw0rd!",
    "first_name": "John",
    "last_name": "Doe"
  },
  "device": {
    "device_id": "unique-device-id",
    "device_name": "iPhone 15",
    "device_type": "ios",
    "os_version": "17.0",
    "app_version": "1.0.0"
  },
  "invite_code": "optional-invite-code"
}
Invite codes may be required depending on your instance configuration.
Password Requirements:
  • Minimum 8 characters
  • Must include uppercase and lowercase letters
  • Must include at least one number
  • Must include at least one special character: !@#$%^&*(),.?":{}|<>
Response:
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "def50200a1b2c3d4e5f6...",
  "token_type": "Bearer",
  "expires_in": 31536000,
  "created_at": 1709539200,
  "user": {
    "id": 123,
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe",
    "ui_layout": "vertical",
    "ai_enabled": false
  }
}

Login

Authenticate an existing user:
POST /api/v1/auth/login
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "SecureP@ssw0rd!",
  "otp_code": "123456",
  "device": {
    "device_id": "unique-device-id",
    "device_name": "iPhone 15",
    "device_type": "ios",
    "os_version": "17.0",
    "app_version": "1.0.0"
  }
}
otp_code
string
Required only if two-factor authentication is enabled for the user.
Response with MFA Required:
{
  "error": "Two-factor authentication required",
  "mfa_required": true
}
Successful Response: Same format as signup response.

Refresh Token

Obtain a new access token using a refresh token:
POST /api/v1/auth/refresh
Content-Type: application/json

{
  "refresh_token": "def50200a1b2c3d4e5f6...",
  "device": {
    "device_id": "unique-device-id"
  }
}
Response:
{
  "access_token": "new_access_token...",
  "refresh_token": "new_refresh_token...",
  "token_type": "Bearer",
  "expires_in": 31536000,
  "created_at": 1709539200
}
The old access token is revoked when a new token is issued via refresh.

SSO Exchange (Mobile)

Exchange a web SSO authorization code for mobile tokens:
POST /api/v1/auth/sso_exchange
Content-Type: application/json

{
  "code": "authorization_code_from_web"
}
This endpoint is used for mobile app authentication flows that leverage web-based SSO.

Enable AI Features

PATCH /api/v1/auth/enable_ai
Authorization: Bearer your_access_token
Content-Type: application/json
Enables AI features for the authenticated user’s account. This endpoint is typically called from mobile apps after a user opts in to AI functionality. Request Headers:
Authorization
string
required
Bearer token from login or signup
Response (200 OK):
{
  "user": {
    "id": "uuid",
    "email": "[email protected]",
    "ai_enabled": true,
    "ai_available": true
  }
}
Errors:
  • 403 Forbidden: AI is not available for this account
  • 422 Unprocessable Entity: Failed to update user settings

Using OAuth Tokens

Pass your access token in the Authorization header:
curl https://your-domain.com/api/v1/accounts \
  -H "Authorization: Bearer your_access_token" \
  -H "Content-Type: application/json"

Python Example

import requests

access_token = "your_access_token"
base_url = "https://your-domain.com/api/v1"

headers = {
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json"
}

response = requests.get(f"{base_url}/accounts", headers=headers)
accounts = response.json()

JavaScript Example

const accessToken = 'your_access_token';
const baseUrl = 'https://your-domain.com/api/v1';

const response = await fetch(`${baseUrl}/accounts`, {
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  }
});

const accounts = await response.json();

Token Lifecycle

1

Obtain Initial Tokens

Use the login or signup endpoint to get your initial access and refresh tokens.
2

Use Access Token

Include the access token in the Authorization header for all API requests.Access tokens expire after 1 year.
3

Refresh Before Expiry

Before your access token expires, use the refresh endpoint to obtain new tokens.The old access token is automatically revoked.
4

Handle Token Expiry

If your access token expires, you’ll receive a 401 Unauthorized error:
{
  "error": "unauthorized",
  "message": "Access token is invalid, expired, or missing required scope"
}
Use your refresh token to obtain a new access token.

OAuth Security Features

PKCE is enforced for all OAuth flows to prevent authorization code interception attacks.This is configured in config/initializers/doorkeeper.rb:191.
Access tokens and refresh tokens are hashed before storage using SHA256.In test environments, plaintext fallback is enabled for easier testing.
OAuth application secrets are hashed using SHA256 before storage.
When you refresh an access token, both the access token and refresh token are rotated. The old tokens are revoked.

Authentication Errors

Both authentication methods return consistent error responses:

Unauthorized (401)

Authentication failed or credentials are missing:
{
  "error": "unauthorized",
  "message": "Access token or API key is invalid, expired, or missing"
}
Common causes:
  • API key is revoked or expired
  • Access token is expired
  • Authorization header is missing or malformed
  • Account has been deactivated

Insufficient Scope (403)

Authentication succeeded but lacks required permissions:
{
  "error": "insufficient_scope",
  "message": "This action requires the 'write' scope"
}
Common causes:
  • Using a read scope for write operations
  • API key doesn’t have the required scope
  • Access token was issued with limited scopes

Choosing an Authentication Method

Use API Keys When

  • Building server-to-server integrations
  • Creating backend automation scripts
  • Implementing system monitoring
  • You don’t need per-user authentication

Use OAuth When

  • Building user-facing applications
  • Need to act on behalf of specific users
  • Building mobile applications
  • Require more granular access control

Security Best Practices

Treat your API keys and access tokens like passwords. Never commit them to version control or expose them in client-side code.
1

Store Credentials Securely

Use environment variables or secure credential stores (like AWS Secrets Manager or HashiCorp Vault) to store API keys and tokens.
# .env file (never commit this)
SURE_API_KEY=your_api_key_here
2

Use HTTPS Only

Always use HTTPS when making API requests. Never send credentials over unencrypted connections.
3

Rotate Keys Regularly

For API keys used in production, rotate them periodically (every 90 days recommended).
4

Use Minimal Scopes

Only request the scopes you actually need. Use read scope for read-only integrations.
5

Monitor Usage

Regularly review API key usage and revoke any keys that are no longer needed.
6

Handle Token Expiry

Implement proper token refresh logic to handle expired access tokens gracefully.

Troubleshooting

  • Ensure you’re passing the key in the X-Api-Key header (not Authorization)
  • Verify the key hasn’t been revoked
  • Check that you copied the entire key without spaces or line breaks
  • Confirm your account is active
Access tokens expire after 1 year. If tokens seem to expire sooner:
  • Check your device’s clock is synchronized
  • Verify you’re not accidentally revoking tokens
  • Implement proper refresh token logic
You need a higher permission level:
  • For API keys: Create a new key with read_write scope
  • For OAuth: Request the read_write scope during authorization
  • Note: You cannot upgrade an existing token’s scope, you must obtain a new one
The API enforces family-level access control:
  • Users can only access resources within their own family
  • This is a security feature that cannot be bypassed
  • Each user belongs to exactly one family

User Management

Sure’s API provides endpoints for managing user accounts. These endpoints require write scope.

Reset Account

DELETE /api/v1/users/reset
Authorization: Bearer your_access_token
# OR
X-Api-Key: your_api_key
Resets all data in your family account, including transactions, accounts, budgets, and rules. This operation cannot be undone. Response (200 OK):
{
  "message": "Account reset has been initiated"
}
This operation is asynchronous. All family data will be deleted in the background. The user account itself is preserved.

Delete Account

DELETE /api/v1/users/me
Authorization: Bearer your_access_token
# OR
X-Api-Key: your_api_key
Permanently deletes your user account and all associated data. This operation cannot be undone. Response (200 OK):
{
  "message": "Account has been deleted"
}
Errors:
  • 422 Unprocessable Entity: Failed to delete account
This permanently deletes your entire user account, including all family data, integrations, and settings. This operation cannot be undone.

Next Steps

Now that you understand authentication, explore the API:

API Overview

Learn about rate limits, pagination, and error handling

Accounts API

Access your accounts and balances

Transactions API

Start working with transactions

All Resources

Browse all API endpoints

Build docs developers (and LLMs) love