> For the complete documentation index, see [llms.txt](https://docs.violet.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.violet.io/concepts/overview/token-refresh-management.md).

# Token Refresh Management

Auth tokens expire after a set time period. Use your refresh token to obtain new auth tokens without re-entering your login credentials. Always refresh your token before it expires to maintain uninterrupted API access.

#### Refreshing Tokens

**Endpoint**: `GET /auth/token`

**Required Headers**:

```http
X-Violet-App-Id: your-app-id-here
X-Violet-App-Secret: your-app-secret-here
X-Violet-Token: your-refresh-token-here
Content-Type: application/json
```

#### Example Automatic Token Refresh Implementation

```javascript
class VioletAuthManager {
  constructor(appId, appSecret, username, password) {
    this.appId = appId;
    this.appSecret = appSecret;
    this.username = username;
    this.password = password;
    this.authToken = null;
    this.refreshToken = null;
    this.expiresAt = null;
    this.baseURL = 'https://sandbox-api.violet.io/v1';
  }

  async initialize() {
    const tokens = await this.login();
    this.setTokens(tokens);
    return tokens;
  }

  async login() {
    const response = await fetch(`${this.baseURL}/login`, {
      method: 'POST',
      headers: {
        'X-Violet-App-Id': this.appId,
        'X-Violet-App-Secret': this.appSecret,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        username: this.username,
        password: this.password
      })
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(errorData.message || 'Login failed');
    }

    const data = await response.json();

    return {
      authToken: data.token,
      refreshToken: data.refresh_token,
      expiresAt: new Date(data.expires_at)
    };
  }

  async refreshAuthToken() {
    if (!this.refreshToken) {
      throw new Error('No refresh token available. Please re-authenticate.');
    }

    try {
      const response = await fetch(`${this.baseURL}/auth/token`, {
        headers: {
          'X-Violet-App-Id': this.appId,
          'X-Violet-App-Secret': this.appSecret,
          'X-Violet-Token': this.refreshToken,
          'Content-Type': 'application/json'
        }
      });

      if (!response.ok) {
        throw new Error('Token refresh failed');
      }

      const data = await response.json();
      this.authToken = data.token;
      this.expiresAt = this.extractExpiryFromJWT(data.token);
      
      return this.authToken;
    } catch (error) {
      // If refresh fails, re-authenticate
      console.warn('Token refresh failed, re-authenticating...');
      const tokens = await this.login();
      this.setTokens(tokens);
      return this.authToken;
    }
  }

  async getValidToken() {
    // Check if token is expired or will expire within 5 minutes
    const now = new Date();
    const fiveMinutesFromNow = new Date(now.getTime() + 5 * 60 * 1000);

    if (!this.authToken || !this.expiresAt || this.expiresAt <= fiveMinutesFromNow) {
      await this.refreshAuthToken();
    }

    return this.authToken;
  }

  async makeRequest(endpoint, method = 'GET', data = null) {
    const token = await this.getValidToken();
    
    const url = `${this.baseURL}${endpoint}`;
    const options = {
      method,
      headers: {
        'X-Violet-App-Id': this.appId,
        'X-Violet-App-Secret': this.appSecret,
        'X-Violet-Token': token,
        'Content-Type': 'application/json'
      }
    };

    if (data && ['POST', 'PUT', 'PATCH'].includes(method)) {
      options.body = JSON.stringify(data);
    }

    try {
      let response = await fetch(url, options);

      if (response.status === 401) {
        // Token might be expired, try refreshing once
        await this.refreshAuthToken();
        options.headers['X-Violet-Token'] = this.authToken;
        response = await fetch(url, options);
      }

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.message || 'API request failed');
      }

      return response.json();
  }

  setTokens({ authToken, refreshToken, expiresAt }) {
    this.authToken = authToken;
    this.refreshToken = refreshToken;
    this.expiresAt = expiresAt;
  }

  extractExpiryFromJWT(token) {
    try {
      const payload = JSON.parse(atob(token.split('.')[1]));
      return new Date(payload.exp * 1000);
    } catch (error) {
      console.warn('Failed to extract expiry from JWT:', error);
      return new Date(Date.now() + 24 * 60 * 60 * 1000); // Default to 24 hours
    }
  }
}

// Usage example
const authManager = new VioletAuthManager(
  process.env.VIOLET_APP_ID,
  process.env.VIOLET_APP_SECRET,
  process.env.VIOLET_USERNAME,
  process.env.VIOLET_PASSWORD
);

await authManager.initialize();

// Make authenticated requests
const merchants = await authManager.makeRequest('/merchants');
const orders = await authManager.makeRequest('/orders');
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.violet.io/concepts/overview/token-refresh-management.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
