History Author Details#
Every entry in an incident's history has an author display string such as PhishFort System or Client (jane@acme.com). authorDetails is the same information as a structured object, so you can tell client messages from PhishFort updates, and automated lines from human ones, without parsing the string.
Enabled per account
authorDetails is switched on per account. Until it is enabled for yours, history entries don't include the field at all. Contact PhishFort support to enable it, and treat the field as optional in your integration.
Where it appears#
authorDetails is returned on each history entry from the single-incident endpoints:
| Method | Endpoint |
|---|---|
| GET | /v1/incident/{id} |
| GET | /v1/incident/subject/{subject} |
It needs no extra request parameters. When it's enabled for your account, it's present on every history entry those endpoints return.
Structure#
{
"id": string,
"message": string,
"type": "info" | "info/auto" | "info/comment", // unchanged
"author": string, // unchanged display string
"authorDetails": {
"type": "client" | "phishfort",
"clientId": string | null,
"email": string | null,
"automated": boolean
},
"timestamp": Date
}
| Field | Type | Meaning |
|---|---|---|
authorDetails.type |
"client" | "phishfort" |
client for messages and takedown approvals or declines from your organisation. phishfort for everything else, including analyst updates and automated status lines. |
authorDetails.clientId |
string | null |
The id of the client that wrote the entry, when it can be matched to exactly one of the clients your API key covers. Always null for phishfort entries. |
authorDetails.email |
string | null |
The responder's email address, when the entry was recorded with one (for example a comment posted with an author email, or a takedown approval). Always null for phishfort entries. |
authorDetails.automated |
boolean |
true for automated, system-generated entries such as Awaiting client approval or Takedown initiated. Always false for client entries. |
How authorDetails lines up with the existing type and author fields:
type |
author |
authorDetails.type |
authorDetails.automated |
|---|---|---|---|
info/auto |
PhishFort System |
phishfort |
true |
info |
PhishFort |
phishfort |
false |
info/comment |
Client (<sender>) or Client |
client |
false |
info |
Client (<sender>) or Client (takedown approvals and declines) |
client |
false |
Response Example#
{
"data": {
"id": "054zKkjCnR1I3B3U812z",
"history": [
{
"id": "5521874",
"message": "Awaiting client approval",
"type": "info/auto",
"author": "PhishFort System",
"authorDetails": {
"type": "phishfort",
"clientId": null,
"email": null,
"automated": true
},
"timestamp": "2026-09-10T08:12:04.000Z"
},
{
"id": "5521908",
"message": "Takedown approved by jane@acme.com",
"type": "info",
"author": "Client (jane@acme.com)",
"authorDetails": {
"type": "client",
"clientId": null,
"email": "jane@acme.com",
"automated": false
},
"timestamp": "2026-09-10T09:30:47.000Z"
},
{
"id": "5521911",
"message": "Please prioritise this one, it is being shared with our customers.",
"type": "info/comment",
"author": "Client (Acme Corp)",
"authorDetails": {
"type": "client",
"clientId": "a1B2c3D4e5F6g7H8i9J0",
"email": null,
"automated": false
},
"timestamp": "2026-09-10T09:31:02.000Z"
},
{
"id": "5522046",
"message": "We've contacted the hosting provider and are waiting on a response.",
"type": "info",
"author": "PhishFort",
"authorDetails": {
"type": "phishfort",
"clientId": null,
"email": null,
"automated": false
},
"timestamp": "2026-09-10T11:05:19.000Z"
}
]
}
}
Other incident fields are left out above for brevity. See DetailedIncidentStructure for the full response.
Usage Examples#
import requests
incident_id = "054zKkjCnR1I3B3U812z"
response = requests.get(
f"https://capi.phishfort.com/v1/incident/{incident_id}",
headers={"accept": "application/json", "x-api-key": "YOUR_API_KEY"},
)
history = response.json()["data"].get("history", [])
# authorDetails is optional: skip entries without it
detailed = [e for e in history if "authorDetails" in e]
client_entries = [e for e in detailed if e["authorDetails"]["type"] == "client"]
analyst_updates = [
e for e in detailed
if e["authorDetails"]["type"] == "phishfort" and not e["authorDetails"]["automated"]
]
const incidentId = "054zKkjCnR1I3B3U812z";
const response = await fetch(
`https://capi.phishfort.com/v1/incident/${incidentId}`,
{ headers: { accept: "application/json", "x-api-key": "YOUR_API_KEY" } }
);
const { data } = await response.json();
// authorDetails is optional: skip entries without it
const detailed = (data.history ?? []).filter((e) => e.authorDetails);
const clientEntries = detailed.filter((e) => e.authorDetails.type === "client");
const analystUpdates = detailed.filter(
(e) => e.authorDetails.type === "phishfort" && !e.authorDetails.automated
);
Notes#
typeandauthorare unchanged.authorDetailsis added alongside them, so existing integrations keep working.- Don't rely on
clientIdoremailbeing set oncliententries. Each one is filled in only when the entry carries that information. - For the rest of the history entry fields, see IncidentHistory.