Activity Logs

2.4k visitas Markdown

The fourteen endpoints that read and clear sent messages, sign-ins, security incidents, actions and module exchanges.

Overview

These fourteen endpoints read and clear the books of what the system did. They cover e-mails and messages sent, sign-ins and the security incidents they opened, user actions, module exchanges with providers, and database queries.

E-mail and message bodies are stored encrypted and do not come back in the list; a separate endpoint decodes them. The other books read plainly.

Every clear shares one shape: you give a cut-off date and everything on and before it goes. The one exception is the query log, which is file-based and takes no date.

Reference

Listing the E-mail Log

get/api/v1/admin/tools/logs/mail
Tools/GetMailLogs admin paged

Returns the record of e-mails sent. The body is not in the list.

Query parameters 3
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
searchstringSearches the records.
Response fields data[] — 9
idintId of the record.
user_idintId of the client the mail went to. Zero when the mail was not tied to an account.
reasonstringThe notification key that produced the mail.
subjectstringThe mail subject.
addressesstringThe recipient address or addresses.
datastringThe template variables, serialised.
ipstringThe address the send was triggered from.
privateintOne when the body is withheld from the panel.
ctimestringWhen it was sent, as YYYY-MM-DD HH:MM:SS. The body field is not among these; the list stays light because bodies are large.
Meta 4
totalintTotal records matching the filter.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero means you are on the last one.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/tools/logs/mail' \
  -H "Authorization: Bearer $API_KEY" \
  -d limit=50
const url = new URL('https://panel.example.com/api/v1/admin/tools/logs/mail');
url.searchParams.set('limit', '50');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/tools/logs/mail?' . http_build_query(['limit' => 50]);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The body is stored encrypted and is NOT in the list; you get it from the decode endpoint.
$logs = Api::Tools()->GetMailLogs([], ['limit' => 50])['data'];

$content = Api::Tools()->GetLogPreview(['type' => 'mail', 'id' => $logs[0]['id']]);

Clearing the E-mail Log

delete/api/v1/admin/tools/logs/mail
Tools/ClearMailLogs admin cannot be undone

Deletes e-mail records older than the date you give.

Body 1
beforestringrequiredThe cut-off date. Records on and before it are deleted.
Response fields data — 2
clearedboolWhether the clear ran.
beforestringThe cut-off date that was used.
Errors 2
invalid_date422No valid date was given.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/logs/mail' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"before":"2026-01-01"}'
const res = await fetch('https://panel.example.com/api/v1/admin/tools/logs/mail', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ before: '2026-01-01' }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/mail');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['before' => '2026-01-01']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The response does not say HOW MANY were deleted; count them by listing first.
Api::Tools()->ClearMailLogs(['before' => '2026-01-01']);

Listing the SMS Log

get/api/v1/admin/tools/logs/sms
Tools/GetSmsLogs admin paged

Returns the record of text messages sent. The body is not in the list.

Query parameters 3
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
searchstringSearches the records.
Response fields data[] — 11
idintId of the record.
user_idintId of the client the message went to. Zero when it was not tied to an account.
reasonstringThe notification key that produced the message.
titlestringThe message title.
numbersstringThe recipient number or numbers.
datastringThe template variables, serialised.
ipstringThe address the send was triggered from.
privateintOne when the body is withheld from the panel.
ownerstringThe sending side: admin or client.
owner_idintThe account that triggered the send.
ctimestringWhen it was sent, as YYYY-MM-DD HH:MM:SS. The body field is missing here for the same reason as the e-mail log.
Meta 4
totalintTotal records matching the filter.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero means you are on the last one.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/tools/logs/sms' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/tools/logs/sms', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/sms');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Tools()->GetSmsLogs();

Clearing the SMS Log

delete/api/v1/admin/tools/logs/sms
Tools/ClearSmsLogs admin cannot be undone

Deletes text message records older than the date you give.

