Stitchflow
Google Workspace logo

Google Workspace User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedMar 11, 2026

Summary and recommendation

The Admin SDK Directory API exposes full CRUD for Google Workspace users at the base URL https://admin.googleapis.com/admin/directory/v1. Authentication requires OAuth 2.0; server-to-server integrations must use a service account with domain-wide delegation enabled in the Admin console under Security → API Controls.

The required scope for write operations is https://www.googleapis.com/auth/admin.directory.user - read-only workloads should use the narrower .readonly scope. Rate limits default to 1,500 requests per 100 seconds per project; HTTP 429 errors do not include a Retry-After header, so exponential backoff with jitter is mandatory.

For teams building an identity graph across SaaS, the Directory API's stable immutable user ID field is the correct anchor - not primaryEmail, which can be renamed and takes up to 10 minutes to propagate.

API quick reference

Has user APIYes
Auth methodOAuth 2.0
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredVaries by Workspace edition and supported IdP provisioning flow

Authentication

Auth method: OAuth 2.0

Setup steps

  1. Go to Google Cloud Console (console.cloud.google.com) and create or select a project.
  2. Enable the Admin SDK API under APIs & Services > Library.
  3. Create OAuth 2.0 credentials (Service Account for server-to-server, or OAuth client ID for user-delegated flows) under APIs & Services > Credentials.
  4. For Service Accounts: download the JSON key file and enable domain-wide delegation in the Google Workspace Admin Console under Security > API Controls > Domain-wide Delegation.
  5. Grant the service account the required OAuth scopes in the domain-wide delegation configuration.
  6. Use the credentials to obtain an access token via Google Auth libraries (e.g., google-auth-library) and include it as a Bearer token in the Authorization header.

Required scopes

Scope Description Required for
https://www.googleapis.com/auth/admin.directory.user Full read/write access to user accounts in the domain Create, update, delete, and list users
https://www.googleapis.com/auth/admin.directory.user.readonly Read-only access to user accounts List and get user details without modification
https://www.googleapis.com/auth/admin.directory.user.security Manage user security settings (tokens, ASPs, verification codes) Managing user security credentials
https://www.googleapis.com/auth/admin.directory.group Full read/write access to groups Managing group membership alongside user operations

User object / data model

Field Type Description On create On update Notes
primaryEmail string User primary email address. Use the immutable id as the durable reference key because primaryEmail can be renamed. required allowed Changing primaryEmail is supported through users.update, but rename propagation is not instantaneous across all services.
name.givenName string User's first name required optional Max 60 characters
name.familyName string User's last name required optional Max 60 characters
password string User's password (hashed or plaintext on input) required optional Min 8 characters. Can specify hashFunction (MD5, SHA-1, crypt) alongside hashed value.
id string Immutable unique identifier for the user server-assigned read-only Use as stable identifier; primaryEmail can change.
suspended boolean Whether the user account is suspended optional optional Suspended users cannot sign in but data is retained.
orgUnitPath string Organizational unit path the user belongs to optional optional Defaults to root OU if not specified.
isAdmin boolean Whether the user has super admin privileges optional optional Use makeAdmin method to promote; cannot set directly via users.update.
emails array List of email addresses for the user optional optional Includes aliases and alternate addresses.
phones array List of phone numbers for the user optional optional Each entry has 'value' and 'type' fields.
addresses array List of physical addresses optional optional Structured with streetAddress, city, country, etc.
organizations array User's organization/department/title information optional optional Includes title, department, costCenter fields.
externalIds array External identifiers (e.g., employee ID) optional optional Use type='organization' for employee ID.
recoveryEmail string Recovery email address for the user optional optional Used for account recovery flows.
recoveryPhone string Recovery phone number in E.164 format optional optional Must include country code (e.g., +15551234567).
changePasswordAtNextLogin boolean Forces password change on next login optional optional Useful for initial provisioning flows.
includeInGlobalAddressList boolean Whether user appears in the Global Address List optional optional Defaults to true.
lastLoginTime string (datetime) Timestamp of user's last login read-only read-only ISO 8601 format. May be empty if user never logged in.
creationTime string (datetime) Timestamp when the user account was created server-assigned read-only ISO 8601 format.
customSchemas object Custom attribute schemas defined for the domain optional optional Must define schema first via Admin Console or Schemas API.

Core endpoints

