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

# Revoke License

> Permanently revoke a license

Permanently revokes a license by changing its status to `revoked` and recording the revocation timestamp. Once revoked, the license cannot be activated on any device, and this action cannot be undone. The license will remain visible in reports and history for audit purposes.

This endpoint is useful for handling customer refunds, policy violations, or when a license needs to be immediately terminated for any reason. An optional reason parameter allows you to document why the license was revoked.

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

## Path Parameters

<ParamField path="licenseKey" type="string" required>
  The license key to revoke (e.g., `ABC-123-XYZ-789`)
</ParamField>

## Request Body

<ParamField body="reason" type="string">
  Optional reason for revocation. Max 500 characters. Useful for audit trails and customer support.
</ParamField>

## Response

<ResponseField name="data" type="object">
  <Expandable title="properties">
    <ResponseField name="id" type="string">
      Unique license identifier
    </ResponseField>

    <ResponseField name="license_key" type="string">
      The license key string
    </ResponseField>

    <ResponseField name="status" type="string">
      License status (will be `revoked`)
    </ResponseField>

    <ResponseField name="revoked_at" type="string">
      ISO 8601 timestamp when the license was revoked
    </ResponseField>

    <ResponseField name="activation_count" type="integer">
      Number of activations before revocation
    </ResponseField>

    <ResponseField name="max_activations" type="integer">
      Maximum number of activations (for reference)
    </ResponseField>

    <ResponseField name="activations_remaining" type="integer">
      Will show remaining count, but license cannot be activated
    </ResponseField>

    <ResponseField name="is_active" type="boolean">
      Will be `false` after revocation
    </ResponseField>

    <ResponseField name="can_activate" type="boolean">
      Will be `false` after revocation
    </ResponseField>

    <ResponseField name="product" type="object">
      Product information
    </ResponseField>
  </Expandable>
</ResponseField>

## Error Responses

<ResponseField name="400 Bad Request" type="object">
  Returned when the license has already been revoked
</ResponseField>

<ResponseField name="404 Not Found" type="object">
  Returned when the license key doesn't exist or doesn't belong to your store
</ResponseField>

<ResponseField name="422 Unprocessable Entity" type="object">
  Returned when validation fails (e.g., reason exceeds 500 characters)
</ResponseField>

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

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

  ```php PHP theme={null}
  $ch = curl_init('https://api.chariow.com/v1/licenses/ABC-123-XYZ-789/revoke');
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_HTTPHEADER, [
      'Authorization: Bearer YOUR_API_KEY',
      'Content-Type: application/json'
  ]);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
      'reason' => 'Customer requested refund'
  ]));
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $response = curl_exec($ch);
  ```
</RequestExample>

<ResponseExample>
  ```json Success (200) theme={null}
  {
    "message": "License revoked successfully",
    "data": {
      "id": "lic_abc123",
      "status": "revoked",
      "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": false,
      "is_expired": false,
      "can_activate": false,
      "activations": {
        "count": 3,
        "max": 10,
        "remaining": 7
      },
      "certificate_url": null,
      "metadata": null,
      "activated_at": "2025-01-15T10:30:00.000000Z",
      "expires_at": "2026-01-15T10:30:00.000000Z",
      "expired_at": null,
      "revoked_at": "2025-01-20T14:22:00.000000Z",
      "created_at": "2025-01-15T09:00:00.000000Z",
      "updated_at": "2025-01-20T14:22:00.000000Z"
    },
    "errors": []
  }
  ```

  ```json Already Revoked (400) theme={null}
  {
    "message": "License has already been revoked",
    "data": [],
    "errors": []
  }
  ```

  ```json Validation Error (422) theme={null}
  {
    "message": "The reason must not exceed 500 characters.",
    "data": [],
    "errors": {
      "reason": ["The reason must not exceed 500 characters."]
    }
  }
  ```

  ```json License Not Found (404) theme={null}
  {
    "message": "No query results for model [App\\Models\\IssuedLicense].",
    "data": [],
    "errors": []
  }
  ```
</ResponseExample>

## Common Use Cases

### Refund Processing

When processing a refund, revoke the license to prevent further use:

```javascript theme={null}
async function processRefund(licenseKey) {
  await fetch(`https://api.chariow.com/v1/licenses/${licenseKey}/revoke`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      reason: 'Full refund processed via payment gateway'
    })
  });
}
```

### Terms of Service Violation

Revoke licenses that violate your terms:

```javascript theme={null}
async function revokeViolation(licenseKey, violationType) {
  await fetch(`https://api.chariow.com/v1/licenses/${licenseKey}/revoke`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      reason: `Terms of service violation: ${violationType}`
    })
  });
}
```

### Fraudulent Purchase

Immediately revoke licenses from suspected fraudulent purchases:

```javascript theme={null}
async function revokeFraudulent(licenseKey) {
  await fetch(`https://api.chariow.com/v1/licenses/${licenseKey}/revoke`, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      reason: 'Suspected fraudulent purchase - payment flagged by gateway'
    })
  });
}
```

## What Happens After Revocation

Once a license is revoked:

1. **Status Change**: The license status becomes `revoked`
2. **Timestamp**: The `revoked_at` field is set to the current timestamp
3. **No Future Activations**: The license cannot be activated on any device
4. **Existing Activations**: Any existing activations remain in the system for audit purposes
5. **Permanent**: The revocation **cannot be undone** - you must issue a new license if needed
6. **Visible in Reports**: The license remains visible in your dashboard and API responses for historical tracking

## Alternative: Deactivating Individual Devices

If you want to free up an activation slot without permanently revoking the entire license, you should instead remove specific activations. This can be done through your store dashboard, allowing the license to be activated on a different device.

<Note>
  There is currently no Public API endpoint for deactivating individual device activations. This must be done through the store dashboard or Core API.
</Note>
