Skip to main content

Audit logs API

info

Audit Logs in Document Management SDK is an implementation case that collects, stores, and reads file, user, and administrative activity through the Document Governance SDK integration. To see how Storage and Editor activity is linked into a single audit trail, see Governance Integration.

Two read-only endpoints over the tenant's audit trail: a paged listing and a CSV export of a whole date range.

Base URL and authorization

/api/external/v1/admins/audit-logs

These endpoints require an API Key issued to an account holding the ADMIN role. Authorization is by role alone - the key's scope is not examined. Both endpoints are read-only, so a key holding only api:read behaves identically to one holding api:write.

The tenant is fixed by the server from the calling key. There is no request parameter that selects another tenant. The tenant is resolved from the request host, so call the domain the key was issued for; calling a different domain fails with API_KEY_004.

The endpoints are absent when governance is off

A deployment running with governance.audit.enabled=false does not register these endpoints at all, and every call returns 404. A 404 here means the feature is off, not that the path is wrong.

Where the data comes from

Audit events are not stored in the Drive database. They live on the governance server, and Drive proxies the governance query API. Governance authentication is handled server-side, so a caller needs nothing beyond the Drive API Key.

One consequence is worth knowing before you build against these endpoints: a filter value outside the governance vocabulary comes back as 500, not 400. Governance rejects the value with a 400, and Drive wraps that into RESPONSE_001. Keep every filter inside the values listed below.

Filter values

eventCategory

ValueCovers
LOGINSign-in, sign-out, account lock state
FILE_FOLDERFile and folder actions
SHARESharing
USER_MANAGEMENTUser and administrator account management
SETTINGConfiguration changes
Send at most one eventCategory

Two or more values return 200 with zero results rather than an error, which is indistinguishable from "nothing happened". Measured on 2026-09-14: eventCategory=LOGIN&eventCategory=SHARE returned totalCount of 0. To cover several categories in one call, expand them into their eventTypes instead.

channel

ValueCovers
WEBThe web interface
APIThe external API
MCPMCP
SYSTEMThe system, with no user request behind it

outcomeStatus

ValueCovers
SUCCESSThe action succeeded
FAILThe action failed

eventType

Forty-one values, each belonging to one category.

CategoryTypes
LOGINLOGIN, LOGOUT, ACCOUNT_LOCKED_STATUS_CHANGE
FILE_FOLDERFILE_CREATE, FILE_UPLOAD, FILE_DOWNLOAD, FILE_PREVIEW, FILE_OPEN, FILE_EDIT, FILE_DELETE, FILE_PERMANENT_DELETE, FILE_RESTORE, FILE_RENAME, FILE_MOVE, FILE_COPY, FOLDER_CREATE, FOLDER_DOWNLOAD, FOLDER_DELETE, FOLDER_PERMANENT_DELETE, FOLDER_RESTORE, FOLDER_RENAME
SHARESHARE_CREATE, SHARE_PERMISSION_CHANGE, SHARE_REMOVE
USER_MANAGEMENTUSER_CREATE, USER_DELETE, USER_PERMANENT_DELETE, USER_RESTORE, USER_INFO_UPDATE, USER_TWOFACTOR_RESET, USER_PASSWORD_CHANGE, USER_STATUS_CHANGE, ADMIN_CREATE, ADMIN_DELETE, ADMIN_PERMANENT_DELETE, ADMIN_RESTORE, ADMIN_INFO_UPDATE, ADMIN_PASSWORD_CHANGE, ADMIN_STATUS_CHANGE
SETTINGSETTING_UPDATE, SETTING_ALLOWED_IP_CHANGE

A successful sign-in and a failed one are both recorded as LOGIN; the difference is outcomeStatus. Only sign-out gets its own type, LOGOUT. Filtering on LOGIN therefore returns successes and failures together.

Dates

Request dates are yyyy-MM-dd. A range runs from 00:00 on from up to 00:00 on the day after to, so the end date is included. Values in the response are yyyy-MM-dd HH:mm:ss.SSS in Asia/Seoul.

List audit events

GET /api/external/v1/admins/audit-logs

Reads the calling key's tenant by page number. Ordering is fixed to occurredAt descending; there is no sort parameter.

ParameterTypeRequiredDescription
piintegerYesPage number, from 1
psintegerYesPage size, 1 to 200. A larger value is clamped to the governance ceiling of 200
actorEmailstringNoActor email, matched exactly. Partial search is not supported
fromstringNoStart date, inclusive
tostringNoEnd date, inclusive
eventCategorystringNoOne category value
eventTypesstring[]NoEvent types, repeated once per value
channelstringNoWEB, API, MCP, or SYSTEM
outcomeStatusstringNoSUCCESS or FAIL

eventTypes is repeated rather than comma-joined: eventTypes=FILE_RENAME&eventTypes=FILE_MOVE. There is no limit on how many you send; the practical ceiling is the request URL length, 8 KB on a default web server.

