Cortex API (Legacy)
The Cortex API is Atria's legacy XML API. It can query and update customers, users, services, provisioning requests, and other core Atria objects.
For a new integration, start with the REST API. It uses bearer tokens, has an interactive reference, and is the preferred interface for currently supported operations. Use the Cortex API when maintaining an existing XML integration or when the operation you need is not available through REST.
The Cortex API uses HTTP Basic authentication and an XML contract that varies by object and installed service. Build new integrations against REST where possible, and test Cortex API changes in a non-production environment first.
How the API works
An integration sends an XML document to the Cortex API. Read operations return XML immediately. Changes that require provisioning normally update Atria and enqueue background work; the initial response contains a provisioning request ID that can be queried separately.
The main object hierarchy is:
customer
├── service
└── user
└── service
The authenticated Atria account determines which customers and operations are visible. The account must have Cortex API Access as well as the normal permission for each requested operation.
Before you begin
You need:
- The base URL of the Atria deployment.
- An Atria account with Cortex API Access and only the additional permissions the integration needs.
- HTTPS enabled for the Cortex API site.
- A test customer or non-production environment for validating changes.
Use HTTPS only. HTTP Basic authentication does not protect credentials unless the connection is encrypted.
Do not put credentials in source control, request samples, logs, or error reports. Use a secret store appropriate to the application running the integration.
Endpoint and authentication
Send an HTTP POST request to:
https://<atria-host>/CortexAPI/Default.aspx
Use these headers:
Authorization: Basic <base64-encoded-username-and-password>
Content-Type: text/xml; charset=utf-8
A SOAP compatibility endpoint is also exposed at:
https://<atria-host>/CortexAPI/Service.asmx
Its SubmitRequest method accepts the XML request as a string. Prefer the direct XML endpoint for simple HTTP integrations.
Request structure
Every request uses a <request> root element with version="1.0" and an action attribute:
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="FIND">
<customer>
<name>Example%</name>
</customer>
</request>
Use lowercase element names as shown in the examples. XML names are case-sensitive. Action values are conventionally written in uppercase, although the API evaluates the value without regard to case.
An optional id attribute can be used to correlate requests and responses:
<request version="1.0" action="GET" id="crm-10482">
<customer>
<name>EXAMPLE</name>
</customer>
</request>
The API copies that value to the <response> element.
Actions
| Action | Purpose |
|---|---|
FIND | Search for objects using one or more criteria. A % in supported text fields acts as a wildcard. |
GET | Retrieve an identified object and the requested child data. |
SET | Create or update an object, or request provisioning or deprovisioning. |
DELETE | Delete an eligible object. Provisioned objects normally need to be deprovisioned first. |
Not every action is available for every object. For example, provisioning request records support GET only.
Root objects
The API implementation recognises these top-level objects:
| Object | Typical use |
|---|---|
customer | Customers, users, customer services, and user services |
request | Provisioning request status, times, and logs |
identity | Details about the authenticated identity |
global | Global data exposed by the API |
location | Location lookup |
template | Reusable XML request templates |
report | Defined report execution |
approval | Workflow approval operations |
token | Token-related compatibility operations |
dataretrieval | Defined data-retrieval operations |
The available child elements and service properties depend on the object, installed services, and the permissions of the authenticated account. Use the discovery workflow below instead of assuming that every Atria environment has the same schema.
Responses and errors
A successful read returns the requested objects beneath <response>:
<?xml version="1.0" encoding="utf-8"?>
<response version="1.0" id="crm-10482">
<customer>
<name>EXAMPLE</name>
<id>42</id>
<fullname>Example Customer</fullname>
<status>Provisioned</status>
</customer>
</response>
An unsuccessful request returns an <error> element:
<?xml version="1.0" encoding="utf-8"?>
<response version="1.0">
<error>
<id>1000</id>
<message>Not authorized</message>
</error>
</response>
The direct Default.aspx endpoint can return HTTP 200 even when the XML contains an API error. Always parse the response and treat <response><error> as a failed operation. Do not rely on the HTTP status code alone.
The request root supports trace="true", but a traced error may expose implementation details. Use tracing only during controlled troubleshooting and never return traced responses to end users.
Recommended discovery workflow
The Cortex API does not publish a single fixed schema for every installed service. Use this sequence when building an operation:
- Use
FINDto locate the customer, user, or service and obtain its exact name or ID. - Use
GETto retrieve the object and the section you plan to change. - Copy the relevant part of the
GETresponse into aSETrequest. - Remove response-only and unrelated elements.
- Change only the required values and submit the request in a test environment.
- If the response contains a provisioning request ID, poll it until the work finishes.
This avoids depending on properties that are absent, renamed, or not enabled in a particular deployment.
Customer examples
Find customers
The customer search supports name, id, fullname, billingid, primarydomain, status, and parent criteria.
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="FIND">
<customer>
<name>EXAMPLE%</name>
<status>Provisioned</status>
</customer>
</request>
An empty customer element returns the customers visible to the authenticated account:
<request version="1.0" action="FIND">
<customer />
</request>
Get a customer
Identify the customer by name or id:
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="GET">
<customer>
<name>EXAMPLE</name>
</customer>
</request>
Create a customer
A new customer requires name, fullname, contactname, contactemail, and primarydomain. The authenticated account's customer is used as the parent unless a permitted parent is supplied.
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="SET">
<customer>
<name>EXAMPLE</name>
<fullname>Example Customer</fullname>
<contactname>Customer Administrator</contactname>
<contactemail>administrator@example.com</contactemail>
<primarydomain>example.com</primarydomain>
<status>Provisioned</status>
</customer>
</request>
SET changes are provisioned by default. An explicit status of Provisioned can also force a provisioning request when no property value changed; NotProvisioned requests deprovisioning.
Update a customer
Identify the existing customer and include only the fields to change:
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="SET">
<customer>
<name>EXAMPLE</name>
<contactname>New Contact</contactname>
<contactemail>new.contact@example.com</contactemail>
</customer>
</request>
Deprovision and delete a customer
Deprovisioning and deletion are separate operations:
<request version="1.0" action="SET">
<customer>
<name>EXAMPLE</name>
<status>NotProvisioned</status>
</customer>
</request>
After deprovisioning has completed successfully, delete the customer only if that is the intended and authorised outcome:
<request version="1.0" action="DELETE">
<customer>
<name>EXAMPLE</name>
</customer>
</request>
DELETE is not the same as deprovisioning. Confirm that the object is in the required state, keep an audit record of the request, and require an explicit operator decision before deleting production data.
User examples
Users are addressed inside their customer.
Find users
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="FIND">
<customer>
<name>EXAMPLE</name>
<user>
<name>a%</name>
</user>
</customer>
</request>
Get a user
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="GET">
<customer>
<name>EXAMPLE</name>
<user>
<name>alex</name>
</user>
</customer>
</request>
Provision or deprovision a user
For a provisioning state change, use SET and specify one of the two accepted target values: Provisioned or NotProvisioned.
<request version="1.0" action="SET">
<customer>
<name>EXAMPLE</name>
<user>
<name>alex</name>
<status>Provisioned</status>
</user>
</customer>
</request>
To deprovision the user, change the status to NotProvisioned. Do not send intermediate states such as InProgress or Failed; those are reported states, not valid targets for SET.
Service examples
Customer services are nested beneath <customer>. User services are nested beneath <customer><user>.
Discover customer services
<request version="1.0" action="FIND">
<customer>
<name>EXAMPLE</name>
<service />
</customer>
</request>
Customer service searches can be narrowed by name, fullname, location, or status.
Get a service and its available properties
Start with the service name returned by FIND:
<request version="1.0" action="GET">
<customer>
<name>EXAMPLE</name>
<service>
<name>SERVICE_NAME</name>
<properties />
</service>
</customer>
</request>
Use the returned service structure as the basis of a SET request. Service names and properties are implementation-specific; do not copy property sets from another service or environment without discovering them first.
Provision a user service
<request version="1.0" action="SET">
<customer>
<name>EXAMPLE</name>
<user>
<name>alex</name>
<service>
<name>SERVICE_NAME</name>
<status>Provisioned</status>
</service>
</user>
</customer>
</request>
Some services require additional properties, packages, resources, or a customer-level service to be provisioned first. Retrieve the service with GET and validate its dependencies before sending SET.
Track provisioning requests
A change that queues background work returns a request identifier:
<response version="1.0">
<request>
<id>12345</id>
</request>
</response>
Query the request with GET:
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="GET">
<request>
<id>12345</id>
<times />
<log />
</request>
</request>
The response includes the request status and object status. <times /> asks for lifecycle timestamps and <log /> asks for log entries. To retrieve child requests created by a parent operation, query by parentid:
<request version="1.0" action="GET">
<request>
<parentid>12345</parentid>
<times />
<log />
</request>
</request>
Treat provisioning as asynchronous. Do not assume that a successful SET response means the downstream system has already been changed.
Send a request with PowerShell
The following PowerShell example prompts for a credential, sends a request over HTTPS, parses the XML response, and fails if the API returned an error:
$apiUri = 'https://atria.example.com/CortexAPI/Default.aspx'
$credential = Get-Credential
$requestXml = @'
<?xml version="1.0" encoding="utf-8"?>
<request version="1.0" action="FIND" id="example-1">
<customer>
<name>EXAMPLE%</name>
</customer>
</request>
'@
$usernameAndPassword = '{0}:{1}' -f `
$credential.UserName,
$credential.GetNetworkCredential().Password
$basicToken = [Convert]::ToBase64String(
[Text.Encoding]::UTF8.GetBytes($usernameAndPassword)
)
$headers = @{ Authorization = "Basic $basicToken" }
try {
$httpResponse = Invoke-WebRequest `
-Uri $apiUri `
-Method Post `
-Headers $headers `
-ContentType 'text/xml; charset=utf-8' `
-Body $requestXml
[xml]$responseXml = $httpResponse.Content
if ($responseXml.response.error) {
$errorId = $responseXml.response.error.id
$errorMessage = $responseXml.response.error.message
throw "Cortex API error $errorId`: $errorMessage"
}
$responseXml.response
}
finally {
Remove-Variable usernameAndPassword, basicToken -ErrorAction SilentlyContinue
}
For unattended automation, replace Get-Credential with retrieval from an approved secret store. Do not disable TLS certificate validation to make a test pass; install and trust the correct certificate instead.
Integration checklist
Before putting an integration into production:
- Prefer the REST API for operations it supports.
- Use a dedicated, least-privileged Atria account.
- Send requests only over HTTPS.
- Discover objects and service properties with
FINDandGETbefore usingSET. - Parse the XML error element even when the HTTP status is
200. - Store and monitor every returned provisioning request ID.
- Apply timeouts and bounded retry logic; do not repeatedly submit the same change while provisioning is still running.
- Keep credentials and full request bodies out of logs where they may contain passwords or personal data.
- Require additional safeguards around deprovisioning and deletion.