Skip to main content

Admin API

Administrative operations scoped to one tenant: creating and maintaining accounts, controlling activation, resetting MFA, managing the license, and configuring how the tenant behaves. For operations across tenants, see Super Admin. The tenant's audit trail has its own page, Audit logs.

Base URL and authorization

/api/external/v1/admins

These endpoints require an API Key issued to an account holding the ADMIN role. A super administrator's key also passes. Two endpoints are exceptions, noted where they appear.

Scope is not checked here

Authorization for /admins/** is by role alone. The API Key's scope is not examined, so a key holding only api:read can create accounts, change quotas, deactivate users, import CSV, and register a license. Treat any admin key as a full-privilege credential regardless of the scope it was issued with.

The single-account endpoint cannot create administrators

POST /admins authenticated by an external API Key may only create accounts with rt of USER. Asking for ADMIN is rejected with USER_013. Note that bulk account import does not apply the same restriction - see the warning there.

Every operation is limited to the caller's own tenant. An endpoint that takes a userSeq returns USER_005 for a userSeq in another tenant, the same response as for one that does not exist, so account existence is not disclosed.

Pagination

Admin listings use cursor pagination: send ps for the page size and ci as the last userSeq of the previous page. nextCursor and hasNext are omitted from the response when they have no value.

Create an account

POST /api/external/v1/admins

Send as multipart/form-data.

ParameterTypeRequiredDescription
uistringYesAccount id, an email address, up to 25 characters
encPwdstringYesPassword, 8 to 64 characters, with at least one uppercase letter, lowercase letter, digit, and symbol
unstringYesDisplay name, up to 20 characters
tqlongYesStorage allowance in bytes
rtstringYesRole; an external key may only send USER
piffileNoProfile image
ctstringNoCountry dialing code without the plus sign, up to 4 characters
pnstringNoPhone number without separators, up to 20 characters

ct and pn must be sent together or both left out; sending one alone returns USER_027.

Create account
curl -X POST "https://drive.example.com/api/external/v1/admins" \
-H "Authorization: Bearer replace-with-your-api-key" \
-F "ui=user1@example.com" \
-F "encPwd=User1234!" \
-F "un=First user" \
-F "tq=1000000000" \
-F "rt=USER"

Returns the new userSeq. A malformed email returns USER_002, a duplicate returns USER_004, and a request that exceeds the licensed seats or available storage returns USER_013 or QUOTA_004.

Read an account

GET /api/external/v1/admins/{userSeq}

Returns the account with its quota, role, status, phone, MFA state, and registration and update history. Dates are formatted strings rather than ISO instants.

isActive is deprecated

It is kept for backward compatibility. Read status instead.

Update an account

PATCH /api/external/v1/admins/{userSeq}

Send as multipart/form-data.

ParameterTypeRequiredDescription
unstringYesDisplay name, up to 20 characters
tqlongYesStorage allowance in bytes
ctstringNoCountry dialing code; send with pn or omit both
pnstringNoPhone number; send with ct or omit both
piffileNoProfile image
dpibooleanNoDelete the existing profile image; defaults to false
skstringNoStorage key

A quota below what the account already uses is rejected with USER_014.

List administrators

GET /api/external/v1/admins

Lists administrator accounts in the caller's tenant, excluding ordinary users.

ParameterTypeRequiredDescription
psintegerYesPage size, minimum 1
cilongNoCursor - the last userSeq of the previous page
senumNoFilter by state - active or inactive, case-insensitive

Any other value for s returns USER_019.

Set an account password

PATCH /api/external/v1/admins/{userSeq}/password
ParameterTypeRequiredDescription
newPwdstringYesNew password, 8 to 64 characters, with at least one uppercase letter, lowercase letter, digit, and symbol

The current password is not required, so this sets a password rather than changing one.

Activate and deactivate

PATCH /api/external/v1/admins/{userSeq}/activate
PATCH /api/external/v1/admins/{userSeq}/deactivate

A failed activation returns USER_017 and a failed deactivation returns USER_018. Neither your own account nor the tenant's default administrator can be deactivated; attempting it returns USER_011.

Mark an account for deletion

PATCH /api/external/v1/admins/{userSeq}/withdraw

Moves the account to a pending-delete state rather than removing it. Your own account and the default administrator cannot be targeted, which returns USER_012. A failure to queue the deletion returns USER_016. See accounts pending deletion for what happens next.

Reset MFA

PATCH /api/external/v1/admins/users/{userSeq}/mfa/reset

Clears the target account's multi-factor setup so the user can enrol again. The action is written to the audit log as USER_TWOFACTOR_RESET. A failure returns USER_022.

Import accounts from CSV

GET /api/external/v1/admins/import/csv/sample
POST /api/external/v1/admins/import/csv

Download the sample first; it defines the column layout the import expects.

ParameterTypeRequiredDescription
filefileYesCSV file in the sample's format
sebooleanNoSend a welcome email to each created account

A fully successful import returns insertCount.

A partial failure returns CSV, not JSON

If any row fails - a duplicate account id, a seat or quota overrun, or a parse error - the response is HTTP 400 with a text/csv body rather than the JSON envelope. The returned file repeats the original columns and adds the reason each row failed. Check Content-Type before parsing the response as JSON.

Read a user's profile image

GET /api/external/v1/users/{userSeq}/profile-image

This one endpoint sits under /users rather than /admins, so the role rule does not apply to it and the ordinary scope check does instead. A key with api:read or api:write and no administrator role can call it.

No tenant boundary on this endpoint

Unlike every other endpoint on this page, this one does not restrict the lookup to the caller's tenant. A userSeq belonging to a different tenant returns that user's profile image rather than USER_005. Do not rely on it to confirm tenant membership, and consider it when deciding who may reach it.

An account with no profile image returns USER_008.

List user accounts

GET /api/external/v1/admins/users

Lists accounts with the USER role in the caller's tenant. Administrator and super administrator accounts are always excluded; use List administrators for those.

ParameterTypeRequiredDescription
psintegerYesPage size, minimum 1
cilongNoCursor - the last userSeq of the previous page
senumNoFilter by state - ACTIVE or INACTIVE; any other value returns USER_019
ustringNoPartial match against the account id

Omitting s returns the default visible states, leaving out deleted and pending-delete accounts.

Search accounts for API Key issuance

GET /api/external/v1/admins/users/search
ParameterTypeRequiredDescription
skstringYesSearch keyword matched against account id or display name

Only accounts with the USER role and ACTIVE status are returned. Other roles and states never appear, which is why this endpoint suits choosing the account an API Key will be issued to.

Read storage usage

GET /api/external/v1/admins/users/{userSeq}/storage-usage

Breaks an account's consumption into its parts.

FieldTypeMeaning
totalQuotaByteslongStorage allowance
totalUsedByteslongTotal consumed
liveUsedByteslongConsumed by current files
versionUsedByteslongConsumed by version history
trashUsedByteslongConsumed by items in the trash

Emptying the trash or deleting version history reclaims the last two.

Read an account's security log

GET /api/external/v1/admins/users/{userSeq}/log
ParameterTypeRequiredDescription
psintegerYesNumber of entries to return
cilongNoCursor - the last userLogSeq of the previous page

Entries carry activityType, ipAddress, region, registerDate, and actorType, which says whether the user performed the action themselves or an administrator did it on their behalf.

Check the status of several accounts

POST /api/external/v1/admins/users/bulk-status
ParameterTypeRequiredDescription
userIdsarrayYesAccount ids to look up; must not be empty

Returns userSeq, userId, and status for each match.

Unknown ids are dropped silently

An id that does not exist in the caller's tenant is left out of the result with no per-item error. Compare the returned list against what you sent rather than assuming every id was resolved.

Create and update accounts in bulk

POST /api/external/v1/admins/users/bulk

Creates and updates accounts in one request. Each entry with no us is created; each entry with a us is updated. The HTTP status is always 200 whether or not anything was created.

ParameterTypeRequiredDescription
usersarrayYesAccounts to create or update; must not be empty

Each entry takes:

FieldTypeRequiredDescription
usintegerNoAccount seq; omit to create, supply to update
uistringNoAccount id, up to 25 characters; required when creating
encPwdstringNoPassword, 8 to 64 characters with at least one uppercase letter, lowercase letter, digit, and symbol; required when creating
unstringYesDisplay name, up to 20 characters
tqlongYesStorage allowance in bytes; cannot be reduced below current usage
rtstringNoRole; required when creating
ctstringNoCountry dialing code; send with pn or omit both
pnstringNoPhone number; send with ct or omit both

The response reports insertedCount, updatedCount, and the userId and userSeq of each created account.

This endpoint can create administrators

Unlike POST /admins, this one does not restrict rt. ADMIN and SUPER_ADMIN are accepted and the accounts are created with those roles, so any admin API Key that reaches this endpoint can mint new administrator accounts. Restrict which of your callers can use it, and validate rt yourself before forwarding a request. A value that is not a known role is not rejected cleanly either - it fails with HTTP 500.

A missing required field on create returns USER_026, a password that fails the pattern returns USER_001, a duplicate account id returns USER_004, and reducing a quota below current usage returns USER_014.

Delete an account immediately

DELETE /api/external/v1/admins/users/{userSeq}
Immediate and irreversible

This is a hard delete. It bypasses the pending-delete grace period entirely and cannot be undone. There is no guard preventing you from deleting your own account or the tenant's only administrator. Use withdraw unless you specifically intend an unrecoverable deletion.

Accounts pending deletion

Accounts marked for deletion wait for a scheduled date before being removed, and can be restored until then.

GET /api/external/v1/admins/users/pending-delete
PATCH /api/external/v1/admins/users/pending-delete/{userSeq}/restore
PATCH /api/external/v1/admins/users/pending-delete/permanent-delete

The listing accepts:

ParameterTypeRequiredDescription
psintegerYesPage size, minimum 1
pdSddateNoStart of the range for when the account was marked; send with pdEd
pdEddateNoEnd of the range for when the account was marked; send with pdSd
dsSddateNoStart of the scheduled-deletion range; send with dsEd
dsEddateNoEnd of the scheduled-deletion range; send with dsSd
cilongNoCursor - the last userSeq; send with cv
cvdateNoCursor - the last pendingDeleteDate; send with ci

Each entry reports pendingDeleteDate, deleteScheduleTime, and who marked the account. status is always PENDING_DELETE.

Restoring returns the account to normal use. An account that is not in the pending-delete state returns ADMIN_USER_001.

Permanent deletion takes ul, a non-empty array of userSeq values, and removes them all. An empty list returns REQUEST_001. If any listed account is not actually pending deletion, the whole request fails with ADMIN_USER_002 rather than partially applying - re-read the list and retry with only valid entries.

License

Three endpoints manage the Thinkfree Drive license.

POST /api/external/v1/admins/register/license
GET /api/external/v1/admins/get/license
GET /api/external/v1/admins/get/license/status
These three use a different response format

The license endpoints do not use the common envelope. A successful registration returns HTTP 200 with no body, and the two read endpoints return the license fields at the top level. Failures return {"code": number, "error": "ENUM_NAME"} where error is a constant name, not a message. Do not parse these responses with your common envelope handler.

GET /admins/get/license/status is authorized for USER rather than ADMIN, so an ordinary account's key can read license status.

Register a license

Send the license file as multipart/form-data under licenseFile. A malformed file returns HTTP 400 with the matching code, a processing failure returns HTTP 500 with 6999, and a failure reading the upload returns HTTP 500 with 4999.

Read the license

GET /admins/get/license returns the issued license.

FieldTypeMeaning
publisherstringIssuer; always TF
CATEGORYstringTRIAL or PRODUCTION
LICENSE_TYPEstringSITE or PERSEAT
LICENSE_IDstringLicense identifier
CLIENT_NAMEstringCustomer name
issuedOnstringIssue date
expiresOnstringExpiry date
updatedAtstringWhen the license record was last refreshed
spentsintegerDays elapsed since issue
daysintegerTotal validity in days
statebooleanWhether the license is currently valid
gracePeriodbooleanPresent and true only while in the post-expiry grace period of up to eight days
paidWhiteLabelbooleanWhether the paid white-label option is included
constrainValuestringSeat limit; present only for PERSEAT
currentSeatNumintegerActive accounts; present only for PERSEAT
availableSeatNumintegerRemaining seats; present only for PERSEAT

Read only the fields above. The response can carry additional internal values that are not part of this contract. A tenant with no license registered returns HTTP 404 with 6998.

Read license status

GET /admins/get/license/status returns state, days, spents, expiresOn, and paidWhiteLabel. When the license needs attention it adds code and resultMessage to the same HTTP 200 response - a warning signal inside a successful response, not an HTTP error.

ConditioncoderesultMessage
Expires within ten days6994LICENSE_UNDER_LIMIT
Already expired6995LICENSE_FILE_EXPIRATION
Seat limit exceeded, which takes precedence over both rows above6993LICENSE_EXCEED_LIMIT
Healthyabsentabsent

When the seat limit is exceeded the response also carries currentSeatNum, constrainValue, and availableSeatNum, which can be negative, and state is forced to false.

Sign-in settings

Controls how users authenticate into the tenant.

GET /api/external/v1/admins/login-settings
PATCH /api/external/v1/admins/login-settings
ParameterTypeRequiredDescription
loginTypeenumYeslocal, oidc, or jwt
providersarrayNoIdentity providers; omit or send null for local

A jwt configuration takes exactly one provider. An oidc configuration may hold several but only one may be ACTIVE. Each provider carries ssoProviderSeq when updating, displayName, status, and a config object whose type must equal loginType - a mismatch returns SSO_PROTOCOL_002, and an unsupported protocol returns SSO_PROTOCOL_001.

An oidc config takes issuerUrl, clientId, and clientSecret. A jwt config takes issuer, an optional audience, and keySourceType of public_key or jwks - supply publicKey for the first and jwksUri for the second. emailClaimName names an alternative claim to read the email from, and errorRedirectUrl is where a failed sign-in lands.

The read response reports redirectUri for the callback and superAdminEnforced, which is true when a super administrator is imposing the setting across tenants.

The read endpoint returns secrets in clear text

GET /admins/login-settings includes clientSecret and publicKey as stored, unmasked. Treat the response as sensitive: do not log it, cache it in a browser, or pass it to a client application.

Branding

GET /api/external/v1/admins/branding
PUT /api/external/v1/admins/branding

Branding applies to the API Key's tenant; there is no identifier in the path. Send the update as multipart/form-data.

ParameterTypeRequiredDescription
tabTitlestringYesBrowser tab title, 2 to 30 characters
serviceNamestringYesService name, 2 to 30 characters
showPoweredBybooleanYesWhether to show the provider attribution
useDefaultbooleanYestrue to use the stock images, false to supply all four
faviconfileConditionalICO or PNG, up to 500 KB; required when useDefault is false
logoIconfileConditionalPNG or SVG, up to 1 MB; required when useDefault is false
logoImagefileConditionalPNG or SVG, up to 2 MB; required when useDefault is false
emailLogofileConditionalPNG or SVG, up to 2 MB; required when useDefault is false

When useDefault is true the four image fields are ignored without validation. When it is false all four are required; sending fewer returns REQUEST_001.

GET /api/external/v1/admins/branding/images/{type}

type is favicon, logo-icon, logo-image, or email-logo, and the required source is custom or default.

Custom images need the paid white-label licence

A tenant without it always receives the stock image regardless of source, so source=custom is only meaningful on a white-label tenant. A missing custom image returns BRANDING_001.

Access restriction

Limits where users may sign in from.

PUT /api/external/v1/admins/access-restriction/countries
PUT /api/external/v1/admins/access-restriction/ips
ParameterTypeRequiredDescription
countriesarrayYesAllowed ISO alpha-2 country codes
ipsarrayYesAllowed IPv4 addresses or CIDR ranges

CIDR host bits must be zero, and IPv6 is not supported. An invalid country code returns ACCESS_002 and an invalid address returns ACCESS_004.

Both endpoints replace the whole list

Neither adds to what is already stored. Sending an empty array deletes every entry. Read the current list, modify it, and send the complete result.

Turn the restriction on and off through system-config/access-restriction-status. Enabling it with no countries and no addresses registered returns ACCESS_003.

Share settings

GET /api/external/v1/admins/share-settings
PATCH /api/external/v1/admins/share-settings
ParameterTypeRequiredDescription
sebooleanYesWhether sharing is available at all
esabooleanConditionalAllow sharing outside the organization; required when se is true
suabooleanConditionalAllow the SPECIFIC_USERS share type; required when se is true
olabooleanConditionalAllow the ORG_LINK share type; required when se is true
pabooleanConditionalAllow the PUBLIC_LINK share type; required when se is true

When se is true, at least one of sua, ola, and pa must also be true. Enabling pa requires esa to be true as well.

The read response adds isEnforced. When it is true, a super administrator is applying one setting to every tenant and the values returned are the global ones rather than this tenant's own.

SMTP

One SMTP configuration exists per tenant. Sending smtpConfigSeq updates the existing record; omitting it creates one.

GET /api/external/v1/admins/smtp-config
POST /api/external/v1/admins/smtp-config
POST /api/external/v1/admins/smtp-config/test
ParameterTypeRequiredDescription
clientNamestringYesCustomer name for the configuration
hoststringYesSMTP server address
portintegerYesSMTP port
encryptionTypeenumYesSSL, TLS, or NONE
authTypeenumYesIDPW or OAUTH
usernamestringYesSMTP account
encPwdstringConditionalPassword; used when authType is IDPW
oauthInfostringConditionalOAuth access token; used when authType is OAUTH
fromAddressstringYesSender address
testReceiverAddressstringYesWhere the test message is sent
smtpConfigSeqintegerConditionalThe configuration to update; required by the test endpoint

encPwd and oauthInfo are not enforced by request validation even though one of them is needed in practice, so a configuration can be saved that cannot actually send. Use the test endpoint to confirm; a failed send returns SMTP_CONFIG_002, and reading a configuration that does not exist returns SMTP_CONFIG_001.

The read endpoint returns the SMTP password in clear text

GET /admins/smtp-config returns encPwd decrypted. Treat the response as sensitive and keep it server-side.

OAuth sending is not fully wired

With authType of OAUTH, oauthInfo is used directly as the access token and username as the account. The server does not check that the token was issued for that account or for fromAddress, and it does not refresh an expired token. Verify the pairing yourself and plan for manual token rotation.

System configuration

GET /api/external/v1/admins/system-config/general
PUT /api/external/v1/admins/system-config/general
GET /api/external/v1/admins/system-config/office
PUT /api/external/v1/admins/system-config/office
GET /api/external/v1/admins/system-config/storage
GET /api/external/v1/admins/system-config/intellect
PUT /api/external/v1/admins/system-config/intellect
GET /api/external/v1/admins/system-config/mfa-status
PUT /api/external/v1/admins/system-config/mfa-status
GET /api/external/v1/admins/system-config/file-size-limit
PUT /api/external/v1/admins/system-config/file-size-limit
GET /api/external/v1/admins/system-config/access-restriction-status
PUT /api/external/v1/admins/system-config/access-restriction-status
GET /api/external/v1/admins/system-config/shares/exists

A PUT that creates a setting for the first time returns 201; updating an existing one returns 200.

General

clientDomain is the tenant's client domain, returned as an empty string when unset.

Editing the domain is restricted in multi-tenant deployments

When more than one tenant is active, only a super administrator may change clientDomain; an ordinary administrator receives SYSTEM_CONFIG_008. When a base domain is registered, the value must end with it, otherwise the call fails with BASE_DOMAIN_004.

Office

officeDomain and officeAdapterName, both required on update. officeDomain is validated as a URL.

Storage

Read-only. Returns storageType of CEPH or S3, plus bucketName, region, endPoint, and status.

Storage credentials are returned unmasked

The response includes accessKey and secretKey in clear text. Any administrator key that can call this endpoint can read the tenant's object-storage credentials. Restrict who can reach it and never forward the response to a client.

Feature toggles

intellect, mfa-status, and access-restriction-status each read and write a single enabled boolean. There is no intellectStatus or status field; use enabled.

access-restriction-status also returns allowedCountries and allowedIps. Setting enabled to true requires at least one country or address to be registered already, otherwise it fails with ACCESS_003.

File size limit

maxFileUploadSize is the upload ceiling in bytes. Send null for no limit; any value you do send must be positive.

Share data check

shares/exists reports whether the tenant holds any share records, as a single exists boolean. Use it before turning sharing off to find out whether doing so would affect existing shares.

Errors

See Errors for the full list of codes these endpoints return.