Hopshift
API Reference

Authentication

How to authenticate with the Hopshift API using API keys

The Hopshift API uses API keys for authentication. All requests to /api/v1/ endpoints must include a valid API key in the Authorization header.

API keys grant access to all companies in your group. Treat them like passwords: store them securely, never commit them to source control, and rotate them if you suspect they have been compromised.

Creating an API Key

API keys are created in the Hopshift dashboard. You need Group Owner or Group Admin access.

  1. Open the Hopshift dashboard and navigate to Group Settings.
  2. Click the API Keys tab.
  3. Click Create API Key.
  4. Give the key a descriptive name (e.g., "HRIS Sync – Production").
  5. Select the scopes the key requires (see Scopes below).
  6. Optionally set an expiry date. Keys without an expiry remain valid until manually revoked.
  7. Click Create.

The raw API key is shown only once immediately after creation. Copy it and store it in a secrets manager (e.g., AWS Secrets Manager, HashiCorp Vault, Vercel Environment Variables) before closing the dialog. You cannot retrieve the key value again after this point.

Key Format

Hopshift API keys use the hops_ prefix followed by 64 hexadecimal characters:

hops_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2

Only strings matching this pattern will be accepted as valid Bearer tokens.

Using an API Key

Include the key in the Authorization header of every request using the Bearer scheme:

curl https://hopshift.nottoosweetlabs.com/api/v1/employees \
  -H "Authorization: Bearer hops_your_api_key_here"

The header format must be exactly:

Authorization: Bearer hops_<key>

Any other format (including omitting Bearer, using a different prefix, or sending the key in a query parameter) will result in a 401 Unauthorized response.

Scopes

Scopes control which endpoints a key can access. Assign only the scopes a key actually needs.

ScopeDescription
employees:readRead access to employee records via GET /api/v1/employees and GET /api/v1/employees/:identifier

Additional scopes for payroll, time off, and timesheets will be added as those endpoints become available.

When a request is made with a valid key that is missing the required scope, the API returns 403 Forbidden:

{
  "error": "Forbidden: missing employees:read scope"
}

Key Lifecycle

Expiry

Keys can optionally be configured with an expiry date at creation time. Once a key's expiry date has passed, it is automatically invalidated and all requests using it return 401 Unauthorized.

Even if a key has no expiry date, it is good practice to rotate keys regularly: for example, every 90 days. Create the new key, update your integration, verify it works, then revoke the old key.

Revoking a Key

To revoke a key, go to Group Settings → API Keys in the dashboard and click Revoke next to the key. Revocation is immediate: any in-flight or subsequent requests using that key will return 401 Unauthorized.

Revoke keys promptly if:

  • A key may have been exposed (leaked in logs, committed to a repository, etc.)
  • A key is no longer in use
  • A team member with access to the key has left the organisation

Last Used Tracking

The dashboard shows the last time each key was used. Use this to identify stale keys that can safely be revoked.

Rate Limiting

Each API key is limited to 200 requests per minute. This limit is applied per key, not per IP address.

When the rate limit is exceeded the API responds with:

HTTP/1.1 429 Too Many Requests
Retry-After: 14
Content-Type: application/json

{
  "error": "Too many requests"
}

The Retry-After header contains the number of seconds to wait before making another request.

Handling 429 in Your Integration

Implement exponential backoff when you receive a 429 response:

async function fetchWithRetry(url: string, options: RequestInit, retries = 3): Promise<Response> {
  const response = await fetch(url, options);

  if (response.status === 429 && retries > 0) {
    const retryAfter = parseInt(response.headers.get("Retry-After") ?? "5", 10);
    await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
    return fetchWithRetry(url, options, retries - 1);
  }

  return response;
}

If you are syncing large numbers of employees, use pagination (page + limit query parameters) rather than making many small requests in tight loops. A single paginated request can return up to 500 records.

Error Reference

StatusErrorCause
401 Unauthorized"Unauthorized"Authorization header is missing, the key format is invalid, the key has been revoked, or the key has expired
403 Forbidden"Forbidden: missing employees:read scope"The key is valid but does not have the scope required for this endpoint
429 Too Many Requests"Too many requests"The key has exceeded 200 requests in the current 60-second window
500 Internal Server ErrorvariesUnexpected server-side error: try again later

401 Unauthorized

# Example: missing Authorization header
curl https://hopshift.nottoosweetlabs.com/api/v1/employees
{
  "error": "Unauthorized"
}

A 401 is returned when:

  • The Authorization header is absent
  • The header does not start with Bearer hops_
  • The key has been revoked
  • The key's expiry date has passed

403 Forbidden

{
  "error": "Forbidden: missing employees:read scope"
}

The key is genuine but it was created without the scope required for this endpoint. Create a new key with the correct scope, or add the scope to the existing key in the dashboard.

500 Internal Server Error

{
  "error": "Internal server error"
}

Something went wrong on our end. If the error persists, please contact Hopshift support.

On this page