From checkpoint-avanan
Provides OAuth2 client credentials authentication, token management, rate limiting, pagination, error handling, and request patterns for Checkpoint Harmony Email (Avanan) API.
npx claudepluginhub wyre-technology/msp-claude-plugins --plugin checkpoint-avananThis skill uses the workspace's default tool permissions.
The Checkpoint Harmony Email & Collaboration (Avanan) API provides programmatic access to email security operations including quarantine management, threat detection, policy configuration, and incident management. This skill covers authentication, request patterns, pagination, rate limiting, error handling, and performance optimization.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Designs, implements, and audits WCAG 2.2 AA accessible UIs for Web (ARIA/HTML5), iOS (SwiftUI traits), and Android (Compose semantics). Audits code for compliance gaps.
The Checkpoint Harmony Email & Collaboration (Avanan) API provides programmatic access to email security operations including quarantine management, threat detection, policy configuration, and incident management. This skill covers authentication, request patterns, pagination, rate limiting, error handling, and performance optimization.
Checkpoint Harmony Email uses OAuth2 client credentials for API authentication:
Step 1: Obtain Access Token
POST https://cloudinfra-gw.portal.checkpoint.com/auth/external
Content-Type: application/json
{
"clientId": "YOUR_CLIENT_ID",
"accessKey": "YOUR_CLIENT_SECRET"
}
Response:
{
"data": {
"token": "eyJhbGciOiJSUzI1NiIs...",
"expiresIn": 3600,
"csrfToken": "abc123..."
}
}
Step 2: Use Token in Subsequent Requests
GET https://cloudinfra-gw.portal.checkpoint.com/app/hec-api/v1.0/quarantine
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Content-Type: application/json
| Field | Description |
|---|---|
token | JWT bearer token for API requests |
expiresIn | Token lifetime in seconds (typically 3600 = 1 hour) |
csrfToken | CSRF token for state-changing operations |
Token Refresh Pattern:
class CheckpointAuth {
constructor(clientId, clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.token = null;
this.expiresAt = 0;
}
async getToken() {
// Refresh 5 minutes before expiry
if (this.token && Date.now() < this.expiresAt - 300000) {
return this.token;
}
const response = await fetch(
'https://cloudinfra-gw.portal.checkpoint.com/auth/external',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
clientId: this.clientId,
accessKey: this.clientSecret
})
}
);
const data = await response.json();
this.token = data.data.token;
this.expiresAt = Date.now() + (data.data.expiresIn * 1000);
return this.token;
}
}
export CHECKPOINT_CLIENT_ID="your-client-id"
export CHECKPOINT_CLIENT_SECRET="your-client-secret"
export CHECKPOINT_AVANAN_MCP_URL="https://checkpoint-avanan-mcp.wyre.workers.dev/mcp"
| Environment | Base URL |
|---|---|
| Production (US) | https://cloudinfra-gw.portal.checkpoint.com |
| Production (EU) | https://cloudinfra-gw-eu.portal.checkpoint.com |
| Production (AP) | https://cloudinfra-gw-ap.portal.checkpoint.com |
| Service | Path Prefix | Description |
|---|---|---|
| Authentication | /auth/external | OAuth2 token endpoint |
| Email Security | /app/hec-api/v1.0 | Harmony Email & Collaboration API |
| Quarantine | /app/hec-api/v1.0/quarantine | Quarantine operations |
| Threats | /app/hec-api/v1.0/threats | Threat detection data |
| Policies | /app/hec-api/v1.0/policies | Policy management |
| Incidents | /app/hec-api/v1.0/incidents | Incident management |
The API region depends on where the tenant was provisioned. Use the portal URL to determine the correct API gateway:
| Portal URL | API Gateway |
|---|---|
portal.checkpoint.com | cloudinfra-gw.portal.checkpoint.com |
portal.checkpoint.com (EU data) | cloudinfra-gw-eu.portal.checkpoint.com |
portal.checkpoint.com (AP data) | cloudinfra-gw-ap.portal.checkpoint.com |
GET /app/hec-api/v1.0/quarantine?startDate=2024-02-01&endDate=2024-02-15&limit=50
Authorization: Bearer <token>
Content-Type: application/json
POST /app/hec-api/v1.0/quarantine/release
Authorization: Bearer <token>
Content-Type: application/json
{
"entityIds": ["qe-abc123", "qe-def456"],
"releaseToRecipients": true,
"addToAllowList": false
}
| Parameter | Type | Description | Default |
|---|---|---|---|
startDate | string (ISO 8601) | Start of date range filter | Required for list operations |
endDate | string (ISO 8601) | End of date range filter | Required for list operations |
limit | int | Maximum results per page | 50 |
offset | int | Number of results to skip | 0 |
sortBy | string | Field to sort by | detectedDate |
sortOrder | string | ASC or DESC | DESC |
GET /app/hec-api/v1.0/threats?startDate=2024-02-01&endDate=2024-02-15&limit=50&offset=0
Response:
{
"data": [...],
"pagination": {
"total": 237,
"limit": 50,
"offset": 0,
"hasMore": true
}
}
async function fetchAllPages(endpoint, params) {
const allItems = [];
let offset = 0;
const limit = 100;
let hasMore = true;
while (hasMore) {
const response = await fetch(`${endpoint}?${new URLSearchParams({
...params,
limit: limit.toString(),
offset: offset.toString()
})}`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
allItems.push(...data.data);
hasMore = data.pagination.hasMore;
offset += limit;
}
return allItems;
}
| Parameter | Maximum | Notes |
|---|---|---|
limit | 200 | Results per page |
| Date range | 90 days | Maximum date range per query |
| Total results | 10,000 | Maximum results per query (paginate within this) |
| Limit Type | Value | Scope |
|---|---|---|
| Requests per minute | 60 | Per API key |
| Requests per hour | 1,000 | Per API key |
| Concurrent requests | 5 | Per API key |
| Bulk operations per request | 100 | Per batch operation |
When rate limited, the API returns HTTP 429:
HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1708012800
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Retry after 30 seconds."
}
}
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Remaining requests in current window |
X-RateLimit-Reset | Unix timestamp when the window resets |
Retry-After | Seconds to wait before retrying (on 429) |
async function requestWithRetry(url, options, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '30');
const jitter = Math.random() * 2000;
await sleep(retryAfter * 1000 + jitter);
continue;
}
if (response.status === 401) {
// Token expired - refresh and retry
options.headers['Authorization'] = `Bearer ${await auth.getToken()}`;
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
// Exponential backoff with jitter
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000;
await sleep(delay);
}
}
}
| Code | Meaning | Action |
|---|---|---|
| 200 | Success | Process response |
| 201 | Created | Entity created successfully |
| 204 | No Content | Operation succeeded, no body |
| 400 | Bad Request | Check request format/values |
| 401 | Unauthorized | Refresh token or check credentials |
| 403 | Forbidden | Check API key permissions/scope |
| 404 | Not Found | Entity doesn't exist |
| 409 | Conflict | Resource conflict (e.g., already released) |
| 422 | Unprocessable Entity | Validation failed |
| 429 | Rate Limited | Implement backoff with Retry-After |
| 500 | Server Error | Retry with exponential backoff |
| 503 | Service Unavailable | Temporary outage, retry later |
{
"error": {
"code": "INVALID_REQUEST",
"message": "The field 'startDate' is required for list operations.",
"details": [
{
"field": "startDate",
"message": "This field is required"
}
]
}
}
| Error Code | Scenario | Resolution |
|---|---|---|
INVALID_TOKEN | Token expired or malformed | Re-authenticate and obtain new token |
INVALID_REQUEST | Missing or invalid parameters | Check request against API docs |
ENTITY_NOT_FOUND | Quarantine/threat/incident not found | Verify entity ID |
ALREADY_PROCESSED | Email already released/deleted | No action needed |
PERMISSION_DENIED | API key lacks required scope | Update API key permissions |
RATE_LIMIT_EXCEEDED | Too many requests | Implement backoff strategy |
DATE_RANGE_EXCEEDED | Date range exceeds 90 days | Narrow the date range |
// Good: Fetch related data in one request with includes
const threat = await client.threats.get('threat-abc123', {
include: ['iocs', 'timeline', 'relatedEmails']
});
// Avoid: Multiple separate requests
const threat = await client.threats.get('threat-abc123');
const iocs = await client.threats.getIOCs('threat-abc123');
const timeline = await client.threats.getTimeline('threat-abc123');
// Good: Independent endpoints in parallel
const [quarantine, threats, incidents] = await Promise.all([
client.quarantine.list({ startDate, endDate }),
client.threats.list({ startDate, endDate }),
client.incidents.list({ startDate, endDate })
]);
// Avoid: Sequential requests for independent data
const quarantine = await client.quarantine.list({ startDate, endDate });
const threats = await client.threats.list({ startDate, endDate });
const incidents = await client.incidents.list({ startDate, endDate });
Cache slowly-changing data to reduce API calls: