# API User Guide

How to retrieve API credentials, which endpoints are available, how payloads should be structured, and what responses to expect.

Updated: Aug 28, 2026
Source: https://activelayer.com/docs/api/
## Overview

This guide walks through the ActiveLayer REST API: how to retrieve API credentials, which endpoints are available, how payloads should be structured, and what responses to expect. Use it as the canonical integration reference for engineering, QA, and support teams.

**Base URL:** `https://api.activelayer.com/api/v1`

**Formats:** JSON request and response payloads

**Versioning:** Current stable version: `v1`

## Quick Start Checklist

- **Generate an API key** — Create an API token in the [ActiveLayer dashboard](https://activelayer.com/) under **API Tokens**.

- **Verify the key** — Call `GET /api/v1/verify` to ensure the token is active before integrating.

- **Send a test request** — Call `POST /api/v1/check` with the cURL snippet below or import the endpoint into Postman.

- **Persist detection IDs** — Log the returned `detection_id` for later audits and feedback submissions.

- **Monitor usage** — Keep an eye on `GET /api/v1/stats` (or your internal metrics) to confirm traffic stays within plan limits.

## Getting an API Key

- Register or sign in at [https://activelayer.com/](https://activelayer.com/).

- Open your workspace settings and select **API Tokens**.

- Create a new key or copy an existing one. Newly generated keys are shown once—store them securely.

- If the UI does not allow self-service tokens on your plan, contact support or your account manager to provision a key.

## Authentication

- Send `Authorization: Bearer ` with every request.

- Compatibility headers include `X-API-Key` or an `api_key` field in the body/query string (discouraged in production).

- All traffic must use HTTPS. Missing, invalid, or revoked keys return `401 Unauthorized`.

## Rate Limiting

Each API key is limited to 50 requests per minute and a monthly quota defined by your plan. Exceeding these limits triggers `429 Rate Limit Exceeded` responses with `remaining: 0`.

## Headers & Payload Requirements

Set both headers on every call and send valid JSON payloads:

- `Content-Type: application/json`

- `Accept: application/json`

## POST /api/v1/check

Full spam analysis for longer submissions such as emails, support tickets, or contact forms.

### Request Fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| message | `string` | **Yes** | Text to analyse (email body, form submission, chat message, etc.). |
| email | `string` | No | Sender email address (max 255 characters). |
| name | `string` | No | Author name or nickname. |
| ip | `string` | No | User IPv4/IPv6 address. Defaults to the request IP if omitted. |
| timestamp | `integer` | No | UNIX timestamp for when the content was created. |
| user_agent | `string` | No | Browser or client User-Agent string. |
| website_url | `string (URL)` | No | Source page URL for the submission. |
| domain | `string` | No | Domain associated with the content (helpful for account validation). |

### Sample Request (cURL)

```
curl -X POST "https://api.activelayer.com/api/v1/check" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Hi! I can deliver 1,000 followers for just $5.",
    "email": "sender@example.com",
    "name": "Cheap Leads Bot",
    "ip": "203.0.113.42",
    "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
    "website_url": "https://blog.example.com/contact"
  }'
```

### Sample Response

```
{
  "detection_id": "4b6c9c42-63d6-4eac-9ff7-1965b0dbc1c9",
  "is_spam": true,
  "total_score": 86.4,
  "threshold": 50,
  "execution_time": 121.37,
  "timestamp": "2025-02-15T11:32:18.214Z"
}
```

### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `detection_id` | `string` | Unique identifier you can reference in audits, feedback, or support tickets. |
| `is_spam` | `boolean` | `true` means the spam threshold was met or exceeded. |
| `total_score` | `float` | Aggregate spam score. Higher values indicate stronger spam signals. |
| `threshold` | `float` | Score required for the detector to classify content as spam. |
| `execution_time` | `float` | Processing time in milliseconds. |
| `timestamp` | `string (ISO 8601)` | Timestamp when the response was generated. |

### PHP Example (Guzzle)

```
 'https://api.activelayer.com/api/v1/',
    'timeout' => 5.0,
]);
$response = $client->post('check', [
    'headers' => [
        'Authorization' => 'Bearer ' . getenv('ACTIVELAYER_API_KEY'),
        'Accept' => 'application/json',
    ],
    'json' => [
        'message' => 'Need more traffic? Buy 10k visitors today!',
        'email' => 'sender@example.com',
        'ip' => '198.51.100.87',
    ],
]);
$result = json_decode($response->getBody()->getContents(), true);
if ($result['is_spam']) {
    // Flag the content or block the user here.
}
```

Keep the `detection_id` alongside the original content to support audits or feedback submissions.

## POST /api/v1/check-comment

Optimised for comment or review widgets where you only need a yes/no verdict and a lightweight payload. Accepts the same fields as `/check`.

### Request Fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| message | `string` | **Yes** | Comment or review text to evaluate. |
| email | `string` | No | Commenter email address, if collected. |
| name | `string` | No | Display name or nickname shown publicly. |
| ip | `string` | No | Originating IP address; falls back to the request IP if omitted. |
| timestamp | `integer` | No | UNIX timestamp when the comment was submitted. |
| user_agent | `string` | No | Client or browser user agent string. |

### Sample Request (cURL)

```
curl -X POST "https://api.activelayer.com/api/v1/check-comment" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Great article! Check out my crypto scheme at http://spam.biz",
    "email": "sender@example.com",
    "ip": "198.51.100.12"
  }'
```

### Sample Response

```
{
  "detection_id": "207e3b47-5f47-42dd-bc0b-775c3e387c33",
  "is_spam": false,
  "total_score": 18.45,
  "threshold": 50,
  "execution_time": 64.09,
  "timestamp": "2025-02-15T11:34:09.817Z"
}
```

### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `detection_id` | `string` | Identifier to use for logging, audits, or feedback. |
| `is_spam` | `boolean` | Final verdict for the comment payload. |
| `total_score` | `float` | Aggregate score calculated for the comment. |
| `threshold` | `float` | Score threshold used for classification. |
| `execution_time` | `float` | Processing time in milliseconds. |
| `timestamp` | `string (ISO 8601)` | Response generation time. |

Use this endpoint when you want the smallest possible JSON response and do not need the extended signal report.

## POST /api/v1/feedback

Submit moderator feedback to improve detection quality.

### Request Fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| detection_id | `string` | **Yes** | Identifier returned by `/check` or `/check-comment`. |
| is_spam | `boolean` | **Yes** | Final label chosen by your system or moderators. |

### Sample Request (cURL)

```
curl -X POST "https://api.activelayer.com/api/v1/feedback" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "detection_id": "4b6c9c42-63d6-4eac-9ff7-1965b0dbc1c9",
    "is_spam": false
  }'
```

### Sample Response

```
{
  "success": true,
  "message": "Feedback submitted and will be processed shortly",
  "data": {
    "detection_id": "4b6c9c42-63d6-4eac-9ff7-1965b0dbc1c9",
    "user_status": true,
    "queued_at": "2025-02-15T11:36:42.055Z"
  }
}
```

### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `success` | `boolean` | Indicates whether the feedback request was accepted for processing. |
| `message` | `string` | Human-readable confirmation or error message. |
| `data.detection_id` | `string` | Echoes the detection you submitted, so you can correlate the acknowledgement. |
| `data.user_status` | `boolean` | The classification you supplied (`true` for spam, `false` for ham). |
| `data.queued_at` | `string (ISO 8601)` | Server timestamp showing when the feedback job entered the queue. |

Error responses follow the same structure described in [Common Errors](#common-errors) (for example, `404` when a `detection_id` is unknown).

## GET /api/v1/verify

Confirm an API key is active and view metadata about the owner.

### Request Requirements

- **Method:** `GET`

- **Path:** `/api/v1/verify`

- **Headers:** `Authorization: Bearer YOUR_API_KEY`, `Accept: application/json`

- No query parameters or body payload are required.

### Sample Response

```
{
  "valid": true,
  "message": "API key is valid",
  "key_info": {
    "name": "Production key",
    "created_at": "2024-11-19T09:22:11Z",
    "last_used_at": "2025-02-15T11:36:55Z"
  },
  "user_info": {
    "id": 481,
    "email": "sender@example.com",
    "name": "Example Ops"
  },
  "timestamp": "2025-02-15T11:36:55.301Z"
}
```

### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `valid` | `boolean` | Indicates whether the presented key is active. |
| `message` | `string` | Human-readable summary of the verification result. |
| `key_info.name` | `string` | Friendly label assigned to the API token. |
| `key_info.created_at` | `string (ISO 8601)` | Date and time the token was created. |
| `key_info.last_used_at` | `string (ISO 8601 | null)` | Timestamp of the most recent successful API call using this key. |
| `user_info.id` | `integer` | Internal identifier of the user who owns the key. |
| `user_info.email` | `string` | Contact email associated with the account. |
| `user_info.name` | `string` | Name of the user tied to the key (if provided). |
| `timestamp` | `string (ISO 8601)` | Server timestamp when the verification response was generated. |

## GET /api/v1/stats

Retrieve current plan usage to manage quotas and alerting.

### Request Requirements

- **Method:** `GET`

- **Path:** `/api/v1/stats`

- **Headers:** `Authorization: Bearer YOUR_API_KEY`, `Accept: application/json`

- No body parameters are required; stats are derived from the authenticated account.

### Sample Response

```
{
  "success": true,
  "data": {
    "plan": {
      "name": "Business",
      "id": 3
    },
    "usage": {
      "total_requests": 50000,
      "used_requests": 3125,
      "remaining_requests": 46875,
      "usage_percentage": 6.25
    },
    "period": {
      "month": 2,
      "year": 2025
    }
  },
  "timestamp": "2025-02-15T11:37:12.648Z"
}
```

### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `success` | `boolean` | Indicates whether the stats lookup succeeded. |
| `data.plan.name` | `string` | Name of the plan associated with the key. |
| `data.plan.id` | `integer` | Internal identifier for the plan. |
| `data.usage.total_requests` | `integer` | Monthly quota allocated to the plan. |
| `data.usage.used_requests` | `integer` | Requests consumed in the current billing period. |
| `data.usage.remaining_requests` | `integer` | Requests still available before the quota resets. |
| `data.usage.usage_percentage` | `float` | Percentage of the allocated quota already used. |
| `data.period.month` | `integer` | Month the stats snapshot refers to. |
| `data.period.year` | `integer` | Year the stats snapshot refers to. |
| `timestamp` | `string (ISO 8601)` | Server timestamp when the stats were generated. |

## Common Errors

| Status | When it happens | Sample payload |
| --- | --- | --- |
| **401 Unauthorized** | Key missing, invalid, or revoked. | `{"error":"Invalid API key","message":"The provided API key is not valid"}` |
| **403 Forbidden** | User has no active subscription plan. | `{"error":"No Plan","message":"User has no active plan"}` |
| **404 Not Found** | `detection_id` not found during feedback submission. | `{"error":"Detection not found","error_details":"No spam detection found with this detection_id"}` |
| **422 Unprocessable Entity** | Validation rules violated. | `{"error":"Validation failed","errors":{"message":["The message field is required."]}}` |
| **429 Too Many Requests** | Per-minute or monthly quota exceeded. | `{"error":"Rate Limit Exceeded","message":"Monthly request limit exceeded","limit":50000,"used":50000,"remaining":0}` |
| **500 Internal Server Error** | Unexpected server-side exception. | `{"error":"Internal server error","message":"An error occurred while processing your request."}` |

## Testing & Sample Payloads

- **Spam sample:** “Exclusive offer! Buy verified leads now and get 300% ROI. Click here: http://cheap-leads.biz/offer.”

- **Ham sample:** “Hey team, attached is the weekly report. Let me know if you need any follow-up data.”

- Verify keys first with `GET /verify`. Regenerate tokens if you receive `401`.

- Store API keys in environment variables or CI secrets (e.g., `ACTIVELAYER_API_KEY`), never hardcode them.

## Integration Tips

- Persist every `detection_id` with the source content for audits and feedback.

- Retry on `429` with exponential backoff and monitor remaining quotas.

- Add a deployment or runtime health-check that calls `/verify` to ensure credentials remain active.

- Avoid sending unnecessary personal data to minimise compliance risk.

- Keep SDKs and client libraries updated; API changes are announced in the changelog.

## Troubleshooting FAQ

### Getting 401 Unauthorized?

Confirm the request includes `Authorization: Bearer YOUR_API_KEY` and that the key is still listed under **API Tokens**. Keys are revoked immediately when deleted.

### Seeing 403 or 429 responses?

Check `/stats` to confirm plan status and remaining quota. Upgrade or wait for the next billing cycle if limits are reached.

### Need deeper insight into a detection?

Share the `detection_id`, timestamp, and sample payload with support. Logs are indexed by those fields.

### Experiencing high latency?

Send requests from regions close to ActiveLayer infrastructure and consider asynchronous workflows if p95 latency affects user flows.

## Support

- **Technical support:** sender@example.com

- **Billing or quota changes:** Contact your account manager or the support team.
