I’m calling a custom Thing service through the REST API using an Application Key, but consistently getting ‘Permission Denied’ errors. The key is configured with full permissions on the Thing, and I can successfully call built-in services like GetPropertyValues. However, my custom service ‘ProcessBillingData’ fails immediately.
The API headers include the correct appKey, and I’ve verified the Thing permissions show the Application Key has Execute rights. The service works fine when called from a Mashup using the same user context.
POST /Thingworx/Things/BillingProcessor/Services/ProcessBillingData
appKey: 12345678-abcd-1234-abcd-123456789abc
Content-Type: application/json
Error response is just ‘Permission Denied’ with no additional details. This is blocking our automation pipeline for invoice processing. Has anyone encountered service-level permission issues that don’t show up in the Thing permissions UI?
The issue is likely the User’s Organization or Project-level permissions. Even with Thing permissions, if the User doesn’t have PropertyRead/ServiceExecute at the Organization level for custom extensions, ThingWorx blocks the call. This is a common gotcha with custom services versus built-in ones.
Also check if your service uses any Resources or DataTables - the User needs visibility permissions on those dependencies too. The error message is vague because ThingWorx doesn’t expose the specific permission failure in API responses for security reasons.
I’ve seen this exact scenario multiple times. Here’s the systematic approach to fix it:
1. Application Key to User Mapping:
Verify in Security > Application Keys that your key maps to a User with appropriate permissions. The User (not just the key) must have Execute rights on the Thing and service.
2. Service-Level Permissions:
Custom services have independent permission settings. In the service editor, go to Permissions tab and explicitly grant Execute to either:
- The mapped User directly
- A User Group the User belongs to
- Set to allow ‘Everyone’ if appropriate for your security model
3. REST API Headers:
Ensure you’re using the correct header format:
appKey: your-app-key-here
Content-Type: application/json
Accept: application/json
4. Visibility Permissions:
The mapped User needs ServiceExecute runtime permission at the Thing level. Go to Thing > Permissions > Runtime and verify ServiceExecute is granted to the User or their group.
5. Downstream Dependencies:
If your service calls other Things/services (like BillingEngine.PostInvoice), the User needs Execute permissions on ALL downstream resources. Map out the call chain and verify each step.
6. Enable Debug Logging:
Add this to ApplicationLog to see detailed permission checks:
log.setLevel('Security', 'DEBUG');
This will show exactly which permission check is failing.
Common Resolution:
In 80% of cases, the issue is the service Permissions tab not explicitly listing the Application Key’s mapped User. Set the service permission to explicitly allow your User/Group rather than relying on inheritance. After that, restart the service or refresh permissions cache by toggling the Thing’s enabled state.
If you’re still blocked after these steps, check if there are any Organization-level restrictions on custom service execution or if your ThingWorx version has known permission bugs (97.x had issues with inherited service permissions that were fixed in later patches).
Check the service definition itself - custom services have their own permission settings separate from Thing permissions. Go to the service editor and look at the Permissions tab on the service. Even if the Application Key has Thing-level Execute rights, the service might have explicit deny rules or missing Allow entries.
Also verify the service isn’t calling other restricted services internally. If ProcessBillingData invokes another Thing’s service, your key needs permissions on that downstream Thing too.