List Users

  • Method: GET
  • URL: https://admin.googleapis.com/admin/directory/v1/users?domain={domain}&maxResults=100
  • Watch out for: Must specify either 'domain' or 'customer' (use 'my_customer' for the authenticated admin's domain). Without one, the request returns a 400 error.

Request example

GET /admin/directory/v1/users?domain=example.com&maxResults=100
Authorization: Bearer {access_token}

Response example

{
  "kind": "admin#directory#users",
  "nextPageToken": "token123",
  "users": [
    {"id": "123", "primaryEmail": "alice@example.com", "name": {"fullName": "Alice Smith"}}
  ]
}

Get User

  • Method: GET
  • URL: https://admin.googleapis.com/admin/directory/v1/users/{userKey}
  • Watch out for: userKey can be the user's primary email, alias email, or immutable user ID. Using the immutable ID is safest for long-lived references.

Request example

GET /admin/directory/v1/users/alice@example.com
Authorization: Bearer {access_token}

Response example

{
  "id": "118...",
  "primaryEmail": "alice@example.com",
  "name": {"givenName": "Alice", "familyName": "Smith"},
  "suspended": false,
  "orgUnitPath": "/Engineering"
}

Create User

  • Method: POST
  • URL: https://admin.googleapis.com/admin/directory/v1/users
  • Watch out for: New users may take up to 24 hours to appear in all Google services. Password must meet domain password policy requirements.

Request example

POST /admin/directory/v1/users
Authorization: Bearer {access_token}
Content-Type: application/json
{
  "primaryEmail": "bob@example.com",
  "name": {"givenName": "Bob", "familyName": "Jones"},
  "password": "SecurePass123!"
}

Response example

{
  "id": "119...",
  "primaryEmail": "bob@example.com",
  "name": {"givenName": "Bob", "familyName": "Jones"},
  "creationTime": "2025-01-15T10:00:00.000Z"
}

Update User

  • Method: PUT
  • URL: https://admin.googleapis.com/admin/directory/v1/users/{userKey}
  • Watch out for: PUT replaces the full resource. Use PATCH for partial updates to avoid accidentally clearing fields not included in the request body.

Request example

PUT /admin/directory/v1/users/bob@example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
  "name": {"givenName": "Robert", "familyName": "Jones"},
  "orgUnitPath": "/Sales"
}

Response example

{
  "id": "119...",
  "primaryEmail": "bob@example.com",
  "name": {"givenName": "Robert", "familyName": "Jones"},
  "orgUnitPath": "/Sales"
}

Patch User (partial update)

  • Method: PATCH
  • URL: https://admin.googleapis.com/admin/directory/v1/users/{userKey}
  • Watch out for: Preferred over PUT for targeted field updates. Only fields included in the request body are modified.

Request example

PATCH /admin/directory/v1/users/bob@example.com
Authorization: Bearer {access_token}
Content-Type: application/json
{
  "suspended": true
}

Response example

{
  "id": "119...",
  "primaryEmail": "bob@example.com",
  "suspended": true
}

Delete User

  • Method: DELETE
  • URL: https://admin.googleapis.com/admin/directory/v1/users/{userKey}
  • Watch out for: Deleted users remain recoverable for up to 20 days. Transfer data before deletion and use the immutable user ID for undelete workflows.

Request example

DELETE /admin/directory/v1/users/bob@example.com
Authorization: Bearer {access_token}

Response example

HTTP 204 No Content

Make User Admin

  • Method: POST
  • URL: https://admin.googleapis.com/admin/directory/v1/users/{userKey}/makeAdmin
  • Watch out for: Cannot set isAdmin directly via users.insert or users.update; must use this dedicated makeAdmin method.

Request example

POST /admin/directory/v1/users/alice@example.com/makeAdmin
Authorization: Bearer {access_token}
Content-Type: application/json
{
  "status": true
}

Response example

HTTP 204 No Content

Undelete User

  • Method: POST
  • URL: https://admin.googleapis.com/admin/directory/v1/users/{userKey}/undelete
  • Watch out for: Use the immutable user ID for deleted users. Google documents restore for up to 20 days after deletion.

Request example

POST /admin/directory/v1/users/119.../undelete
Authorization: Bearer {access_token}
Content-Type: application/json
{
  "orgUnitPath": "/"
}

Response example

HTTP 204 No Content

Rate limits, pagination, and events

  • Rate limits: Admin SDK Directory API enforces per-domain and per-project quotas. Default is 1,500 queries per 100 seconds per project, and 1,500 queries per 100 seconds per user. Burst limits apply.
  • Rate-limit headers: No
  • Retry-After header: No
  • Rate-limit notes: Quota increases can be requested via Google Cloud Console. Errors return HTTP 429 with a 'userRateLimitExceeded' or 'rateLimitExceeded' reason. Implement exponential backoff. Quotas are visible in Cloud Console under APIs & Services > Quotas.
  • Pagination method: token
  • Default page size: 100
  • Max page size: 500
  • Pagination pointer: pageToken