List audit events
curl -X GET "https://drive.example.com/api/external/v1/admins/audit-logs?pi=1&ps=20&from=2026-09-01&to=2026-09-14&eventCategory=FILE_FOLDER&eventTypes=FILE_RENAME&eventTypes=FILE_MOVE" \
-H "Authorization: Bearer replace-with-your-api-key" \
-H "Content-Type: application/json"
Success
{
"result": true,
"code": 200,
"data": [
{
"eventId": "019b2f58-7f3a-7c21-8e90-4c1f2f2e7840",
"occurredAt": "2026-09-14 14:11:03.510",
"eventType": "FILE_RENAME",
"eventCategory": "FILE_FOLDER",
"actorType": "HUMAN",
"actorName": "First user",
"actorEmail": "user1@example.com",
"objectType": "FILE",
"objectName": "Proposal.pptx",
"objectEmail": null,
"objectPath": "MY/Sales/2026",
"outcomeStatus": "SUCCESS",
"outcomeCode": null,
"channel": "WEB",
"clientIp": "198.51.100.20",
"tenantSeq": "3",
"tenantName": "Example tenant",
"change": {
"before": "Proposal_draft.pptx",
"after": "Proposal.pptx"
},
"targets": null
}
],
"totalCount": 1234,
"pageIndex": 1,
"pageSize": 20
}

The listing response carries no message. Paging values arrive as totalCount, pageIndex, and pageSize.

FieldTypeDescription
eventIdstringEvent identifier, issued by governance
occurredAtstringWhen it happened
eventTypestringEvent type, the value eventTypes matches on
eventCategorystringThe category the type belongs to
actorTypestringActor kind; HUMAN
actorNamestringActor display name
actorEmailstringActor email, the same value as the Drive account id
objectTypestringTarget kind: FILE, FOLDER, USER, or SETTING
objectNamestringTarget name - file or folder name, account name, and so on
objectEmailstringTarget account email; present only when the target is an account, otherwise null
objectPathstringTarget path relative to its parent folder. The leading segment is a location code: MY for My Drive, SHARE for the shared area
outcomeStatusstringSUCCESS or FAIL
outcomeCodestringFailure reason code, on failures only, otherwise null
channelstringWhere the request came from
clientIpstringClient IP of the request
tenantSeqstringTenant identifier, the governance scope id
tenantNamestringTenant name, the governance scope name
changeobjectBefore and after as {before, after, summary}, on change events only
targetsobject[]Target list, such as the recipients of a share, on the events that have one
Failure
{
"result": false,
"code": 400,
"errorCode": "REQUEST_001",
"message": "[{msg=must not be null, field=pi}]"
}

Export audit events as CSV

GET /api/external/v1/admins/audit-logs/export

Downloads the whole matching date range as CSV. It takes the same filters as the listing but no paging parameters, and the body is raw CSV with no JSON envelope.

ParameterTypeRequiredDescription
fromstringNoStart date, inclusive. Empty means 92 days before to
tostringNoEnd date, inclusive. Empty means now
actorEmailstringNoActor email, matched exactly
eventCategorystringNoOne category value
eventTypesstring[]NoEvent types, repeated once per value
channelstringNoWEB, API, MCP, or SYSTEM
outcomeStatusstringNoSUCCESS or FAIL

The range is capped at 92 days. Leaving both dates empty applies the last 92 days, and a wider span is rejected with 400. A calendar quarter is 89 to 92 days, so 92 covers any three-month window. For anything longer, split the range across several calls.

pi and ps are not used here and are ignored if sent. The response is the whole range, not a page of it.

Export audit events
curl -X GET "https://drive.example.com/api/external/v1/admins/audit-logs/export?from=2026-06-01&to=2026-09-01&eventCategory=SHARE" \
-H "Authorization: Bearer replace-with-your-api-key" \
-o audit-events.csv
Response headerValue
Content-Typetext/csv
Content-Dispositionattachment; filename*=UTF-8''audit-events_20260601-20260901.csv
Content-LengthAbsent - the body is streamed in chunks, so the total size is not known up front

The file name follows audit-events_{from}-{to}.csv.

Export body
schemaVersion,eventId,eventType,sourceEventType,occurredAt,origin.system,…,observedIp,ingestKeyId
1.0,019b2f58-7f3a-7c21-8e90-4c1f2f2e7840,FILE_RENAME,FILE_RENAME,2026-07-16T05:11:03.510Z,TFD,…,198.51.100.20,key-acme-01

The file is the governance format unchanged: UTF-8 with a BOM, CRLF line endings, RFC 4180 quoting, 44 columns whose order is part of the contract, and a leading apostrophe on values that would otherwise be read as a formula. It carries more columns than the listing response.

Failure
{
"result": false,
"code": 400,
"message": "감사 로그 내보내기 기간은 최대 92일입니다."
}

The export failures are the exception to the common envelope: they carry no errorCode.

A failure after the first chunk cannot be signalled

The response is chunked. Once the first chunk is sent the status is already 200, so a later failure just ends the response early. A conforming HTTP client treats a missing final chunk as an error rather than accepting the truncated file, but the client is still responsible for confirming that what it received is complete.

Stream long ranges to disk. A row is roughly 1,450 bytes, so 100,000 rows is about 138 MB. Anything that materializes the whole response in memory - a browser Blob, a string conversion - can fail on a long range. Write straight to a file instead, with curl -o or a stream copy.

Concurrency is limited to ten exports at a time per server instance, counted across all tenants. The eleventh returns 429, and the listing endpoint is unaffected. A 429 is safe to retry.

Failure
{
"result": false,
"code": 429,
"message": "다른 내보내기가 진행 중입니다. 잠시 뒤 다시 시도해 주세요."
}

Errors

CodeStatusMeaning
API_KEY_004401Authentication failed - missing header, unknown value, deactivated or expired key, deactivated account, or a different tenant's domain
AUTH_009403The calling key does not hold the ADMIN role
REQUEST_001400Validation failed. message carries the failing fields, such as a missing pi or ps, or one below 1
RESPONSE_001500The governance query failed, including a filter value outside the governance vocabulary

See Errors for the full list of codes the API returns.