Body 1
beforestringrequiredThe cut-off date. Records on and before it are deleted.
Response fields data — 2
clearedboolWhether the clear ran.
beforestringThe cut-off date that was used.
Errors 2
invalid_date422No valid date was given.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/logs/sms' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"before":"2026-01-01"}'
const res = await fetch('https://panel.example.com/api/v1/admin/tools/logs/sms', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ before: '2026-01-01' }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/sms');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['before' => '2026-01-01']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
Api::Tools()->ClearSmsLogs(['before' => '2026-01-01']);

Listing the Sign-in Log

get/api/v1/admin/tools/logs/login
Tools/GetLoginLogs admin paged

Returns the record of sign-ins to the panel and the client area.

Query parameters 4
typestringWhich side: client or admin. It defaults to client. member is read as client and staff as admin; any other value is refused.
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
searchstringSearches the records.
Response fields data[] — 18
idintId of the sign-in record.
owner_idintThe account the sign-in belongs to.
user_idintThe same account, from the joined client row.
full_namestringThe account holder's name.
company_namestringThe company name on corporate accounts.
blacklistintOne when the account is blacklisted.
ipstringThe address the sign-in came from.
portstringThe source port.
country_codestringThe ISO country code resolved from the address.
citystringThe city resolved from the address.
latlngstringThe latitude and longitude resolved from the address.
timezonestringThe time zone resolved from the address.
user_agentstringThe browser user agent.
staffboolTrue when a staff member opened this session with Sign In as Client in the admin panel.
staff_idintThe staff member who opened the session. Zero on ordinary sign-ins.
staff_namestringThat staff member's full name. Null on ordinary sign-ins.
tokenstringThe session token tied to the sign-in.
ctimestringWhen the sign-in happened, as YYYY-MM-DD HH:MM:SS. The type filter works on the joined account, so a record always belongs to one side or the other.
Meta 4
totalintTotal records matching the filter.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero means you are on the last one.
Errors 2
invalid_type422The type is not client, admin or one of their aliases.
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/tools/logs/login' \
  -H "Authorization: Bearer $API_KEY" \
  -d type=admin
const url = new URL('https://panel.example.com/api/v1/admin/tools/logs/login');
url.searchParams.set('type', 'admin');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/tools/logs/login?' . http_build_query(['type' => 'admin']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Without a type you get CLIENT sign-ins; staff sign-ins answer to 'admin' (or its alias 'staff').
$staff = Api::Tools()->GetLoginLogs([], ['type' => 'admin']);

Listing Sign-in Attempts

get/api/v1/admin/tools/logs/login-attempts
Tools/GetLoginAttempts admin paged

Returns every sign-in attempt recorded on the client and staff doors, successful and failed alike, through every method. A row exists even when no session was opened.