Plan Limit Concurrent
All Google Workspace plans 1,500 requests per 100 seconds per project; 1,500 requests per 100 seconds per user 0
  • Webhooks available: Yes
  • Webhook notes: The Admin SDK Directory API supports push notifications (webhooks) via the watch method. Clients register a HTTPS endpoint to receive notifications when resources change. Channels expire and must be renewed (max TTL is 604800 seconds / 7 days).
  • Alternative event strategy: Google Workspace Admin Reports API (activities.list) provides audit log polling for admin, login, and user events as an alternative to push notifications.
  • Webhook events: users.watch – changes to user resources, groups.watch – changes to group resources, members.watch – changes to group membership, orgunits.watch – changes to organizational units

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Varies by Workspace edition and supported IdP provisioning flow

  • Endpoint: Varies by IdP integration. Google Workspace acts as a SCIM service provider when provisioned from Okta, Azure AD/Entra ID, or OneLogin. The SCIM endpoint URL is provided within the IdP's Google Workspace app configuration (e.g., Okta generates it automatically). Google does not publish a standalone generic SCIM base URL; provisioning is configured through supported IdP connectors.

  • Supported operations: Create users (POST /Users), Read users (GET /Users, GET /Users/{id}), Update users (PUT /Users/{id}, PATCH /Users/{id}), Deactivate/suspend users (PATCH active=false), List users with filtering (GET /Users?filter=), Push groups/manage group membership (POST /Groups, PATCH /Groups/{id})

Limitations:

  • Google Workspace is a SCIM destination (service provider), not a SCIM source; it cannot push SCIM events to external systems.
  • SCIM provisioning requires SSO to be configured first via SAML.
  • Not all Directory API user fields are exposed via SCIM; custom schemas are not supported through SCIM.
  • SCIM group push support varies by IdP connector.
  • Google does not expose a generic public SCIM endpoint; provisioning is only available through certified IdP integrations (Okta, Azure AD/Entra ID, OneLogin, Ping Identity, etc.).

Common scenarios

Three scenarios cover the majority of programmatic use cases. First, provisioning: POST /users with primaryEmail, name fields, password, orgUnitPath, and changePasswordAtNextLogin: true; capture the returned immutable id immediately for all subsequent references.

Note that new accounts can take up to 24 hours to be fully active across all Google services - do not assume immediate downstream availability. Second, offboarding: PATCH /users/{userKey} with suspended: true to block sign-in while preserving data, then invoke the Data Transfer API before issuing DELETE.

deleting without suspending first forfeits the window to transfer data while the account is still accessible. Third, bulk audit: GET /users?

customer=my_customer&maxResults=500&projection=full with pageToken pagination (max page size 500); collect lastLoginTime and suspended fields, then cross-reference with the Reports API activities endpoint for login detail.

Use projection=basic when only a subset of fields is needed - full projection increases payload size significantly at scale.

Provision a new employee and assign to an OU

  1. POST /admin/directory/v1/users with primaryEmail, name.givenName, name.familyName, password, orgUnitPath, and changePasswordAtNextLogin: true.
  2. Capture the returned immutable 'id' field for future stable references.
  3. PATCH /admin/directory/v1/users/{id} to add phone, organizations (title, department), and externalIds (employee ID) if not set at creation.
  4. If the user needs group membership, POST /admin/directory/v1/groups/{groupKey}/members with the user's email.

Watch out for: New accounts may take up to 24 hours to be fully active across all Google services. Do not assume immediate availability for downstream integrations.

Suspend and offboard a departing employee

  1. PATCH /admin/directory/v1/users/{userKey} with suspended: true to immediately block sign-in while preserving data.
  2. Use the Data Transfer API (POST /admin/datatransfer/v1/transfers) to transfer Drive, Calendar, and other data to a manager or archive account.
  3. Remove the user from groups via DELETE /admin/directory/v1/groups/{groupKey}/members/{memberKey}.
  4. After data transfer is confirmed, DELETE /admin/directory/v1/users/{userKey} to initiate the 20-day soft-delete window.

Watch out for: Deleting without suspending first increases offboarding risk. Suspend first, transfer data, then rely on the documented 20-day recovery window only as a safety net.

Bulk list and audit all users in a domain

  1. GET /admin/directory/v1/users?customer=my_customer&maxResults=500&projection=full to retrieve the first page of users with all fields.
  2. Check the response for 'nextPageToken'; if present, repeat the request with pageToken={nextPageToken} until no token is returned.
  3. Collect lastLoginTime and suspended fields to identify inactive or suspended accounts.
  4. Cross-reference with the Reports API (GET /admin/reports/v1/activity/users/all/applications/login) for detailed login activity.

Watch out for: Using projection=full significantly increases response payload size and may slow down pagination for large domains. Use projection=basic and specific fields parameter if only a subset of fields is needed.

Why building this yourself is a trap

Three API behaviors matter in production. First, isAdmin cannot be set through users.insert or users.update - you need the dedicated makeAdmin method. Second, deleted users remain recoverable for up to 20 days, and undelete should use the immutable user ID rather than the email address.

Third, watch-based event delivery is not set-and-forget; channels expire and need explicit renewal, so long-running integrations need renewal logic and a fallback polling plan.

Automate Google Workspace workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedMar 11, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen