Skip to main content

Overview

The revoke endpoint toggles a license status between ACTIVE and REVOKED. This allows you to temporarily or permanently disable a license without deleting it.

Endpoint

PATCH /license/revoke/:key
This endpoint requires authentication. Include a valid JWT token in the Authorization header.

Authentication

Include the JWT token in the Authorization header:
Authorization: Bearer <your-jwt-token>

Request

URL Parameters

key
string
required
The license key to revoke or reactivate

Example Request

curl -X PATCH https://your-keybox-server.com/license/revoke/KB-PROJ123-XXXX-XXXX-XXXX \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Response

Success Response

message
string
Description of the status change
key
string
The license key that was modified
status
string
The new status (“ACTIVE” or “REVOKED”)

Example Response - Revoked

{
  "message": "License status changed to REVOKED",
  "key": "KB-PROJ123-XXXX-XXXX-XXXX",
  "status": "REVOKED"
}

Example Response - Reactivated

{
  "message": "License status changed to ACTIVE",
  "key": "KB-PROJ123-XXXX-XXXX-XXXX",
  "status": "ACTIVE"
}

Toggle Behavior

The endpoint toggles the license status:
1

Check Current Status

Retrieve the current license status from the database
2

Toggle Status

If status is ACTIVE, change to REVOKEDIf status is REVOKED, change to ACTIVE
3

Save Changes

Update the license in the database
4

Invalidate Cache

Clear the Redis cache for this license to ensure fresh validation results
The toggle only works between ACTIVE and REVOKED states. Licenses with PENDING or EXPIRED status are not affected by this endpoint.

Cache Invalidation

When a license is revoked or reactivated:
  1. The license status is updated in MongoDB
  2. The Redis cache entry for this license is invalidated
  3. Next validation request will fetch fresh data from MongoDB
  4. The new status is then cached for future requests
This ensures that revocation takes effect immediately across all validation requests.

Impact on Validation

When Revoked

After revoking a license, validation attempts will return:
{
  "valid": false,
  "status": "revoked",
  "message": "License revoked by developer"
}

When Reactivated

After reactivating a license (toggle from REVOKED to ACTIVE), validation will succeed again:
{
  "valid": true,
  "status": "active",
  "duration": "12 months",
  "expiresAt": 1704067200000
}
Reactivating a license does not extend its expiration date. If the license expired while revoked, it will still be expired when reactivated.

Error Responses

Missing License Key

Status Code: 400
{
  "message": "License key is required"
}

License Not Found

Status Code: 404
{
  "message": "License not found"
}

Unauthorized

Status Code: 401
{
  "message": "No token provided"
}

Server Error

Status Code: 500
{
  "message": "Failed to toggle status",
  "error": "Detailed error message"
}

Use Cases

Revoke licenses when payment fails or subscription is cancelled. Reactivate when payment is resumed.
Temporarily revoke licenses for policy violations. Reactivate once issues are resolved.
Disable licenses during support investigations or account reviews.
Temporarily disable licenses for testing without deleting them.

Complete Example

class LicenseManager {
  constructor(serverUrl, authToken) {
    this.serverUrl = serverUrl;
    this.authToken = authToken;
  }

  async toggleLicense(licenseKey) {
    try {
      const response = await fetch(
        `${this.serverUrl}/license/revoke/${licenseKey}`,
        {
          method: 'PATCH',
          headers: {
            'Authorization': `Bearer ${this.authToken}`
          }
        }
      );

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      const data = await response.json();
      console.log(data.message);
      console.log(`New status: ${data.status}`);
      
      return data;
    } catch (error) {
      console.error('Failed to toggle license:', error);
      throw error;
    }
  }

  async revokeLicense(licenseKey) {
    const result = await this.toggleLicense(licenseKey);
    if (result.status !== 'REVOKED') {
      // If it's not revoked after toggle, toggle again
      return await this.toggleLicense(licenseKey);
    }
    return result;
  }

  async reactivateLicense(licenseKey) {
    const result = await this.toggleLicense(licenseKey);
    if (result.status !== 'ACTIVE') {
      // If it's not active after toggle, toggle again
      return await this.toggleLicense(licenseKey);
    }
    return result;
  }
}

// Usage
const manager = new LicenseManager(
  'https://your-keybox-server.com',
  'your-jwt-token'
);

// Toggle status
await manager.toggleLicense('KB-PROJ123-XXXX-XXXX-XXXX');

// Explicitly revoke
await manager.revokeLicense('KB-PROJ123-XXXX-XXXX-XXXX');

// Explicitly reactivate
await manager.reactivateLicense('KB-PROJ123-XXXX-XXXX-XXXX');

Best Practices

Audit Trail

Log all revocations and reactivations for compliance and auditing

User Communication

Notify users when their license is revoked or reactivated

Grace Period

Consider a grace period before revoking for payment issues

Automation

Automate revocation based on business rules (e.g., payment failures)

See Also

Build docs developers (and LLMs) love