Summary and recommendation
Autotask PSA exposes a REST API (v1.0) for full resource lifecycle management: create, read, update, and deactivate. Authentication uses three static HTTP headers-UserName (API key), Secret, and ApiIntegrationCode-with no OAuth 2.0 support; SSO credentials are entirely separate from API credentials.
The first call in any integration must be GET /zoneInformation to resolve the correct zone-specific base URL, as the subdomain varies per tenant. Stitchflow connects to Autotask via an MCP server with ~100 deep IT/identity integrations, handling zone resolution, pagination, and rate-limit coordination across integrations automatically.
API quick reference
| Has user API | Yes |
| Auth method | API Key + Secret + Integration Code (HTTP headers) |
| Base URL | Official docs |
| SCIM available | No |
| SCIM plan required | N/A — No native SCIM endpoint in Autotask PSA. SCIM provisioning is available only via third-party IdP integrations (e.g., Okta SCIM connector to Autotask). |
Authentication
Auth method: API Key + Secret + Integration Code (HTTP headers)
Setup steps
- Log in to Autotask PSA as an administrator.
- Navigate to Admin > Resources (Users) and click the dropdown next to '+ New', then select 'New API User'.
- In the General pane, enter First Name, Last Name, and Email Address; set Security Level to 'API User (system)'.
- In the Security pane, copy the generated Username (Key) and Password (Secret) - the secret is shown only once.
- Assign or self-generate an API Integration Code (tracking identifier) from the Security tab of the API user's Resource Management page.
- Pass all three values as HTTP headers on every request: 'UserName', 'Secret', and 'ApiIntegrationCode', plus 'Content-Type: application/json'.
- Determine your zone-specific base URL by calling GET /zoneInformation?user={email} before making entity calls.
- Ensure TLS 1.2 is used for all inbound connections.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| API User (system) security level | Provides full system administrator access to Autotask modules, features, and data via the REST API with no UI access. No per-seat charge; no limit on number of API-only users. | All REST API access |
| Create Company Webhooks permission | Must be explicitly enabled on the API user's security level under the 'Other' tab. Disabled by default for all security levels. | Creating and managing webhooks |
| Impersonation permission | Must be enabled on both the API-only user's security level and the impersonated resource's security level to attribute actions to a specific user. | ImpersonationResourceId header usage |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | integer | System-assigned unique identifier for the resource. | read-only (system-set; do not supply) | read-only | Attempting to set id on POST will cause the create to fail. |
| firstName | string(50) | Resource's first name. | required | optional | |
| lastName | string(50) | Resource's last name. | required | optional | |
| string(254) | Primary email address. Max 254 characters enforced by the API. | required | optional | Also email2 and email3 fields available; same 254-char limit applies. | |
| userName | string(254) | Login username for the resource. | required | read-only after creation | |
| password | string | Resource login password. Never returned on query (always null). | required | optional (set to new value to change) | If strong password policy is enabled: min 7 chars, at least one special character in positions 2-6, must differ from previous 5 passwords. |
| securityLevelID | integer (picklist) | References the security level assigned to the resource. | required | optional | Use GET /SecurityLevels to retrieve valid picklist values. |
| licenseType | integer (picklist) | License type assigned to the resource (e.g., Full, Limited, API-only). | required | optional | |
| isActive | boolean | Indicates whether the resource account is active. | optional (defaults to true) | optional | |
| phone | string(25) | Primary phone number. | optional | optional | |
| mobilePhone | string(25) | Mobile phone number. | optional | optional | |
| title | string(50) | Job title of the resource. | optional | optional | |
| departmentID | integer (reference) | References the department the resource belongs to. | optional | optional | |
| locationID | integer (reference) | References the office location of the resource. | optional | optional | |
| defaultServiceDeskRoleID | integer (reference) | Default service desk role assigned to the resource. | optional | optional | |
| internalCost | decimal | Internal cost rate for the resource. | optional | optional | If the date range for Internal Cost does not include the current date, value is returned as 0. |
| hireDate | datetime (UTC) | Date the resource was hired. | optional | optional | All datetime fields stored and returned in UTC. |
| userDefinedFields | array of {Name, value} | Customer-specific user-defined fields attached to the resource. | optional | optional | UDF names and values vary per Autotask implementation. Query /Resources/entityInformation/fields to discover available UDFs. |
Core endpoints
Get Resource by ID
- Method: GET
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/Resources/{id} - Watch out for: Returns a single item object (not an items array). A 404 is returned if the ID does not exist.
Request example
GET /V1.0/Resources/29683995
Headers:
UserName: apiuser@example.com
Secret: abc123
ApiIntegrationCode: ASHJKLFDKAHKASLFH85LSA905H
Content-Type: application/json
Response example
{
"item": {
"id": 29683995,
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@example.com",
"isActive": true,
"userDefinedFields": []
}
}
Query Resources (filter)
- Method: POST
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/Resources/query - Watch out for: GET query strings are limited to 2048 characters; use POST for complex filters. Max 500 records per page.
Request example
POST /V1.0/Resources/query
{
"filter": [
{"op": "eq", "field": "isActive", "value": true}
],
"MaxRecords": 500
}
Response example
{
"items": [{"id": 29683995, "firstName": "Jane", ...}],
"pageDetails": {
"count": 1,
"requestCount": 500,
"prevPageUrl": null,
"nextPageUrl": null
}
}
Create Resource
- Method: POST
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/Resources - Watch out for: Do not include 'id' in the POST body - the create will fail. Password is never returned on subsequent queries.
Request example
POST /V1.0/Resources
{
"firstName": "John",
"lastName": "Smith",
"email": "john@example.com",
"userName": "john@example.com",
"password": "P@ssw0rd!",
"securityLevelID": 1,
"licenseType": 1,
"isActive": true
}
Response example
{
"itemId": 29684100
}
Update Resource (partial)
- Method: PATCH
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/Resources - Watch out for: PATCH only updates supplied fields. Read-only fields are silently ignored. 'id' must be included in the body.
Request example
PATCH /V1.0/Resources
{
"id": 29684100,
"isActive": false,
"title": "Senior Engineer"
}
Response example
{
"itemId": 29684100
}
Replace Resource (full)
- Method: PUT
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/Resources - Watch out for: PUT replaces the full entity. Omitting optional fields may clear existing values.
Request example
PUT /V1.0/Resources
{
"id": 29684100,
"firstName": "John",
"lastName": "Smith",
"email": "john@example.com",
"isActive": true
}
Response example
{
"itemId": 29684100
}
Get Resource Field Metadata
- Method: GET
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/Resources/entityInformation/fields - Watch out for: Use this endpoint to discover picklist values, UDF definitions, and field constraints specific to your Autotask instance - they vary per implementation.
Request example
GET /V1.0/Resources/entityInformation/fields
Response example
{
"fields": [
{"name": "firstName", "dataType": "string",
"isRequired": true, "isReadOnly": false, ...}
]
}
Get Zone Information
- Method: GET
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/zoneInformation?user={email} - Watch out for: Must be the first call made to determine the correct zone-specific base URL. All subsequent calls must use the returned zone URL.
Request example
GET /V1.0/zoneInformation?user=apiuser@example.com
Response example
{
"url": "https://webservices4.autotask.net/",
"webUrl": "https://ww4.autotask.net/",
"zoneId": 4
}
Create Company Webhook (for user-change events)
- Method: POST
- URL:
https://webservices[n].autotask.net/ATServicesRest/V1.0/CompanyWebhooks - Watch out for: Webhook creation permission is disabled by default on all security levels. Must be explicitly enabled on the API user's security level under the 'Other' tab. Webhooks only fire if the webhook owner has the required entity permissions.
Request example
POST /V1.0/CompanyWebhooks
{
"IsActive": true,
"Name": "myapp.Resources.Modify",
"WebhookUrl": "https://myapp.example.com/hook",
"DeactivationUrl": "https://myapp.example.com/deactivate",
"IsSubscribedToUpdateEvents": true,
"SecretKey": "mysecret123"
}
Response example
{
"itemId": 5
}
Rate limits, pagination, and events
- Rate limits: Autotask enforces a limit of 10,000 API requests per rolling 60-minute window per database (counting all integrations combined). A usage-based latency is added as usage approaches the threshold (e.g., 0.5s latency at 50% usage, 1s at 75%). A 5-minute execution timeout applies to all REST API calls. Thread limits also apply per object endpoint per tracking identifier (default 3 threads for integrations created after 2023.1).
- Rate-limit headers: No
- Retry-After header: No
- Rate-limit notes: Threshold applies across all integrations sharing the same Autotask database. Exceeding the limit suspends API access for the entire tenant. Autotask sends email notifications when the threshold is exceeded. Use the 'API Activity by Hour' report in Autotask to monitor usage. Call batching is not available for the REST API.
- Pagination method: cursor
- Default page size: 500
- Max page size: 500
- Pagination pointer: MaxRecords (in search body); nextPageUrl / prevPageUrl returned in pageDetails
| Plan | Limit | Concurrent |
|---|---|---|
| All plans (per database) | 10,000 requests per rolling 60-minute window | 3 |
- Webhooks available: Yes
- Webhook notes: Autotask supports outbound webhooks created and managed entirely via the REST or SOAP API. Webhooks fire an HTTP POST to a registered URL when a subscribed event occurs. Callouts typically fire within one minute of a trigger event; up to five minutes under heavy load.
- Alternative event strategy: Poll the Resources or Contacts endpoints using LastModifiedDate filters to detect changes without webhooks. Webhooks are the preferred approach as they reduce API call volume.
- Webhook events: Create (entity record created), Update/PATCH (subscribed field or UDF changed), PUT (full entity update), Delete (entity record deleted), Deactivate (webhook callout deactivated)
SCIM API status
- SCIM available: No
- SCIM version: Not documented
- Plan required: N/A - No native SCIM endpoint in Autotask PSA. SCIM provisioning is available only via third-party IdP integrations (e.g., Okta SCIM connector to Autotask).
- Endpoint: Not documented
Limitations:
- No native SCIM 2.0 endpoint exposed by Autotask PSA.
- SCIM-like provisioning requires an Okta integration or similar IdP connector that maps SCIM calls to Autotask REST API calls.
- The Autotask REST API does not support SSO authentication; API credentials are separate from SSO credentials.
Common scenarios
Three core automation scenarios are well-supported by the API:
- Provision: POST /Resources with required fields (firstName, lastName, email, userName, password, securityLevelID, licenseType, isActive=true). Do not include 'id' in the body-it causes the request to fail. Fetch picklist values for securityLevelID from GET /Resources/entityInformation/fields first, as values are instance-specific.
- Deprovision: PATCH /Resources with {"id":
, "isActive": false}. There is no DELETE operation on the Resources entity; deactivation is the only supported offboarding path via the API. - Real-time sync: POST /CompanyWebhooks to register a callout URL, then POST /CompanyWebhookFields to specify which field changes trigger it. Webhooks fire within one minute under normal load. Note: webhook creation permission is disabled by default on all security levels and must be explicitly granted.
Provision a new internal user (Resource)
- Call GET /zoneInformation?user={adminEmail} to resolve the correct zone-specific base URL.
- Call GET /Resources/entityInformation/fields to discover required fields, picklist values for securityLevelID and licenseType specific to the instance.
- Call POST /Resources with firstName, lastName, email, userName, password, securityLevelID, licenseType, and isActive=true.
- Store the returned itemId as the resource's Autotask ID for future updates.
- Optionally call PATCH /Resources with the new id to set additional fields (title, departmentID, etc.).
Watch out for: Do not include 'id' in the POST body. Password must meet strong-password policy if enabled (min 7 chars, special character in positions 2-6, not one of last 5 passwords). Picklist values for securityLevelID must be fetched from the target instance - they are not universal.
Deprovision / deactivate a user
- Query POST /Resources/query with a filter on email or userName to retrieve the resource's id.
- Call PATCH /Resources with {"id":
, "isActive": false} to deactivate the account. - Optionally verify deactivation by calling GET /Resources/{id} and confirming isActive is false.
Watch out for: There is no DELETE operation on the Resources entity - deactivation via isActive=false is the correct offboarding method. Deleting a resource is not supported via the REST API.
Sync user changes in near-real-time using webhooks
- Ensure the API user's security level has 'Create Company Webhooks' permission enabled (Admin > Security Levels > Other tab).
- Call POST /CompanyWebhooks (or the relevant entity webhook endpoint) with WebhookUrl, DeactivationUrl, IsActive=true, and the desired event subscriptions (IsSubscribedToUpdateEvents, etc.).
- Register WebhookFields via POST /CompanyWebhookFields to specify which field changes trigger the callout.
- Receive HTTP POST payloads at the registered WebhookUrl when subscribed events occur (typically within 1 minute).
- Use the payload's entity data to update the external system; use ExcludedResources to suppress callouts triggered by the integration's own writes.
Watch out for: Webhooks only fire if the webhook owner (API user) has entity-level and Line of Business permissions for the records involved. If the owner lacks access to a record, the callout will not fire for that record. Webhook creation permission is off by default - it must be explicitly granted per security level.
Why building this yourself is a trap
The rate limit is per database, not per integration: all integrations sharing the same Autotask tenant draw from a single pool of 10,000 requests per rolling 60-minute window. One poorly throttled integration can degrade every other connected system in the tenant.
Additional constraints compound this: a hard cap of 500 records per query page, a 3-thread-per-endpoint default for integrations created after 2023.1, and a 5-minute execution timeout on all REST calls.
Webhooks mitigate call volume but introduce their own caveat-callouts only fire for records the webhook-owning API user has permission to access, so a misconfigured security level silently drops events without error.
Automate Autotask PSA 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.