> ## Documentation Index
> Fetch the complete documentation index at: https://chariow.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Licenses

> Learn how to manage software licenses via the Chariow API

Chariow provides built-in license key management for software products. Licenses are automatically generated when customers purchase license-type products and can be activated, validated, and revoked through the API.

## License Object

A license contains comprehensive information about its status, activation history, and validity:

```json theme={null}
{
  "id": "lic_abc123",
  "status": "active",
  "customer": {
    "id": "cus_xyz789",
    "name": "John Doe",
    "email": "john@example.com"
  },
  "product": {
    "id": "prd_abc456",
    "name": "Premium Software License",
    "slug": "premium-software-license"
  },
  "license": {
    "key": "ABC-123-XYZ-789",
    "masked_key": "ABC-***-***-789"
  },
  "is_active": true,
  "is_expired": false,
  "can_activate": true,
  "activations": {
    "count": 3,
    "max": 10,
    "remaining": 7
  },
  "certificate_url": "https://api.chariow.com/certificates/lic_abc123.pdf",
  "metadata": null,
  "activated_at": "2025-01-15T10:30:00.000000Z",
  "expires_at": "2026-01-15T10:30:00.000000Z",
  "expired_at": null,
  "revoked_at": null,
  "created_at": "2025-01-15T09:00:00.000000Z",
  "updated_at": "2025-01-15T10:30:00.000000Z"
}
```

### Key Fields

* **`license.key`**: The unique license key string (e.g., `ABC-123-XYZ-789`)
* **`license.masked_key`**: Masked version for display (e.g., `ABC-***-***-789`)
* **`status`**: Current license status (see table below)
* **`is_active`**: Boolean indicating if the license is currently active and usable
* **`is_expired`**: Boolean indicating if the license has expired
* **`can_activate`**: Boolean indicating if the license can be activated (has remaining slots)
* **`activations.count`**: Current number of device activations
* **`activations.max`**: Maximum allowed activations
* **`activations.remaining`**: Number of activation slots remaining
* **`certificate_url`**: URL to download the license certificate (if available)
* **`activated_at`**: When the license was first activated (null if never activated)
* **`expires_at`**: When the license will expire (null for lifetime licenses)
* **`revoked_at`**: When the license was revoked (null if not revoked)

## License Statuses

| Status               | Description                            |
| -------------------- | -------------------------------------- |
| `pending_activation` | License created but not yet activated  |
| `active`             | License is activated and valid for use |
| `expired`            | License has passed its expiration date |
| `revoked`            | License has been permanently revoked   |

## Listing Licenses

Retrieve all issued licenses for your store:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.chariow.com/v1/licenses" \
    -H "Authorization: Bearer sk_live_your_api_key"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.chariow.com/v1/licenses', {
    headers: {
      'Authorization': 'Bearer sk_live_your_api_key'
    }
  });

  const { data } = await response.json();
  ```
</CodeGroup>

### Query Parameters

| Parameter     | Type    | Description                                                             |
| ------------- | ------- | ----------------------------------------------------------------------- |
| `per_page`    | integer | Number of licenses per page (default 50, max 100)                       |
| `cursor`      | string  | Pagination cursor from previous response                                |
| `status`      | string  | Filter by status (`pending_activation`, `active`, `expired`, `revoked`) |
| `customer_id` | string  | Filter by customer public ID (e.g., `cus_abc123`)                       |
| `product_id`  | string  | Filter by product public ID (e.g., `prd_def456`)                        |

### Filtering Examples

```bash theme={null}
# Get active licenses only
curl -X GET "https://api.chariow.com/v1/licenses?status=active" \
  -H "Authorization: Bearer sk_live_your_api_key"

# Get licenses for a specific product
curl -X GET "https://api.chariow.com/v1/licenses?product_id=prd_abc123" \
  -H "Authorization: Bearer sk_live_your_api_key"

