Audit Logs
The audit logs endpoint allows administrators to retrieve security and activity events for compliance and monitoring purposes.
List Audit Logs
Returns a paginated list of audit log events. This endpoint uses cursor-based pagination for efficient retrieval of large datasets.
Authentication
Requires an API key with Admin role permissions. See Authentication for more details.
Restricted API Keys
You can create API keys that are restricted to only access this endpoint by naming them with the SIEM-LOG-ONLY prefix. This is useful for SIEM integrations or third-party services that only need audit log access.
For example, an API key named SIEM-LOG-ONLY-splunk or SIEM-LOG-ONLY-datadog will:
- Be allowed to access
GET /api/public/v0/audit-logs - Be blocked from accessing all other API endpoints (returns
403 Forbidden)
This provides a security best practice of least-privilege access for audit log integrations.
Subscription Requirements
This endpoint is only available on plans with the Advanced Auth feature (Business and Enterprise plans). Requests from tenants without this feature will receive a 402 Payment Required response.
Query Parameters
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
after | integer | No | Cursor for pagination. Returns events with ID greater than this value. | 0 |
count | integer | No | Number of events to return per page. Must be between 1 and 1000. Omit to use default. | 100 |
Response Format
Status: 200 OK
{
after: number // Cursor value for next page (last event ID in this response)
count: number // Number of events returned in this response
events: Array<{
id: number // Unique event identifier
user: { // User who performed the action (null for system events)
id: number // User ID
name: string // User's display name
email: string // User's email address
} | null
action: string // Action type (see Action Types below)
ip: string // IP address of the request
userAgent: string // User agent string
createdAt: string // ISO 8601 timestamp
meta?: object // Additional context about the action (see Action Types below)
}>
}
Action Types
The meta field provides additional context about the action. It is omitted from the response when empty.
| Action | Description | Meta Fields |
|---|---|---|
2fa_disable | Two-factor authentication disabled | |
2fa_enable | Two-factor authentication enabled | |
archive_project | Project was archived | project_id, project_code, project_title |
auth.ip_or_user_agent_changed | IP address or user agent changed during session | |
cancel_invite | User invitation was cancelled | invited_email, invited_role |
delete_project | Project was deleted | project_id, project_code, project_title |
email_change | User changed their email address | old (previous email), new (new email) |
integration.created | Issue tracker integration was created | integration_id, integration_title, integration_type, plus type-specific fields: new_url and view_url (custom), account (GitHub), email and url (Jira), organization_key (Linear) |
integration.deleted | Issue tracker integration was deleted | integration_id, integration_title, integration_type, linked_project_count |
integration.project_linked | Project was linked to an issue tracker integration | integration_id, integration_title, integration_type, project_id, project_code, project_title, plus relation-config fields per integration type: github_repo (GitHub), jira_project_id and jira_project_name (Jira), linear_team_id and linear_team_name (Linear). When the project was previously linked, the prior config is included with a previous_ prefix (e.g., previous_integration_id, previous_integration_title, previous_github_repo) |
integration.project_unlinked | Project was unlinked from an issue tracker integration | Same as integration.project_linked but without the previous_ fields |
integration.updated | Issue tracker integration configuration was updated | integration_id, integration_title, integration_type, plus only the fields that changed (from the same set as integration.created) |
invite_user | User was invited to the organization | invited_email, invited_role |
login | User logged in | |
logout | User logged out | |
oauth.authorization_created | OAuth authorization granted (e.g., for QAS CLI) | grant_type, client_id, authorization_id |
oauth.authorization_revoked | OAuth authorization revoked | client_id, authorization_id |
password_change | User changed their password | |
password_reset | Password was reset | |
register | New user registered | |
request_password_reset | Password reset was requested | |
scim.user_create | User provisioned via SCIM | userName, apiKeyId, externalId (when set on the user) |
scim.user_deactivate | User suspended via SCIM | Same as scim.user_create |
scim.user_reactivate | User unsuspended via SCIM | Same as scim.user_create |
scim.user_update | User attributes updated via SCIM | Same as scim.user_create |
slack_disconnect | Slack workspace was disconnected | |
slack_install | Slack workspace was connected | team_id, team_name, domain |
slack_link_user | Slack user was linked to a QA Sphere user | team_id, slack_user_id, source (oauth_install when auto-linked during install) |
slack_subscribe | Slack channel subscribed to project events | team_id, channel_id, channel_name, project_id, project_code, event_types |
slack_unlink_user | Slack user was unlinked from a QA Sphere user | |
slack_unsubscribe | Slack channel unsubscribed from project events | team_id, channel_id, channel_name, project_id, project_code, event_types, remaining |
unarchive_project | Project was unarchived | project_id, project_code, project_title |
webhook.created | Webhook was created | webhook_id, webhook_name, endpoint, enabled, event_types, allow_all_projects, allowed_project_count (when allow_all_projects is false). secret, headers, and payload appear as **** when set (values are redacted) |
webhook.deleted | Webhook was deleted | Same as webhook.created |
webhook.updated | Webhook configuration was updated | webhook_id, webhook_name, plus only the fields that changed (from the same set as webhook.created; secret/headers/payload changes appear as ****) |
Example Request
curl \
-H "Authorization: ApiKey your.api.key.here" \
"https://your-company.your-region-code.qasphere.com/api/public/v0/audit-logs?count=50"
Example Response
{
"after": 156,
"count": 3,
"events": [
{
"id": 154,
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
},
"action": "login",
"ip": "192.168.1.100",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"createdAt": "2025-01-28T10:30:00Z"
},
{
"id": 155,
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
},
"action": "archive_project",
"ip": "192.168.1.100",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"createdAt": "2025-01-28T11:00:00Z",
"meta": {
"project_id": "1CKgJ5HMU_2apSDSQWRw6Ys",
"project_code": "PROJ",
"project_title": "My Project"
}
},
{
"id": 156,
"user": {
"id": 2,
"name": "Jane Smith",
"email": "jane@example.com"
},
"action": "email_change",
"ip": "192.168.1.101",
"userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"createdAt": "2025-01-28T12:00:00Z",
"meta": {
"old": "jane.old@example.com",
"new": "jane@example.com"
}
}
]
}
Pagination
This endpoint uses cursor-based pagination for efficient retrieval:
- Make an initial request without the
afterparameter to get the first page - Use the
aftervalue from the response as theafterparameter for the next request - Continue until you receive fewer events than requested (end of data)
Pagination Example
# First page
curl -H "Authorization: ApiKey your.api.key.here" \
"https://your-company.your-region-code.qasphere.com/api/public/v0/audit-logs?count=100"
# Response: { "after": 100, "count": 100, "events": [...] }
# Second page (using after value from previous response)
curl -H "Authorization: ApiKey your.api.key.here" \
"https://your-company.your-region-code.qasphere.com/api/public/v0/audit-logs?after=100&count=100"
# Response: { "after": 156, "count": 56, "events": [...] }
# count < 100 indicates this is the last page
When after is 0 or omitted, the response starts from the first event of the current month. If no events exist for the current month, an empty result is returned. The after value in the response equals the input after value when there are no more events to return.
Error Responses
| Status Code | Description |
|---|---|
| 400 | Invalid parameters (e.g., count > 1000) |
| 401 | Invalid or missing API key |
| 402 | Subscription plan lacks Advanced Auth feature |
| 403 | Insufficient permissions (non-admin access) |
| 500 | Internal server error |
This endpoint enables you to:
- Monitor user authentication activity
- Track security-related changes (2FA, password changes)
- Audit project lifecycle events
- Integrate with SIEM systems for compliance
- Build custom security dashboards