Query parameters 10
typestringWhich side: client or admin. It defaults to client. member is read as client and staff as admin; any other value is refused.
resultstringOnly attempts with this outcome: success, invalid, inactive, blocked, country, veto, disabled, two-factor, two-factor-failed, proxy or throttled. Any other value is refused.
methodstringOnly attempts through this door: password, jetpass, passkey, social or sso. Any other value is refused.
ipstringIP address, partial match.
countrystringTwo-letter ISO country code resolved from the address, such as US. Any other shape is ignored.
owner_idintOnly attempts against this account.
date_rangestringAttempt date: a single day YYYY-MM-DD or an inclusive span YYYY-MM-DD - YYYY-MM-DD.
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
searchstringSearches the address, the city, the user agent and the matched account's name, company and e-mail.
Response fields data[] — 19
idintId of the attempt row.
ctimestringWhen the attempt happened, as YYYY-MM-DD HH:MM:SS.
typestringmember for the client door, admin for the staff door.
owner_idintThe account the attempt was made against. Zero when the address matched no account.
user_idintThe same account, from the joined client row. Null when there is no account.
full_namestringThe account holder's name. Null when there is no account.
company_namestringThe company name on corporate accounts.
emailstringThe account e-mail. Null when there is no account.
email_hashstringSHA-256 of the lowercased address that was tried. The address itself is never stored, so attempts against unknown accounts can still be grouped.
ipstringThe address the attempt came from.
resultstringThe outcome, one of the result filter values.
methodstringThe door, one of the method filter values.
user_agentstringThe browser user agent, trimmed to 255 characters.
country_codestringThe ISO country code resolved from the address. Empty when no lookup was available; a failed attempt never triggers a fresh lookup.
citystringThe city resolved from the address, under the same rule.
is_proxyintOne for a proxy or VPN, zero for a plain address, minus one when unknown.
asnstringThe network name resolved from the address, when known.
risk_scoreintThe score assigned by the risk engine. Zero until the engine evaluates attempts.
risk_flagsstring[]Names of the risk signals that fired. Empty when none.
Meta 4
totalintTotal attempts matching the filter.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero means you are on the last one.
Errors 4
invalid_type422The type is not client, admin or one of their aliases.
invalid_result422The result is not one of the listed outcomes.
invalid_method422The method is not one of the listed doors.
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/tools/logs/login-attempts' \
  -H "Authorization: Bearer $API_KEY" \
  -d type=client \
  -d result=invalid
const url = new URL('https://panel.example.com/api/v1/admin/tools/logs/login-attempts');
url.searchParams.set('type', 'client');
url.searchParams.set('result', 'invalid');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/tools/logs/login-attempts?' . http_build_query(['type' => 'client', 'result' => 'invalid']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Failed password attempts on the client door; the e-mail that was tried never comes back, only its hash.
$failed = Api::Tools()->GetLoginAttempts([], ['type' => 'client', 'result' => 'invalid']);

Listing Security Events

get/api/v1/admin/tools/logs/security-events
Tools/GetSecurityEvents admin paged

Returns the incidents the account protection engine opened. An incident is one address reaching too many unrelated client accounts, or a risky sign-in that went through unchallenged. Attack mode switching on or off and a canary account being used open one too. Unlike the bell notice, a row stays until an operator resolves or ignores it.

