Custom Service Provisioning
A custom service uses the standard customer-service and user-service request contract. This gives custom rules the customer or user identity, service metadata, effective service properties, access levels, and—when configured—service package properties.
Event names
Replace <ServiceName> with the internal service name, not its display label.
Event$Customer Service$<ServiceName>$After Provision
Event$Customer Service$<ServiceName>$After Deprovision
Event$User Service$<ServiceName>$After Provision
Event$User Service$<ServiceName>$After Deprovision
The full PreProvision, Provision, PostProvision, PreDeprovision, Deprovision, and PostDeprovision lifecycle is available, with Before, Main, and After rule sets for each phase.
Customer-service request
A customer-service request begins with the base customer properties—from CustomerID through the audit values—and adds:
| Property | Shape | Description |
|---|---|---|
ServiceProperties | Hashtable | Effective properties for this customer-service instance. |
ServiceID | Integer | Customer-service database identifier. |
ServiceName | String | Internal service name used in event paths. |
ServiceLabel | String | Customer-facing service label. |
ServiceAdminUsers | String array | Service administrator accounts. |
ServiceObjectID | Integer | Provisioning object identifier for the customer service. |
CorrelationID | String | Correlation value for related service requests. |
ServiceAccessLevels | String array | User plans assigned to the customer service. |
ServicePackage | Hashtable | Default customer package properties; present only when customer package creation is enabled and a package exists. |
ServiceInstance | String | Instance name; present only for a multi-instance service. |
CustomerRoles is also added to customer-service provision and deprovision requests. The core-customer-only values such as CustomerProperties, CustomerLevel, and ProxyServiceProperties are not automatically copied to every service request. Proxy service requests add additional Proxy-specific customer values.
User-service request
A user-service request includes the base customer and user properties—through SystemDomain in the user table—then adds:
| Property | Shape | Description |
|---|---|---|
UserServiceObjectID | Integer | Provisioning object identifier for this user-service assignment. |
ServiceProperties | Hashtable | Merged customer-service, user-service, enabled user-plan, and provider-added properties. |
ServiceID | Integer | Customer-service database identifier. |
ServiceName | String | Internal service name. |
ServiceLabel | String | Customer-facing service label. |
ServiceAccessLevels | String array | Enabled access-level names for the user. |
ServicePackage | Hashtable | Default customer package properties when customer package creation is enabled and a package exists. |
ServiceInstance | String | Sanitised service instance name for a multi-instance service. |
isCopyProcess | Boolean | Present and True when the request was generated by a copy process. |
The core-user-only values such as top-level UserProperties, SpecificProperties, UserServices, and UserConnectors are not automatically copied to every user-service request. A service can add equivalent values inside ServiceProperties; the MSOL service does this for UserProperties.
The service implementation can add more ServiceProperties. For a user service, CORE builds that hashtable in this order:
- customer-service properties;
- user-service properties;
- properties from enabled user access levels;
- values added by the service's customer and user provider classes.
On deprovision, CORE uses access levels that were originally enabled and adds the internal package-deprovision flag. If a customer-service removal caused the user-service removal, the service can also receive isCustomerServiceDeprovision.
Access custom service properties
Assume a custom service defines an ExternalSystemUrl customer-service property and a ProfileCode user-plan property. Both are available through ServiceProperties:
{ServiceProperties}("ExternalSystemUrl")
{ServiceProperties}("ProfileCode")
Example condition:
Not String.IsNullOrEmpty({ServiceProperties}("ExternalSystemUrl")) AndAlso
Not String.IsNullOrEmpty({ServiceProperties}("ProfileCode"))
Choose unique property names. When two sources define the same key, the merged value depends on the merge order and the service implementation.
Access service package properties
Customer package template properties are exposed separately through ServicePackage:
{ServicePackage}("ExternalSku")
Example Powershell Execute script parameter:
& 'C:\AtriaScripts\Set-ExternalPlan.ps1' `
-CustomerId {CustomerID} `
-PlanCode '{ServicePackage}("ExternalSku")'
Add a condition because ServicePackage is optional:
Not {ServicePackage} Is Nothing AndAlso
Not String.IsNullOrEmpty({ServicePackage}("ExternalSku"))
ServicePackage contains the default customer package selected for the service. It is not a list of every package and it is not populated for services that do not enable customer package creation.
A practical custom service pattern
For an external SaaS service:
- Put tenant creation in
Event$Customer Service$<ServiceName>$After Provision. - Store any external tenant reference using an Atria-supported persistence mechanism; a property created only by a rule lasts for the current request path.
- Put user assignment in
Event$User Service$<ServiceName>$After Provision. - Put user removal before tenant removal in the matching deprovision events.
- Make every create/update action safe to repeat because provision events can represent both initial provision and later changes.
- Confirm the live property set with a journalled request before enabling the rule in production.
See Rule values and PowerShell actions for substitution and result-property behaviour.