Proofpoint Enterprise DLP Integration Guide
Overview
The Proofpoint Enterprise DLP integration connects your workflows to the Proofpoint
Enterprise Data Loss Prevention / Data Security platform (the op.analyze
"ObserveIT" / ITM stack). It exposes the full platform API surface — data-loss
events across every channel (endpoint, CASB, email, network, threat, isolation),
data classification, incident workflow, DLP policies and rules, tenant/identity
administration, notifications and more — directly from your workflows.
Unlike channel-specific connectors, Proofpoint Enterprise DLP is a multi-service
platform. Every service ("module") is published under /v2/apis/{module} and
described by its own OpenAPI specification. This integration is schema-driven
(Pattern B): each operation's HTTP method and path are read from a generated
schema, so all 560 operations across 11 modules share one generic request
dispatcher. There is no bespoke code per endpoint.
Scope note. This connector targets Enterprise DLP (multi-channel Data Security). It is not the Adaptive Email / Tessian email-only product. The multi-channel presence in a live tenant (audit, CASB, endpoint, threat, network events) is what identifies it as Enterprise DLP.
Status
The integration currently covers 11 platform modules / 560 operations:
| Module (resource) | Path prefix | Operations | What it does |
|---|---|---|---|
| Activity | /v2/apis/activity | 37 | Query DLP events; manage incidents (workflow, comments, tags, severity); remediation; aggregate reports |
| Classification | /v2/apis/classification | 124 | Business categories, ML classifiers/models, seed groups, embeddings, clusters, file-version analysis, classification jobs |
| Workbench | /v2/apis/workbench | 21 | Explorations (saved searches/analytics), subscriptions, ACLs, ad-hoc queries over activity data |
| Auth | /v2/apis/auth | 197 | Tenants, users, principals, groups, personas, policies, capabilities, OAuth clients/tokens, identity providers |
| Notification | /v2/apis/notification | 24 | Notification templates, target groups (recipients), dispatch/query notification requests |
| Resolver | /v2/apis/resolver | 18 | IP geo-location, Misdirected Email (MDE) onboarding, MDE policies/detector-sets/categories, XML manifests |
| Depot | /v2/apis/depot | 37 | Configuration/settings store: articles (versioned settings docs), predicates (reusable detector logic), tags, properties |
| Landlord | /v2/apis/landlord | 48 | Multi-tenant provisioning: customers, tenants, agent/data realms, regions, resource-groups, deployment configurations |
| Registry | /v2/apis/registry | 40 | DLP policies and rules (CRUD, versions), configurations and policy bindings, service instances, tasks |
| Storage | /v2/apis/storage | 7 | Object storage in bins (get/delete/batch), resource object-requests, DLP content scans |
| Scheduler | /v2/apis/scheduler | 7 | Scheduled tasks (CRUD), task executions, DSL query over the task store |
Terminology warning — "MDE". Inside the Resolver module,
mdemeans Proofpoint Misdirected Email, not Microsoft Defender for Endpoint. In the Activity module,mdeis one of the queryable event entity types (also Misdirected Email). Do not confuse either with any Microsoft product.
Credential Configuration
Authentication Method
The Proofpoint Data Security / op.analyze platform is a standard OAuth2
authorization server: you create credentials by registering a Client
Application (which yields client_id + client_secret) and exchange them via an
OAuth2 flow for an API access token (a short-lived Bearer JWT). Proofpoint
supports all major OAuth2 flows.
This integration supports two credential modes:
| Mode | Auth type | You provide | The integration does |
|---|---|---|---|
| OAuth2 Client Credentials (recommended) | oauth2 | clientId + clientSecret (+ baseUrl, optional scope) | Calls POST /v2/apis/auth/oauth/token with grant_type=client_credentials, caches the returned access token, and refreshes it automatically before it expires. |
| Pre-issued Bearer Token | apiKey | apiToken (+ baseUrl) | Attaches the supplied JWT as-is on every request. No refresh — you rotate it yourself. |
Every request ultimately carries:
Authorization: Bearer <access token>
Pick OAuth2 Client Credentials for unattended automation: you configure the client credentials once and the integration handles token minting and refresh. Use Pre-issued Bearer Token only when you already have an access token and cannot (or prefer not to) store the client secret.
Credential fields
OAuth2 Client Credentials (oauth2):
| Field | Credential key | Required | Description | Example |
|---|---|---|---|---|
| Client ID | clientId | Yes | OAuth2 client (application) ID from a registered Client Application. | 1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d |
| Client Secret | clientSecret | Yes | OAuth2 client secret paired with clientId. | s3cr3t... |
| Scope | scope | No | OAuth2 scope requested for minted tokens. Defaults to *. | * |
| Base URL | baseUrl | Yes (defaulted) | API host for your tenant's region/pod. Defaults to https://app.us-east-1-op1.op.analyze.proofpoint.com. | https://app.us-east-1-op1.op.analyze.proofpoint.com |
Pre-issued Bearer Token (apiKey):
| Field | Credential key | Required | Description | Example |
|---|---|---|---|---|
| Bearer Token | apiToken | Yes | A Bearer JWT access token issued by the Auth API. Short-lived (typically ~8 hours). | eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... |
| Base URL | baseUrl | Yes (defaulted) | As above. | https://app.us-east-1-op1.op.analyze.proofpoint.com |
Validation: a credential is accepted when it carries either apiToken or a
full clientId + clientSecret pair. Supplying only one half of the OAuth pair is
rejected (clientSecret is required when clientId is set, and vice-versa). baseUrl
falls back to the default host and scope to * when omitted.
Anatomy of the JWT
The token is an RS256-signed JWT. Its claims scope the token to a specific customer and tenant, and set its lifetime. Understanding the claims helps diagnose auth issues:
| Claim | Meaning |
|---|---|
iss | Issuer — the auth key that signed the token (it:auth:key/...) |
jti | Token ID — used by GET /v2/apis/auth/tokens/{jti} to inspect/track the token |
iat / exp | Issued-at / expiry (Unix seconds). Lifetime is typically ~8 hours; plan for rotation |
ten | Tenant ID the token is bound to |
cus | Customer ID (GUID) the token is bound to |
knd | Token kind (e.g. lit) |
Because exp is short, a token that worked yesterday will return HTTP 401
today. This is expected — see Token expiry & rotation.
Obtaining the access token (official method: OAuth2 Client Application)
Per Proofpoint's official documentation, the native way to create credentials on the Data Security / op.analyze platform is to:
Set up Credentials for a Client Application to obtain client credentials and API access tokens. Proofpoint supports all major OAuth2 authentication flows for easy, secure access to the APIs.
In other words, the platform is a standard OAuth2 authorization server. You do
not hand-craft JWTs — you register a Client Application, receive client
credentials (client_id + client_secret), and exchange them through an OAuth2
flow for an API access token (the Bearer JWT this integration consumes).
Step 1 — Register a Client Application (get client credentials)
Create an OAuth client and record its client_id / client_secret:
- In the console/Developer Portal: register a Client Application and copy its client credentials.
- Via the API (this integration):
auth.createApplication(POST /v2/apis/auth/clients) to create the client;auth.getApplicationSet(GET /v2/apis/auth/clients) to list them. Scope the client's assignments to the minimum capabilities needed (see Permissions Model).
Step 2 — Exchange credentials for an access token (OAuth2)
The platform's OAuth2 token endpoint is auth.requestToken
(POST /v2/apis/auth/oauth/token). Proofpoint supports all major OAuth2 flows;
the relevant ones are:
| OAuth2 flow | grant_type | Use case |
|---|---|---|
| Client Credentials | client_credentials | Machine-to-machine automation (recommended for this integration). No user interaction — exchange client_id+client_secret directly for an access token. |
| Authorization Code | authorization_code | Interactive apps acting on behalf of a signed-in user. Backed by auth.promptUserForAccess / auth.createAuthorizeApplication (/v2/apis/auth/oauth/authorize) then auth.requestToken. |
| Refresh Token | refresh_token | Obtain a fresh access token without re-authenticating, when a refresh token was issued. |
Additional token utilities in the Auth module:
auth.createToken(POST /v2/apis/auth/tokens) — renew the current token.auth.getToken(GET /v2/apis/auth/tokens/{jti}) — inspect a token by itsjti.auth.checkToken(GET /v2/apis/auth/logins/validation) — validate a session.auth.getTokenKeySet(GET /v2/apis/auth/oauth/token-keys) — the public keys used to verify token signatures (JWKS).
Step 3 — Use the credentials in this integration
You have two options:
- Let the integration do the exchange (recommended). Configure the OAuth2
Client Credentials auth type with
clientId+clientSecret. The integration calls the token endpoint itself (grant_type=client_credentials), caches the access token, and refreshes it automatically shortly before expiry (it reads theexpclaim from the JWT, or anexpires_inif returned, and applies a 60-second safety buffer). You never handle raw JWTs. - Supply an access token directly. Configure the Pre-issued Bearer Token
auth type with
apiToken. Use this when you obtained the token elsewhere (console, a separateauth.requestTokencall, etc.). This mode does not refresh — rotate the token yourself.
Bootstrapping note. To call
auth.requestToken/auth.createApplicationyou already need access. In practice you bootstrap from the Proofpoint DLP console (or via your Proofpoint contact), register a dedicated Client Application for automation, then use its client credentials to mint access tokens going forward.
Base URL / regions
The base URL identifies your tenant's regional pod. The default
(https://app.us-east-1-op1.op.analyze.proofpoint.com) is the US-East pod. If your
tenant is provisioned in a different region/pod, set baseUrl to the host provided
by Proofpoint for your tenant. All module paths (/v2/apis/{module}/...) are
appended to this host.
Creating a Proofpoint Enterprise DLP credential
- Navigate to the Credentials section.
- Click Add New Credential.
- Fill in the details:
- Name: a descriptive name (e.g., "Proofpoint DLP Production").
- Integration Service: select "Proofpoint Enterprise DLP".
- Auth Type: choose one:
- OAuth2 Client Credentials (recommended) — provide clientId,
clientSecret, optionally scope (defaults to
*), and baseUrl. - Bearer Token — provide apiToken and baseUrl.
- OAuth2 Client Credentials (recommended) — provide clientId,
clientSecret, optionally scope (defaults to
- baseUrl: your regional host, or leave blank for the US-East default.
- Test Connection — this calls
GET /v2/apis/activity/_status. In OAuth2 mode it first mints a token via the client credentials; the check fails if the token endpoint rejects the credentials or the probe returns HTTP 401. A 403 on the probe is tolerated (valid token, resource not permitted). - Save.
Permissions Model
The Proofpoint DLP platform separates authentication from authorization, and this integration relies on that distinction:
| Platform response | Code | Meaning | How the integration treats it |
|---|---|---|---|
| HTTP 401 | it:error:authentication | The token is invalid, malformed, or expired. | Credential failure. ValidateCredentials fails; ExecuteOperation returns API error [401]: .... |
| HTTP 403 | it:error:authorization | The token is valid and authenticated, but the tenant/principal lacks permission (entitlement/capability) for that specific resource. | Not a credential failure. ValidateCredentials still passes; the call returns API error [403]: .... |
This is why a 403 on one module does not mean your token is bad — it means the token authenticated correctly but that module/operation is not entitled for your tenant or principal.
What grants permission
Within the platform, access is governed by the Auth module primitives:
- Capabilities (
auth.getCapabilitySet) — the granular permissions available. - Policies (
auth.getPolicySet) — bind capabilities to principals. - Personas (
auth.getPersonaSet) and assignments — role/identity grouping. - OAuth clients (
auth.getApplicationSet/createApplication) and their assignments — scope what a machine client can do.
To broaden what your automation token can do, grant the corresponding capabilities to the principal/OAuth client that mints the token (done by a tenant administrator in the Auth module or the console).
Entitlement-gated modules (observed in a standard tenant)
Some modules are provisioning/infrastructure or add-on features and commonly return HTTP 403 in a standard DLP tenant even with a valid token. Based on live verification, the following were reachable-but-gated (403) unless the corresponding entitlement/capability is granted:
| Module / operation | Endpoint | Typical result | Why |
|---|---|---|---|
| Resolver — MDE (Misdirected Email) | /v2/apis/resolver/mde/* | 403 | Requires the Misdirected Email add-on entitlement |
| Depot — properties | GET /v2/apis/depot/properties | 403 | Restricted settings surface |
| Landlord — all read endpoints | /v2/apis/landlord/* | 403 | Multi-tenant provisioning; operator-only |
| Registry — tasks | GET /v2/apis/registry/tasks | 403 | Gated even with tenant scope |
| Storage — scan results | GET /v2/apis/storage/scans/results | 403 | Requires a valid scanAgentId + scan entitlement |
A 403 here confirms the module is reachable and the token is valid — you simply need the entitlement/capability granted to your principal.
How Requests Are Built (dispatch convention)
All operations flow through one generic dispatcher (ExecuteOperation →
executeGenericOperation). Understanding how it maps your parameters object onto
the HTTP request is essential for calling any of the 560 operations correctly:
- Path parameters — any
{placeholder}in the operation's path is filled from a same-named parameter. Missing/empty path params raisemissing required path parameter: <name>. Values are URL-path-escaped. Example: path/queries/{entityTypes}consumes theentityTypesparameter. - Body — the single special parameter named
body(a JSON object) becomes the request body. This is where the search DSL and create/update payloads go. The body is only sent for non-GET/non-DELETEmethods. - Everything else → query string, regardless of HTTP method. Paging and
scope options (
limit,offset,entityTypes,scope,fields,sources,scanAgentId, ...) are sent as query params even onPOST. Arrays are expanded into repeated query keys; empty strings are omitted.
Headers set automatically: Authorization: Bearer <token>, Accept: application/json, and Content-Type: application/json when a body is present.
Response envelopes
The platform returns two envelope shapes; the dispatcher normalizes both into a
map[string]interface{}:
- Activity-style: a top-level
dataarray/object. - ObserveIT-style (Classification, Workbench, Registry, Scheduler, ...):
_status(status/code/context) +_meta(stats:total/limit/offset) +data. - A bare JSON array response is wrapped as
{ "data": [...] }. - An empty body (e.g.
DELETE/204) is normalized to{ "success": true }.
The query DSL
Query endpoints (activity.createQuery, workbench ad-hoc queries,
scheduler.createQuery) accept an Elasticsearch-style search DSL in body.
A minimal "match everything" body is:
{ "query": { "match_all": {} } }
Paging (limit, offset) and scope (entityTypes, scope, ...) go in the query
string, not in the body.
For Activity, entityTypes is a path parameter selecting the channel to
query. Allowed values: event, casbevent, audit, network, threat,
isolation, mde.
For Scheduler, entityTypes is a selector with allowed values default
(tasks) or executions.
Supported Resources and Operations
Because the schema is generated from the platform's own OpenAPI specs, each
operation key equals the platform operationId (e.g. getPolicySet,
createQuery). List operations are typically get<Thing>Set; single-item reads are
get<Thing>; mutations are create* / modify* (PATCH) / overwrite* (PUT) /
delete*. Below are representative, verified operations per module. The full set is
in the generated schema.
Activity (/v2/apis/activity)
Query DLP events across every channel and manage incident lifecycle.
| Operation | Method / Path | Description |
|---|---|---|
createQuery | POST /queries/{entityTypes} | Query events for one channel (DSL in body, limit/offset in query) |
createQueryQueries | POST /queries | Query without a channel path param |
modifyEventActionRemediation | PATCH /events/{fqid}/actions/remediation | Apply remediation to an event (mutating) |
modifyEventAnnotationWorkflow | PATCH /events/{fqid}/annotations/workflow | Change incident workflow state (mutating) |
modifyEventTags | PATCH /events/{fqid}/tags | Add/remove tags on an event (mutating) |
createEventAnnotationCommentSet | POST /events/{fqid}/annotations/comments | Add a comment (mutating) |
createFalsePositiveRequest | POST /events/{fqid}/actions/false-positive | Mark false-positive (mutating) |
modifyEventIncientSeverity | PATCH /events/{fqid}/incident/severity | Change incident severity (mutating) |
deleteEventInBulk | POST /actions/bulk-deletion | Bulk-delete events (mutating) |
Entity types (channels): event, casbevent, audit, network, threat,
isolation, mde.
Classification (/v2/apis/classification)
| Operation | Method / Path | Description |
|---|---|---|
getBusinessCategorySet | GET /business-categories | List business categories |
getBusinessCategoryTreeSet | GET /business-category-trees | List category hierarchies |
getClassifierSet | GET /business-categories/classifiers | List classifiers |
getModelSet | GET /models | List ML models |
(124 operations total: seed groups, embeddings, clusters, file-version analysis, classifier reviews/feedback, classification jobs, ...)
Workbench (/v2/apis/workbench)
| Operation | Method / Path | Description |
|---|---|---|
getExplorationSet | GET /explorations | List explorations (saved searches/analytics) |
(21 operations: create/run explorations, subscriptions, ACLs, ad-hoc queries.)
Auth (/v2/apis/auth)
Identity, access, and token issuance. Largest module (197 ops).
| Operation | Method / Path | Description |
|---|---|---|
getTenantSet | GET /tenants | List tenants |
getUserSet | GET /users | List users |
getPolicySet | GET /policies | List authorization policies |
getCapabilitySet | GET /capabilities | List capabilities (granular permissions) |
getPersonaSet | GET /personas | List personas |
getGuestSet | GET /guests | List guests |
requestToken | POST /oauth/token | Mint a Bearer JWT (client-credentials) |
createToken | POST /tokens | Renew the current user token |
getToken | GET /tokens/{jti} | Inspect a token by its jti |
createApplication | POST /clients | Register an OAuth client (application) |
getApplicationSet | GET /clients | List OAuth clients |
checkToken | GET /logins/validation | Check whether the session/token is valid |
Notification (/v2/apis/notification)
| Operation | Method / Path | Description |
|---|---|---|
getTargetGroupSet | GET /target-groups | List recipient target groups |
getTemplateSet | GET /templates | List notification templates |
Resolver (/v2/apis/resolver)
IP geo-location and Misdirected Email (MDE) onboarding/policies. MDE endpoints are entitlement-gated (403 without the add-on).
| Operation | Method / Path | Description |
|---|---|---|
getMdeCategorySet | GET /mde/categories | List Misdirected-Email categories (gated) |
Depot (/v2/apis/depot)
Configuration/settings store.
| Operation | Method / Path | Description |
|---|---|---|
getArticleSet | GET /articles | List articles (versioned settings documents) |
getPredicateSet | GET /predicates | List predicates (reusable detector logic) |
getTagSet | GET /tags | List tags |
getPropertySet | GET /properties | List properties (gated: 403 on standard tenants) |
Landlord (/v2/apis/landlord)
Multi-tenant provisioning (operator-only; typically 403).
| Operation | Method / Path | Description |
|---|---|---|
getResourceGroupSet | GET /resource-groups | List resource groups (gated) |
getDeploymentConfigurationSet | GET /deployment-configurations | List deployment configs (gated) |
Registry (/v2/apis/registry)
DLP policies and rules, configurations, and service instances.
| Operation | Method / Path | Description |
|---|---|---|
getPolicySet | GET /policies | List DLP policies |
getConfigurationSet | GET /configurations | List configurations (policy bindings) |
getInstanceSet | GET /instances | List registered service/agent instances |
getTaskSet | GET /tasks | List registry tasks (gated: 403) |
Storage (/v2/apis/storage)
Object storage in bins and DLP content scans.
| Operation | Method / Path | Description |
|---|---|---|
getConfigurationDlpScanResultSet | GET /scans/results | Aggregated scan results (requires scanAgentId) (gated) |
(7 operations: bin object get/delete, batch object operations, resource object-requests, submit scans, poll scan status.)
Scheduler (/v2/apis/scheduler)
Scheduled tasks and their executions.
| Operation | Method / Path | Description |
|---|---|---|
createQuery | POST /queries | DSL query over the task store; entityTypes = default | executions |
createTask | POST /tasks | Create a task (mutating) |
getTask | GET /tasks/{taskId} | Read a task |
overwriteTask | PUT /tasks/{taskId} | Replace a task (mutating) |
deleteTask | DELETE /tasks/{taskId} | Delete a task (mutating) |
getTaskExecutionsSet | GET /tasks/{taskId}/executions | List task executions |
getTaskExecution | GET /tasks/{taskId}/executions/{taskExecId} | Read one execution |
Examples
All examples use the generic shape: pick a resource (module) and an operation
(operationId), and pass parameters. Remember the dispatch rules — body is the
request body; everything else is a query/path parameter.
Query endpoint DLP events (Activity)
{
"integration_service": "proofpoint-dlp",
"resource": "activity",
"operation": "createQuery",
"parameters": {
"entityTypes": "event",
"limit": 25,
"offset": 0,
"body": {
"query": { "match_all": {} }
}
}
}
entityTypesfills the{entityTypes}path segment (channel).limit/offsetgo on the query string.bodycarries the search DSL. Swapeventforcasbevent,audit,network,threat,isolation, ormdeto query other channels.
List DLP policies (Registry)
{
"integration_service": "proofpoint-dlp",
"resource": "registry",
"operation": "getPolicySet",
"parameters": {}
}
List business categories (Classification)
{
"integration_service": "proofpoint-dlp",
"resource": "classification",
"operation": "getBusinessCategorySet",
"parameters": {}
}
List tenants / users (Auth)
{
"integration_service": "proofpoint-dlp",
"resource": "auth",
"operation": "getUserSet",
"parameters": {}
}
Query scheduled tasks (Scheduler)
{
"integration_service": "proofpoint-dlp",
"resource": "scheduler",
"operation": "createQuery",
"parameters": {
"entityTypes": "default",
"limit": 10,
"body": { "query": { "match_all": {} } }
}
}
Add a comment to an incident (Activity — mutating)
{
"integration_service": "proofpoint-dlp",
"resource": "activity",
"operation": "createEventAnnotationCommentSet",
"parameters": {
"fqid": "{{event_fqid}}",
"body": {
"comment": "Triaged by SOC — confirmed exfiltration attempt, escalating."
}
}
}
fqidfills the{fqid}path segment.- The comment payload goes in
body.
Mint a token via OAuth client credentials (Auth)
{
"integration_service": "proofpoint-dlp",
"resource": "auth",
"operation": "requestToken",
"parameters": {
"body": {
"grant_type": "client_credentials",
"client_id": "{{oauth_client_id}}",
"client_secret": "{{oauth_client_secret}}"
}
}
}
Use the returned JWT to update the credential's
apiToken. Exact body fields depend on your OAuth client configuration in the Auth module.
Token Expiry & Rotation
The Bearer JWT is short-lived (typically ~8 hours, per the exp claim). How
rotation is handled depends on the credential mode:
- OAuth2 Client Credentials mode — automatic. The integration caches the minted
access token and refreshes it transparently shortly before expiry. It computes the
refresh time from the token's
expclaim (or anexpires_infield if returned), minus a 60-second safety buffer. You do nothing; there is no manual rotation as long as theclientId/clientSecretremain valid. - Pre-issued Bearer Token mode — manual. The integration does not refresh a
supplied
apiToken. Expect HTTP 401 (it:error:authentication) once it passesexp. Rotate by minting a fresh token (auth.requestToken, orauth.createToken) and updating the credential'sapiToken. For unattended workflows, prefer OAuth2 mode, or run a scheduled step that mints and stores a new token before expiry.
ValidateCredentials / Test Connection only fails on 401 (or, in OAuth2 mode, if
the token endpoint rejects the client credentials), so it is a reliable "are my
credentials still alive?" check.
Troubleshooting
| Issue | Cause & resolution |
|---|---|
invalid or expired token (status 401) on Test Connection | Token is invalid/expired (it:error:authentication). In Bearer mode, mint a fresh JWT and update apiToken. In OAuth2 mode, the minted token was rejected — check clientId/clientSecret. |
OAuth token error [401]: ... | The token endpoint rejected the client credentials (OAuth2 mode). Verify clientId/clientSecret and that the Client Application is active and assigned the needed capabilities. |
OAuth token error [400]: ... | Malformed token request (OAuth2 mode) — usually an invalid scope or grant_type rejection. Default scope is *. |
either apiToken or clientId + clientSecret is required | The credential has neither auth mode configured. Provide apiToken, or both clientId and clientSecret. |
API error [401]: ... it:error:authentication | Same as above, on a specific call. Rotate the token. |
API error [403]: ... it:error:authorization | Token is valid but lacks permission/entitlement for that module/operation. Grant the needed capability/policy to the principal, or confirm the add-on (e.g. Misdirected Email) is licensed. The token itself is fine. |
missing required path parameter: <name> | You omitted a {placeholder} path value. Provide it as a top-level parameter (e.g. entityTypes, fqid, taskId, id). |
unsupported resource: <x> / unsupported operation: <r>.<o> | The resource/operation key is wrong. Resource = module name (activity, registry, ...); operation = the platform operationId (getPolicySet, createQuery, ...). |
| Query returns few/no records | Check entityTypes (Activity channels differ in volume; e.g. audit/casbevent are high-volume, isolation/mde may be empty). Confirm body DSL and limit/offset. |
API error [400]: ... it:error:arguments | A required query/body field is missing or an enum value is invalid (e.g. wrong entityTypes). Check the operation's allowed values. |
| Empty body but success | DELETE/204 responses normalize to { "success": true }. Check for that key downstream. |
| Wrong region / connection issues | Set baseUrl to your tenant's regional pod host. The default is US-East. |
Error format
Non-2xx responses surface as API error [<status>]: <raw platform body>. The raw
body includes the platform code (e.g. it:error:authentication,
it:error:authorization, it:error:arguments) and a context with
transactionId/correlationId/incidentId useful for Proofpoint support.
Best Practices
- Use a dedicated OAuth client for automation. Register a purpose-built client
via
auth.createApplicationand scope its assignments to only the capabilities your workflows need. Don't reuse a human user's token. - Automate token rotation. Tokens expire in hours. Build a refresh step
(
auth.requestToken) that runs ahead ofexpand updates the credential. - Treat 403 as "grant a capability", not "bad token". Diagnose entitlement gaps
in the Auth module (
getCapabilitySet/getPolicySet) rather than re-issuing tokens. - Query the right channel. In Activity, pick
entityTypesdeliberately —event(endpoint),casbevent(CASB),audit,network,threat,isolation,mde(Misdirected Email). Volume varies enormously by channel. - Page large result sets with
limit/offset(query string) instead of one large pull. - Keep search logic in
body, options in parameters. The DSL (query, filters, sort, aggregations) belongs inbody; paging/scope belong as top-level parameters (query string). - Set
baseUrlexplicitly for non-US-East tenants to avoid cross-region calls.
Security Considerations
- Protect the JWT. The
apiTokenis a bearer credential — anyone holding it can act as the bound principal untilexp. Store it only in the credential manager; never place it in workflow parameters, logs, comments, or source control. - Prefer short-lived tokens + rotation over long-lived credentials. The
platform's short
expis a feature; lean into it. - Least privilege. Scope the OAuth client/principal to the minimum capabilities required. Read-only workflows should not hold mutation capabilities.
- Rotate immediately on exposure. If a token is leaked, revoke/rotate the
issuing OAuth client and mint a new token. Because tokens carry
jti, they can be tracked/inspected viaauth.getToken. - Guard mutating operations. Activity remediation, incident workflow changes,
bulk deletion, task create/delete, and any Auth writes have real operational
impact — gate them behind approvals and log the
transactionIdreturned by the platform for auditability.
Appendix — Module / Operation Reference
- Resource key = platform module:
activity,classification,workbench,auth,notification,resolver,depot,landlord,registry,storage,scheduler. - Operation key = platform
operationId(e.g.getPolicySet,createQuery,modifyEventTags). - HTTP method & path for every operation are defined in the generated schema
(
internal/integrations/proofpoint-dlp/schema.go). The schema is regenerated from the platform's OpenAPI specs — do not hand-edit operations.
Totals: 11 modules, 560 operations. Live verification (standard tenant): read
endpoints on Activity, Classification, Workbench, Auth, Notification, Depot, and
Registry returned 200 with data; Resolver-MDE, Depot-properties, Landlord,
Registry-tasks, and Storage-scans returned 403 (reachable, valid token, missing
entitlement); Scheduler task query returned 200.
Updated: 2026-07-20