# Get licenses for a specific customer
curl -X GET "https://api.chariow.com/v1/licenses?customer_id=cus_xyz789" \
  -H "Authorization: Bearer sk_live_your_api_key"
```

## Getting a License by Key

Retrieve a specific license using its license key:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789" \
    -H "Authorization: Bearer sk_live_your_api_key"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.chariow.com/v1/licenses/ABC-123-XYZ-789', {
    headers: {
      'Authorization': 'Bearer sk_live_your_api_key'
    }
  });

  const { data } = await response.json();
  ```
</CodeGroup>

## Validating a License

To validate a license in your application, retrieve it and check the status:

```javascript theme={null}
async function validateLicense(licenseKey) {
  const response = await fetch(
    `https://api.chariow.com/v1/licenses/${licenseKey}`,
    { headers: { 'Authorization': 'Bearer sk_live_your_api_key' }}
  );

  if (!response.ok) {
    return { valid: false, reason: 'License not found' };
  }

  const { data } = await response.json();

  if (!data.is_active) {
    return { valid: false, reason: 'License is not active' };
  }

  if (data.is_expired) {
    return { valid: false, reason: 'License has expired' };
  }

  return { valid: true, license: data };
}
```

## Activating a License

Activate a license on a device. The system automatically captures IP address and user agent:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/activate" \
    -H "Authorization: Bearer sk_live_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "device_identifier": "00:1B:44:11:3A:B7"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/activate',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer sk_live_your_api_key',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        device_identifier: '00:1B:44:11:3A:B7'  // MAC address, UUID, etc.
      })
    }
  );
  ```
</CodeGroup>

### First Activation Behaviour

On the first activation:

* Status changes from `pending_activation` to `active`
* `activated_at` timestamp is set
* `expires_at` is calculated based on product validity period
* `activation_count` increments to 1

### Subsequent Activations

On additional activations:

* `activation_count` is incremented
* A new activation record is created
* License status remains `active`

### Activation Limits

Each license has a maximum number of activations (`max_activations`). When the limit is reached, further activations will fail:

```json theme={null}
{
  "message": "Activation limit reached",
  "data": [],
  "errors": []
}
```

Check `can_activate` and `activations.remaining` before attempting activation.

## Revoking a License

Revoke a license to prevent further use:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/revoke" \
    -H "Authorization: Bearer sk_live_your_api_key" \
    -H "Content-Type: application/json" \
    -d '{
      "reason": "Customer requested refund"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/revoke',
    {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer sk_live_your_api_key',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        reason: 'Customer requested refund'
      })
    }
  );
  ```
</CodeGroup>

<Warning>
  Revoking a license is permanent. The license cannot be reactivated after revocation.
</Warning>

## Getting Activation History

View all activations for a specific license with detailed device tracking:

```bash theme={null}
curl -X GET "https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/activations?per_page=20" \
  -H "Authorization: Bearer sk_live_your_api_key"
