Query your simulation campaigns (phishing, credential harvesting, ransomware) from your own systems: reporting, internal dashboards, integrations with your SIEM, etc.
Base URL: all endpoints live under the prefix {{base_url}}/api/companies/v1.
To get the production host (
base_url), contact your Whalemate representative or write to us through the support chat.
Authentication: X-API-KEY header.
X-API-KEY: tu_api_key_de_empresa
Generate or view your key from Configuración → Integraciones → card Claves API → Claves Activas. Details in API keys: how to generate, use, and revoke them.
The company is resolved automatically from the API Key: you don't send company_id, and each request operates only on your company's campaigns.
Header | Value | Required |
|---|---|---|
| Your company API Key | ✅ Yes |
|
| ✅ Yes |
GET {{base_url}}/api/companies/v1/campaigns
Returns all the campaigns that match the filter, as a flat array, not paginated.
Param | Type | Default | Description |
|---|---|---|---|
| date (YYYY-MM-DD) | 1 month ago |
|
| date (YYYY-MM-DD) | today |
|
Without filter[from]/filter[to] the default range applies (last month). There is no filter by status.
Example: GET {{base_url}}/api/companies/v1/campaigns?filter[from]=2025-10-01&filter[to]=2025-10-31
Response (200 OK):
[
{
"id": 88,
"name": "Campaña Q4 - Phishing bancario",
"launch_date": "2025-10-05 09:00:00",
"send_by_date": "2025-10-05 18:00:00",
"closes_at": "2025-10-12 09:00:00",
"type": "Ransomware",
"victims_count": 134,
"stats": {
"email_sent": 134, "email_opened": 98, "clicked_link": 41,
"email_reported": 12, "credential_harvesting": 9
}
}
]Sorted by launch_date descending. type: Click Only | Credential Harvesting | Ransomware. closes_at is null if no close is configured. All dates/times in the response are in UTC.
stats: independent counter per event type, excluding events after the close (closes_at):
Field | Counts events of type |
|---|---|
|
|
|
|
|
|
|
|
|
|
GET {{base_url}}/api/companies/v1/campaigns-v2
Same information as GET /campaigns, but paginated: of GET /campaigns, but paginated: returns at most pat most per_page campañas por request, envuer_pagetas campaignnks/me per requesta. Designed for companies with many campaigns, where fetching everything in a single response is impractical. Use this endpoint if your integration can handle pagination; if you prefer to keep receiving the full array, GET /c, GET /campaimpaigns no cs does not change.
Param | Type | Default | Default | Description |
|---|---|---|---|---|
| date (YYYY-MM-DD) | 1 month ago |
|
|
| date (YYYY-MM-DD) | today |
| |
| integer | 50 | Campaigns per page. Must be an integer between 1 and 100; any other value returns | |
| integer | 1 | Page number | |
| date (YYYY-MM-DD) | today |
| |
| integer | 50 | Campaigns per page. Must be an integer between 1 and 100; any other value returns | |
| integer | 1 | Page number |
If you send filter[from]/filter[to] a value that is not a valid date, it returns 422 (before this change, a malformed value could break with a s-rv2?filtidor error).
Example: GET {{base_url}}/api/companies/v1/campaigns-v2?filter[from]=2025-10-01&filter[to]=2025-10-31&per_page=20
Response (200 OK):
{
"data": [
{
"id": 88,
"name": "Campaña Q88,
"name": "Campaña Q4 - Phishing bancario",
"launch_launch_date": "2025-110-05 09:00:00",
"send_by_dasend_by_date": "2025-10-05 18:00:00",
"closes_at": "2025-10-12 09:00:00",
"type": "Ransommware",
are4,
"statss_count": 134,
"emastats": 9{ "clicked_link": 41,
"email_sent_reported": 134, 12, "cnedential_had_linkpen": 41: 3,
"download": 2, "emaail_led": 1, "automaticed": 12, "credeclickestingd": 9, 4, "impersonfile_opeted": 3: 0
}
}
],
"links": [
{ "downurlo": dl": 2, "failevious": 1, "active":"url": "https://.../campaigns-v2?pager_page=20", "label": "1", "actoivatic_clicke": drue },
{ "url": 4, "https://.../campaimpersogns-v2?page=2&per_ptedge=20": 0 "label": "2", "active": false },
}
}
],
{ "url": "httlinks": { "f://.../campairsgs-v2?page=2&per_page=20", "label": "Next", "active": fase }
],
"current_p":ge": 1,
"pev": ull: 20, "next": "...""total": },
134,
"meta":"last_page": {7,
"frm": 1,
"to": 20,
"rrenext_page": 1, "pe_page_url": 50, "https://.../campatgns-v2?page=2&per_page=20tal",: 134, "last_page":"prev_page_url": 3null,
"https://.../campaigns-v2?page=1&per_page=20",
"https://.../campaigns-v2?page=7&per_page=20",The block above (everything except
data) is insidemetain the real response; we show it flattened here so it is easier to read.linksis the list of pagination buttons (Previous / page numbers / Next), not an object withfirst/last/prev/next: to get the URL of the next page, usemeta.next_page_url(nullif you are already on the last page).
sSorted nch_date stesnco independent counter that Gdno trode of each page. next_pexclusivege_ur/pre its tiv_page_u rver_pag and the date filtos ve fecho (os. Same vaciy calest as GET /campaigns. All the fras ña):
Field | Counts events of type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Field | Counts events of type |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Code | Cause | Body |
|---|---|---|
| Missing |
|
| API Key nonexistent/revoked |
|
|
|
|
|
|
|
curl -X GET "https://api.whalemate.io/api/companies/v1/campaigns?filter[from]=2025-10-01&filter[to]=2025-10-31" \
-H "X-API-KEY: tu_api_key_aqui" -H "Accept: application/json"curl -X GET "https://api.whalemate.io/api/companies/v1/campaigns-v2?filter[from]=2025-10-01&filter[to]=2025-10-31&per_page=20" \
-H "X-API-KEY: tu_api_key_aqui" -H "Accept: application/json"curl -X GET "https://api.whalemate.io/api/companies/v1/campaigns-v2?filter[from]=2025-10-01&filter[to]=2025-10-31&per_page=20" \
-H "X-API-KEY: tu_api_key_aqui" -H "Accept: application/json"I sent from_date/to_date and nothing is filtered. The correct names are filter[from]/filter[to]. A parameter with any other name is silently ignored and falls back to the default range (last month).
It returns 200 OK but no campaigns. The active date range has no campaigns with launch_date inside that window, or the API Key belongs to another company.
Is it paginated? GGET /campaigngns no, it returns the full array. GET /complete. GET /campaigns-v2-v2 yes, 50 per page by default (meta.per_page); adjustable with ?per_page=100 and navigable with ?page=2,
Does credential_harvesting include file_open or download? No, each field in stats counts only its own event type.
What time zone are the dates in? All in UTC. If you set a cutoff at 16:00 in Buenos Aires (UTC-3), in the API you will see it as 19:00. Convert to your local time zone before showing or comparing it.
Where do I get my API Key? In Configuración → Integraciones → card Claves API → Claves Activas.
Do you have feedback or want to request improvements? Let us know at roadmap.whalemate.com/roadmap