Migration Guide to V2

We are enhancing the security of our APIs!
Starting 31st May 2026, Basic Authentication - username and password in every API call, and Token Authentication will be deprecated and replaced with JWT-Authentication.

Why Are We Making This Change?

Increased security

  • Your credentials are no longer sent with every request.
  • Instead, you exchange your credentials once for a short-lived access token.

Impact on you

  • APIs that previously worked using Basic Auth - passing Authorization: Basic ..., and Token Auth - passing Authorization: Token access_token, will stop accepting those headers after 31st May 2026.
  • You must obtain an access token by calling:
    POST https://app1.compliancely.com/api/v2/token/
  • All subsequent API requests must use the access token in the Authorization header:
    Authorization: Bearer <access_token>

Migrating to V2

  • Stop sending "Authorization: Basic (base64-username:password)" and "Authorization: Token access_token".
  • Call the token endpoint /api/v2/token/ with your username and password.
  • Store:
    • access (access token)
    • refresh (refresh token)
  • Use access in the Authorization: Bearer header for all API calls.
  • When the access token expires (either normally or prematurely) or invalid, use the refresh token (/api/v2/token/refresh/) API to obtain a new access token instead of relying on logic tied to the 1-hour expiry time.
  • Similarly, add a fallback to call /api/v2/token/ with the username and password whenever the refresh token is expired (normally or prematurely) or becomes invalid, rather than depending on logic based on the 24-hour expiry time.
  • (Optional) Use the validate endpoint to check token validity and remaining lifetime.

Authentication endpoints overview

  1. Obtain access & refresh tokens

    Endpoint:

    POST /api/v2/token/
    Host: app1.compliancely.com
    Content-Type: application/json

    Request body

    {
      "username": "<username>",
      "password": "<password>"
    }

    Successful response (HTTP 200)

    {
      "access": "<access_token>",
      "access_expiry_seconds": <expires_in_seconds>,
      "refresh": "<refresh_token>",
      "refresh_expiry_seconds": <expires_in_seconds>
    }

    Using the access token
    Include the access token as a Bearer token in the Authorization header:

    Authorization: Bearer <access_token>

    Example:

    curl --location 'https://app1.compliancely.com/api/v2/protected-endpoint/' \
      --header 'Authorization: Bearer eyJhbGciOiJIUz...'
  2. Refreshing access tokens

    Use the refresh token when your access token expires.
    Endpoint:

    POST /api/v2/token/refresh/
    Host: app1.compliancely.com
    Content-Type: application/json

    Request body

    {
      "refresh": "<your-refresh-token>"
    }

    Successful response (HTTP 200)

    {
      "access": "<new_access_token>",
      "access_expiry_seconds": <expires_in_seconds>
    }

    Use this new access token as a Bearer token going forward.

  3. Validating tokens (optional)

    You can validate a token’s status and get its remaining lifetime.
    Endpoint:

    POST /api/v2/token/validate/
    Host: app1.compliancely.com
    Content-Type: application/json

    Request body

    {
      "token": "eyJhbGciOiJIUz..."
    }

    Successful response (HTTP 200)

    {
      "token_type": "access",
      "valid": true,
      "expiry_seconds": 1799
    }

Error responses:

This section lists all possible responses for:

  • POST /api/v2/token/
  • POST /api/v2/token/refresh/
  • POST /api/v2/token/validate/

Use these to handle errors gracefully in your integration.

POST /api/v2/token/ – Obtain tokens

✅ Success (HTTP 200)

{
  "access": "<access_token>",
  "access_expiry_seconds": <expires_in_seconds>,
  "refresh": "<refresh_token>",
  "refresh_expiry_seconds": <expires_in_seconds>
}

❌ Validation Error (HTTP 400)
Missing required fields:

{
  "errors": [
    {
      "code": "username",
      "message": "This field is required."
    },
    {
      "code": "password",
      "message": "This field is required."
    }
  ]
}

❌ Malformed JSON (HTTP 400)

{
  "errors": [
    {
      "detail": "JSON parse error - Expecting ',' delimiter: line 3 column 5 (char 37)"
    }
  ]
}

❌ Authentication Failed (HTTP 401)
Invalid username or password:

{
  "errors": [
    {
      "detail": "Invalid username or password."
    }
  ]
}

❌ Forbidden (HTTP 403)

{
    "errors": [
        {
            "detail": "Account has been temporarily locked due to multiple failed login attempts. Please reset your password or contact support."
        }
    ]
}

❌ Forbidden ( HTTP 403 )

{
    "errors": [
        {
            "detail": "There is some problem with your account. Please contact support for further assistance."
        }
    ]
}

❌ Method Not Allowed (HTTP 405)

{
  "detail": "Method \"PUT\" not allowed."
}

❌ Unsupported Media Type (HTTP 415)

{
  "detail": "Unsupported media type \"text/plain\" in request."
}

❌ Too Many Requests (HTTP 429)
Rate limiting on token generation (10 requests/min):

