Configure the environment; don't detect it

Orchestrate has no function that returns "production" or "sandbox". The reliable way is to tell the orchestration explicitly: create an app attribute such as environmentName, assign it a value for each environment in App Manager on the tenant, and read it with attrstore.stringValue("environmentName"). Workday's attribute pages describe exactly this behaviour: an app attribute resolves its value based on the tenant environment the app runs in.

What Orchestrate does give you is the tenant's name, context.tenant(). That is useful in a log line, but it is a naming convention, not an environment type, and deciding "is this production?" from a string match is how test data ends up at a partner's live endpoint.

Why the tenant name and tenant-level settings are not enough

context.tenant() returns the name of the tenant running the orchestration. Tenant names follow each customer's own convention, often a base name for production with a suffix for sandbox and preview, so a check like "the name has no suffix" is a guess that breaks the day a new tenant is added. system.apiGatewayEndpoint() returns the API gateway, for example https://api.workday.com, which identifies the gateway, not the environment.

The bigger trap is configuration stored in the tenant itself. Workday's Integration App Lifecycle page notes that Sandbox and Sandbox Preview tenants are refreshed every week with production data. Anything production holds as tenant data, such as an integration system attribute saying isProduction = true or a production endpoint URL, arrives in the sandbox with the next refresh. An orchestration that trusts that value will, after a refresh, behave as production while running in the sandbox.

How app attribute values are scoped to an environment

App attributes are defined once in the app on the Console and saved in App Hub; their values are set per tenant in App Manager. When you enter a value, the Environment field decides where it applies. Workday's example assigns one attribute three ways:

Environment Value
EnvironmentWCPDEVValuevalue for the developer tenant
EnvironmentSANDBOXValuevalue for the sandbox
EnvironmentPRODValuevalue for production

Two rules from Workday's Assign Integration App Attribute Values page make this safe. A value whose Environment is left blank applies to all environments, so never leave the environment-identifying attribute blank. And attribute values cannot be transferred across environments: you assign them separately in each environment the app is deployed to.

The environment scoping is what protects you across a refresh. Workday says an app attribute resolves its value from the environment the app runs in, so a value scoped to PROD is not the value a sandbox reads, whatever tenant data the refresh copied. If the sandbox has no value of its own, the read in step 4 below stops the run instead of returning PROD.

Step by step

  1. Create the attribute. On the Console, open the app, and on the Overview tab under Attributes click Add Another Attribute. Name it environmentName, type String, and save. The Console generates a new build.
  2. Make it available in each tenant. Deploy or install the build to each tenant, as the attributes page describes for the Promotions tab.
  3. Assign values in each tenant. In App Manager on the tenant, click Configure for the app, click Update App Configuration under App Attributes and confirm, then Edit the default configuration and enter the value with its Environment: PROD in production, SANDBOX in the sandbox, and so on.
  4. Read it at the start of the orchestration. In a Create Values step:
attrstore.stringValue("environmentName")

The attrstore reference says stringValue throws if the value isn't a string or doesn't exist. That is what you want: an orchestration in a tenant where nobody set the value stops at the first step instead of guessing.

  1. Fail closed on anything unexpected. Add a Continue on Conditions step whose Assertion checks that the value is one of the names you defined. If the assertion is false, the orchestration stops and logs the step's Message, so write one that says which value was expected.

Prefer per-environment values over a production flag

A boolean isProduction invites code like "if production, call the live URL, else call the test URL", with both URLs written into the app. It is cleaner to store the things that differ as their own environment-scoped attributes: the partner endpoint, the target folder, the notification address. The orchestration then reads attrstore.stringValue("partnerEndpoint") and has no branch at all; each environment's value is set where it runs.

Keep environmentName for the decisions that really are about the environment: refusing to run a destructive cleanup in production, adding a "TEST" prefix to outbound file names outside production, or switching off a notification to real employees.

Secrets do not belong in attributes. Keep credentials in the tenant's credential store; the Integration App Lifecycle page notes that refresh tokens on the external client credential store must be created separately in Sandbox and Sandbox Preview. See OAuth 2.0 credentials for third-party APIs.

What about Integration System attributes?

In the Integration System template, intsys functions such as intsys.stringAttributeValueOrDefault(name, default) read attributes configured on the integration system in the tenant. They are the right place for values an administrator should change without an app release, such as a report path or a business form layout. Because they are tenant configuration, treat them as production values that will appear in the sandbox after a refresh, and do not use them to identify the environment.

Workday's Orchestration Processes page gives individual processes 60 minutes in an app promoted to production and 45 minutes in an app not yet promoted. That is a property of the app's promotion level, not a signal to read, but it explains why a long run that passes in production can time out in a sandbox.

Prove it after every refresh

At the start of each run, write the resolved environment and context.tenant() into an Add Integration Message or log entry (see logging in Orchestrate), so every integration event says where it thought it ran. Then:

  1. Run once in each tenant and confirm the message shows the expected environment. The app logs on the Developer Site record the environment independently in their wd_env field (IMPL, SANDBOX, PROD or WCPDEV), so compare your message with that value for the same run. No Orchestrate global function returns wd_env, so it is a check, not something to branch on.
  2. After the next sandbox refresh, run once in the sandbox before anything scheduled does, and confirm it still reports SANDBOX and calls the test endpoint.
  3. In a newly created tenant with no attribute value assigned, confirm the run stops at the first step.

For how sandbox refreshes affect other configuration, see what changes when a Workday sandbox is refreshed.

Sources checked