```

### Response

```json theme={null}
{
  "data": [
    {
      "id": "act_abc123",
      "activated_by": {
        "ip": {
          "value": "203.0.113.45",
          "country": {
            "code": "US",
            "name": "United States"
          }
        },
        "user_agent": {
          "browser": "Chrome",
          "platform": "Windows",
          "device": "desktop"
        },
        "device": "00:1B:44:11:3A:B7"
      },
      "metadata": null,
      "activated_at": "2025-01-18T15:42:00.000000Z",
      "created_at": "2025-01-18T15:42:00.000000Z"
    },
    {
      "id": "act_def456",
      "activated_by": {
        "ip": {
          "value": "198.51.100.12",
          "country": {
            "code": "FR",
            "name": "France"
          }
        },
        "user_agent": {
          "browser": "Safari",
          "platform": "macOS",
          "device": "desktop"
        },
        "device": "A4:5E:60:D8:2F:11"
      },
      "metadata": null,
      "activated_at": "2025-01-16T09:15:00.000000Z",
      "created_at": "2025-01-16T09:15:00.000000Z"
    }
  ],
  "pagination": {
    "count": 2,
    "per_page": 20,
    "next_cursor": null,
    "prev_cursor": null,
    "has_more_pages": false
  }
}
```

### What's Tracked

Each activation record contains:

* **IP Address**: Automatically captured from the activation request, with geolocation
* **User Agent**: Parsed browser and platform information
* **Device Identifier**: Optional identifier you provide (MAC address, UUID, etc.)
* **Timestamp**: When the activation occurred
* **Metadata**: Optional custom data

This is useful for:

* Auditing license usage
* Detecting suspicious activity
* Providing customers with device management
* Debugging activation issues

## Implementation Example

Here's a complete example of license validation in a desktop application:

```javascript theme={null}
class LicenseManager {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.chariow.com/v1';
  }

  async validate(licenseKey) {
    const response = await fetch(
      `${this.baseUrl}/licenses/${licenseKey}`,
      { headers: { 'Authorization': `Bearer ${this.apiKey}` }}
    );

    if (!response.ok) {
      throw new Error('Invalid license key');
    }

    const { data } = await response.json();

    if (!data.can_activate) {
      throw new Error('License cannot be activated');
    }

    return data;
  }

  async activate(licenseKey, deviceId) {
    const response = await fetch(
      `${this.baseUrl}/licenses/${licenseKey}/activate`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ device_identifier: deviceId })
      }
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message);
    }

    return response.json();
  }
}

// Usage
const manager = new LicenseManager('sk_live_your_api_key');

try {
  const license = await manager.validate('ABC-123-XYZ-789');
  console.log('License valid:', license.is_active);

  await manager.activate('ABC-123-XYZ-789', getDeviceId());
  console.log('License activated successfully');
} catch (error) {
  console.error('License error:', error.message);
}
```

## API Endpoints Summary

| Endpoint                                | Method | Description                      |
| --------------------------------------- | ------ | -------------------------------- |
| `/v1/licenses`                          | GET    | List all licenses with filtering |
| `/v1/licenses/{licenseKey}`             | GET    | Get specific license details     |
| `/v1/licenses/{licenseKey}/activate`    | POST   | Activate license on a device     |
| `/v1/licenses/{licenseKey}/revoke`      | POST   | Permanently revoke a license     |
| `/v1/licenses/{licenseKey}/activations` | GET    | Get activation history           |

## Best Practices

### Security

* Never expose your API key in client-side code
* Use API keys server-side only
* Validate licenses server-side before granting access
* Store license keys securely on the customer's device

### Device Identification

* Use unique, persistent device identifiers (MAC address, hardware UUID)
* Don't use user-changeable identifiers (computer name, username)
* Consider platform-specific identifiers (Windows: machine GUID, macOS: hardware UUID)

### Activation Management

* Check `can_activate` before attempting activation
* Display `activations_remaining` to users
* Implement device management UI for customers
* Handle activation errors gracefully

### Validation Frequency

* Validate on application startup
* Re-validate periodically (e.g., every 24 hours)
* Cache validation results locally
* Implement offline grace period

### Error Handling

* Handle network errors gracefully
* Provide clear error messages to users
* Implement retry logic with exponential backoff
* Log activation attempts for debugging

## Related Resources

<CardGroup cols={2}>
  <Card title="Products Guide" icon="box" href="/en/guides/products">
    Create license-type products
  </Card>

  <Card title="Licenses API" icon="code" href="/api-reference/licenses/list-licenses">
    View the complete Licenses API reference
  </Card>

  <Card title="Get License" icon="key" href="/api-reference/licenses/get-license">
    Retrieve license details
  </Card>

  <Card title="Activate License" icon="check" href="/api-reference/licenses/activate-license">
    Activate on a device
  </Card>
</CardGroup>