{
  "detail": "Your request has been throttled due to exceeding the allowed rate limit. Please wait 26 seconds for time before trying again. If this issue persists, consider adjusting the request frequency or contact support for further assistance."
}

❌ Unexpected Error (HTTP 500)
Sometime no response too.

{
  "errors": [
    {
      "detail": "Something went wrong while processing your request"
    }
  ]
}

POST /api/v2/token/refresh/ – Refresh tokens

✅ Success (HTTP 200)

{
  "access": "<new_access_token>",
  "access_expiry_seconds": 3600
}

❌ Validation Error (HTTP 400)

{
  "errors": [
    {
      "code": "refresh",
      "message": "This field is required."
    }
  ]
}

❌ Invalid Token (HTTP 400)

{
  "errors": [
    {
      "code": "refresh",
      "detail": "Token is invalid or expired"
    }
  ]
}

❌ Malformed JSON (HTTP 400)

{
  "errors": [
    {
      "detail": "JSON parse error - Expecting ',' delimiter: line 3 column 5 (char 37)"
    }
  ]
}

❌ Blacklisted Token (HTTP 401)

{
  "errors": [
    {
      "detail": "Token is blacklisted"
    }
  ]
}

❌ Authentication Failed (HTTP 403)

{
  "errors": [
    {
      "detail": "There is some problem with your account. Please contact support for further assistance."
    }
  ]
}

❌ Method Not Allowed (HTTP 405)

{
  "detail": "Method \"PUT\" not allowed."
}

❌ Unsupported Media Type (HTTP 415)

{
  "detail": "Unsupported media type \"text/plain\" in request."
}

❌ Too Many Requests (HTTP 429)

{
  "detail": "Your request has been throttled due to exceeding the allowed rate limit. Please wait 26 seconds for time before trying again. If this issue persists, consider adjusting the request frequency or contact support for further assistance."
}

❌ Unexpected Error (HTTP 500)
Sometime no response too.

{
  "errors": [
    {
      "detail": "Something went wrong while processing your request"
    }
  ]
}

POST /api/v2/token/validate/ – Validate tokens

✅ Success (HTTP 200)

{
  "token_type": "access",
  "valid": true,
  "expiry_seconds": 3520
}

❌ Validation Error – Missing Field (HTTP 400)

{
  "errors": [
    {
      "code": "token",
      "message": "This field is required."
    }
  ]
}

❌ Invalid Token (HTTP 400)

{
  "errors": [
    {
      "detail": "Token is invalid or expired"
    }
  ]
}

❌ Malformed JSON (HTTP 400)

{
  "errors": [
    {
      "detail": "JSON parse error - Illegal trailing comma before end of object: line 2 column 243 (char 244)"
    }
  ]
}

❌ Blacklisted Token (HTTP 401)

{
  "errors": [
    {
      "detail": "Token is blacklisted"
    }
  ]
}

❌ Authentication Failed (HTTP 403)

{
  "errors": [
    {
      "detail": "There is some problem with your account. Please contact support for further assistance."
    }
  ]
}

❌ Method Not Allowed (HTTP 405)

{
  "detail": "Method \"PUT\" not allowed."
}

❌ Unsupported Media Type (HTTP 415)

{
  "detail": "Unsupported media type \"text/plain\" in request."
}

❌ Too Many Requests (HTTP 429)

{
  "detail": "Your request has been throttled due to exceeding the allowed rate limit. Please wait 26 seconds for time before trying again. If this issue persists, consider adjusting the request frequency or contact support for further assistance."
}

❌ Unexpected Error (HTTP 500)

{
  "errors": [
    {
      "detail": "Something went wrong while processing your request"
    }
  ]
}

FAQ

Q1. What happens if I keep using Basic Auth after the transition date?
A. API requests using Basic Authentication will start returning 403 Forbidden:

{
  "detail": "Authentication credentials were not provided."
}

Q2. Is there any rate limit for the token generation API?
A. Yes. To prevent abuse, there is a rate limit on token generation requests (10 requests/min). Please cache and reuse your tokens rather than requesting new ones constantly.

Q3. What will happen when my access token expires?
A. You will receive a 403 response:

{
  "detail": "Token is invalid or expired."
}

Use your refresh token with POST https://app1.compliancely.com/api/v2/token/refresh/ to obtain a new access token.

Q4. What should I do if my refresh token is also expired or invalid?
A. Call the login endpoint again:

POST https://app1.compliancely.com/api/v2/token/

Send your username and password to obtain a new access/refresh token pair.

Q5. Can I reuse the same refresh token multiple times?
A. Yes, you can reuse it until it expires or is invalidated/blacklisted.

Q6. Is there any change in error responses for invalid credentials when switching from Basic Auth to V2?

  • With Basic Authentication, invalid username or password returns:
    {
      "detail": "Invalid username/password."
    }
  • With Token Authentication, an invalid token will return 403 status code and below response
    {
        "detail": "Invalid token."
    }

Need help?

If you have questions or issues regarding this transition, contact:

[email protected]

We appreciate your cooperation as we work to make your integrations more secure.