Query parameters 8
typestringOnly events of this kind: account-takeover-suspected, account-protection-no-channel, attack-mode-on, attack-mode-off or canary-hit. Any other value is refused.
severitystringOnly events of this severity: info, warning or critical. Any other value is refused.
statusstringOnly events in this state: open, resolved or ignored. Any other value is refused.
ipstringIP address, partial match.
date_rangestringEvent date: a single day YYYY-MM-DD or an inclusive span YYYY-MM-DD - YYYY-MM-DD.
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
searchstringSearches the IP address, the network (AS) number, the city and the account ID list.
Response fields data[] — 16
idintId of the event.
ctimestringWhen the event was opened, as YYYY-MM-DD HH:MM:SS.
typestringThe event kind, one of the type filter values.
severitystringinfo, warning or critical.
ipstringThe address the incident came from. Empty for attack mode events.
asnstringThe network (AS) number resolved from the address, such as AS64496. Empty when unknown.
country_codestringLower-case ISO country code resolved from the address. Empty when unknown.
citystringThe city resolved from the address. Empty when unknown.
user_idsint[]Ids of the client accounts involved. Empty for attack mode events.
accountsobject[]The same accounts with id, full_name and email, one object per id. Name and e-mail are empty when the account no longer exists.
scoreintRisk score of the sign-in that opened the event. Zero when no sign-in was scored.
dataobjectDetails of the event kind. A suspected takeover carries accounts (how many unrelated accounts the address reached), minutes (the window), last_user_id and flags (the risk signals that fired). A no-channel event carries flags and subject_user_name. Attack mode events carry window_minutes, attempts, threshold and multi_accounts.
statusstringopen, resolved or ignored.
actionsobject[]Actions taken on the event, oldest first. Each has action (lock-accounts, block-ip, watch-asn or auto-sessions, the last being the engine's automatic protection), admin_id (the staff account that ran it, 0 for the engine), time and result (what the action returned, see the action endpoint).
resolved_byintStaff account that resolved or ignored the event. Zero while open.
resolved_atstring|nullWhen the event was resolved or ignored. Null while open.
Meta 4
totalintTotal events matching the filter.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero means you are on the last one.
Errors 4
insufficient_scope403The key lacks the required scope.
invalid_type422The type is not one of the listed event kinds; details.allowed lists them.
invalid_severity422The severity is not info, warning or critical.
invalid_status422The status is not open, resolved or ignored.
Request
curl -G 'https://panel.example.com/api/v1/admin/tools/logs/security-events' \
  -H "Authorization: Bearer $API_KEY" \
  -d status=open \
  -d severity=critical
const url = new URL('https://panel.example.com/api/v1/admin/tools/logs/security-events');
url.searchParams.set('status', 'open');
url.searchParams.set('severity', 'critical');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/tools/logs/security-events?' . http_build_query(['status' => 'open', 'severity' => 'critical']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// Open critical incidents first: the suspected takeovers still waiting for an operator.
$open = Api::Tools()->GetSecurityEvents([], ['status' => 'open', 'severity' => 'critical']);

Running an Action on a Security Event

post/api/v1/admin/tools/security-events/{id}/action
Tools/SecurityEventAction admin

Runs one operator action on an event and writes a staff action-log line for it. The actions are the same ones the Security Events screen and the alert e-mail offer. The lock action gives every tied client account a new random password; it cannot be undone.

Path parameters 1
idintId of the security event.
Body 1
actionstringrequiredWhat to do: lock locks every client account tied to the event (random password, so sessions and "remember me" tokens drop; trusted devices forgotten; a reset e-mail sent) and skips staff and missing accounts. block shuts the event's address out of the password and JetPass doors for 24 hours. watch adds the event's network (ASN) to the watched list under Account Protection. resolve, ignore and reopen only change the status. Any other value is refused.
Response fields data — 4
idintId of the event.
actionstringThe action that ran.
resultobjectWhat the action did. lock: locked (account ids that were locked), reset_sent (ids a reset e-mail went out to) and skipped (staff or missing ids). block: ip, until (block expiry), doors (the doors blocked now) and already (true when both doors were blocked before). watch: asn, already and list (the watched networks after the change). The status actions return status, the new state.
eventobjectThe event after the action, with the fields of the listing endpoint above.
Errors 7
insufficient_scope403The key lacks the required scope.
security_event_not_found404No security event with this id.
invalid_action422The action is not one of the listed values; details.allowed lists them.
no_accounts422Lock was requested, but the event is tied to no account.
no_ip422Block was requested, but the event carries no IP address.
no_asn422Watch was requested, but the event carries no network (ASN).
action_failed422The action could not be completed; the message says why, for example the event was deleted meanwhile.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/tools/security-events/18/action' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"action":"block"}'
const res = await fetch('https://panel.example.com/api/v1/admin/tools/security-events/18/action', {
  method:  'POST',
  headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
  body:    JSON.stringify({ action: 'block' }),
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/security-events/18/action');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey, 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS     => json_encode(['action' => 'block']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// A second block on the same event does not fail; it comes back with already => true.
$result = Api::Tools()->SecurityEventAction(['id' => 18], ['action' => 'block']);

Listing the Action Log

get/api/v1/admin/tools/logs/actions
Tools/GetActionLogs admin paged

Returns the record of what users and the system did.

Query parameters 5
typestringWhose actions: client, admin or system. It defaults to client. member is read as client and staff as admin; any other value is refused.
owner_idintOnly the actions of this account: a staff member's id with type=admin, a client's id with type=client. A value that is not a positive whole number is ignored. System rows belong to no account, so with type=system the list comes back empty.
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
searchstringSearches the records. It also matches rows whose sentence, in the language of the request, contains the word.
Response fields data[] — 10
idintId of the record.
owner_idintThe account that performed the action.
target_idintThe record the action was performed on.
reasonstringThe action group: update, deletion, create and the like.
detailstringThe action key. A translation key from the action language file, not a sentence: show description rather than this key.
locale_detailstringThe sentence as it was written, in the installation's default language at that moment. It does not follow the reader's language, and it holds the key itself when the key had no sentence yet.
descriptionstringThe sentence in the language of this request. It falls back to locale_detail when the key has no sentence any more.
datastringThe context of the action, serialised.
ipstringThe address the action came from.
ctimestringWhen it happened, as YYYY-MM-DD HH:MM:SS. Module records share this table but stay out of this listing; they have their own endpoint.
Meta 4
totalintTotal records matching the filter.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero means you are on the last one.
Errors 2
invalid_type422The type is not client, admin, system or one of their aliases.
insufficient_scope403The key lacks the required scope.
Request
curl -G 'https://panel.example.com/api/v1/admin/tools/logs/actions' \
  -H "Authorization: Bearer $API_KEY" \
  -d type=admin
const url = new URL('https://panel.example.com/api/v1/admin/tools/logs/actions');
url.searchParams.set('type', 'admin');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
$url = 'https://panel.example.com/api/v1/admin/tools/logs/actions?' . http_build_query(['type' => 'admin']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
$response = Api::Tools()->GetActionLogs([], ['type' => 'admin']);

Clearing the Action Log

delete/api/v1/admin/tools/logs/actions
Tools/ClearActionLogs admin cannot be undone

Deletes action records older than the date you give. It leaves the module log alone.

Body 1
beforestringrequiredThe cut-off date. Records on and before it are deleted.
Response fields data — 2
clearedboolWhether the clear ran.
beforestringThe cut-off date that was used.
Errors 2
invalid_date422No valid date was given.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/logs/actions' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"before":"2026-01-01"}'
const res = await fetch('https://panel.example.com/api/v1/admin/tools/logs/actions', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ before: '2026-01-01' }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/actions');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['before' => '2026-01-01']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// This clear does NOT sweep the module log; that has its own endpoint.
Api::Tools()->ClearActionLogs(['before' => '2026-01-01']);
Api::Tools()->ClearModuleLogs(['before' => '2026-01-01']);

Listing the Module Log

get/api/v1/admin/tools/logs/module
Tools/GetModuleLogs admin paged

Returns the record of what modules exchanged with providers.

Query parameters 3
pageintDefaults to 1.
limitintDefaults to 25, maximum 100.
searchstringSearches the records.
Response fields data[] — 9
idintId of the record.
owner_idintThe account tied to the call. Zero when the system triggered it.
target_idintThe service the module call belonged to.
reasonstringAlways module-log on this endpoint.
detailstringThe module and the action recorded.
locale_detailstringReadable text, when the writer supplied one.
datastringThe request and answer of the module call, serialised.
ipstringThe address the call came from.
ctimestringWhen it happened, as YYYY-MM-DD HH:MM:SS. These records share a table with the action log, but clearing one leaves the other untouched.
Meta 4
totalintTotal records matching the filter.
pageintThe page you are on.
limitintThe page size.
next_pageintThe next page. Zero means you are on the last one.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl 'https://panel.example.com/api/v1/admin/tools/logs/module' \
  -H "Authorization: Bearer $API_KEY"
const res  = await fetch('https://panel.example.com/api/v1/admin/tools/logs/module', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/module');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The module log only fills while it is ON in the log settings; an empty list is not 'all fine'.
$settings = Api::Tools()->GetLogSettings()['data'];

if ($settings['module_log']) {
    $logs = Api::Tools()->GetModuleLogs();
}

Clearing the Module Log

delete/api/v1/admin/tools/logs/module
Tools/ClearModuleLogs admin cannot be undone

Deletes module records older than the date you give.

Body 1
beforestringrequiredThe cut-off date. Records on and before it are deleted.
Response fields data — 2
clearedboolWhether the clear ran.
beforestringThe cut-off date that was used.
Errors 2
invalid_date422No valid date was given.
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/logs/module' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"before":"2026-01-01"}'
const res = await fetch('https://panel.example.com/api/v1/admin/tools/logs/module', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ before: '2026-01-01' }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/module');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['before' => '2026-01-01']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
Api::Tools()->ClearModuleLogs(['before' => '2026-01-01']);

Decoding the Body

post/api/v1/admin/tools/logs/preview
Tools/GetLogPreview admin decrypts

Decrypts and returns the stored body of one e-mail or text message record.

Body 2
typestringrequiredWhich log: mail or sms.
idintrequiredId of the record.
Response fields data — 3
typestringThe log type.
idintId of the record.
contentstringThe decrypted body. The very text that went to the client.
Errors 3
invalid_request422The type or the id was missing.
not_found404No such record.
insufficient_scope403The key lacks the required scope.
Request
curl -X POST 'https://panel.example.com/api/v1/admin/tools/logs/preview' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"type":"mail","id":1240}'
const res = await fetch('https://panel.example.com/api/v1/admin/tools/logs/preview', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ type: 'mail', id: 1240 }),
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/preview');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['type' => 'mail', 'id' => 1240]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// The decrypted body carries client data: do not write it to your own logs.
$content = Api::Tools()->GetLogPreview([
    'type' => 'mail',
    'id'   => 1240,
])['data']['content'];

Deleting the Query Log

delete/api/v1/admin/tools/logs/query
Tools/ClearQueryLogs admin deletes files

Deletes the database query log files. It takes no date and removes all of them.

Response fields data — 2
clearedboolWhether the clear ran.
deletedintHow many files were deleted.
Errors 1
insufficient_scope403The key lacks the required scope.
Request
curl -X DELETE 'https://panel.example.com/api/v1/admin/tools/logs/query' \
  -H "Authorization: Bearer $API_KEY"
const res = await fetch('https://panel.example.com/api/v1/admin/tools/logs/query', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
$ch = curl_init('https://panel.example.com/api/v1/admin/tools/logs/query');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
// This endpoint takes NO date: every file goes. Writing them is switched off in the settings.
Api::Tools()->ClearQueryLogs();
Api::Tools()->SetLogSettings(['query_logging' => 0]);

Pitfalls

The body is not in the list

The content of e-mail and message records is stored encrypted and never comes back from the listing endpoints. Seeing what was sent means calling the decode endpoint separately, one request per record. The decrypted text carries client data, so do not store it on your side.

An empty book does not mean nothing happened

The module and query logs only fill while they are on in the log settings. With them off the lists come back empty, which does not mean nothing happened. Confirm in the settings that the log you need is on before investigating anything.

The default side is the client

On the sign-in and action logs, leaving the type out gives you the client side. Looking for admin sign-ins or the system's own actions means sending the type explicitly, or you conclude the record you want never existed.

The action clear leaves the module log

Clearing the action log leaves the module log where it is; they are separate endpoints. Making one call to free space, you may not notice the bigger book is still sitting there.

The clear does not say how many it deleted

The date-based clears return only that they ran and which date they used; they give no count. To measure the effect, list the same range and count it first.

Lock is final, block and watch are repeatable

The lock action gives every tied client account a new random password. There is no undo; the owner must use the reset e-mail. block and watch do not fail on a second call: they return already: true and change nothing. Read that flag instead of taking a 200 as "the block was placed now".

¿Le ha resultado útil?

¡Gracias por sus comentarios!

¿Todavía necesita ayuda?

Nuestro equipo de soporte está disponible las 24 horas para ayudarle con lo que no encuentre aquí.