Summary and recommendation
Pendo exposes two distinct API surfaces that serve different purposes and must not be conflated. The REST API at `https://app.pendo.io/api/v1` manages product visitor metadata and analytics data - it does not manage Pendo application (admin/team) users.
The SCIM 2.0 endpoint at `https://app.pendo.io/scim/v2` manages Pendo team users and requires both SSO and a Premium-tier subscription or SCIM add-on as hard prerequisites. Authentication for the REST API uses a static Integration Key passed as `x-pendo-integration-key`; SCIM uses a separate bearer token generated in Settings > Integrations > SCIM.
Integration keys do not expire by default and have no OAuth refresh flow, so rotation policy must be enforced manually.
API quick reference
| Has user API | Yes |
| Auth method | API Key (Integration Key) passed as HTTP header `x-pendo-integration-key` |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Premium (Pro tier or as add-on); SSO must be configured as a prerequisite |
Authentication
Auth method: API Key (Integration Key) passed as HTTP header x-pendo-integration-key
Setup steps
- Log in to Pendo as an Admin.
- Navigate to Settings > Integrations > Integration Keys.
- Click 'Add Integration Key', name it, and select the appropriate permissions (read, write).
- Copy the generated key; it is shown only once.
- Include the key in all API requests as the header:
x-pendo-integration-key: <YOUR_KEY>.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| read | Allows GET operations on visitors, accounts, metadata, and reports. | Listing and retrieving visitor/user records |
| write | Allows POST/PUT/DELETE operations on visitor and account metadata. | Creating, updating, or deleting visitor metadata |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| visitorId | string | Unique identifier for the visitor (maps to your internal user ID). | required | immutable | Set by the Pendo snippet install_type or via API; must match the ID used in the snippet. |
| accountId | string | ID of the account (organization) the visitor belongs to. | optional | optional | Links visitor to an account object. |
| metadata.auto.email | string | Visitor email address, stored under auto metadata group. | optional | optional | Auto metadata is set by the Pendo snippet; can be overridden via API. |
| metadata.auto.firstName | string | Visitor first name. | optional | optional | |
| metadata.auto.lastName | string | Visitor last name. | optional | optional | |
| metadata.auto.role | string | Visitor role within their organization. | optional | optional | |
| metadata.auto.lastvisit | number (epoch ms) | Timestamp of the visitor's last session. | system-set | system-set | Read-only; managed by Pendo. |
| metadata.auto.firstvisit | number (epoch ms) | Timestamp of the visitor's first session. | system-set | system-set | Read-only; managed by Pendo. |
| metadata.custom. |
string | number | boolean | Custom metadata fields defined in Pendo Data Mappings. | optional | optional | Custom fields must be pre-defined in Pendo UI under Data > Visitor Metadata before they can be written via API. |
| id | string | Internal Pendo visitor record ID (same as visitorId in most contexts). | system-set | immutable |
Core endpoints
Get a single visitor
- Method: GET
- URL:
https://app.pendo.io/api/v1/visitor/{visitorId} - Watch out for: Returns 404 if the visitor has never been seen by the Pendo snippet and has not been created via API.
Request example
GET /api/v1/visitor/user-123
Headers:
x-pendo-integration-key: <KEY>
content-type: application/json
Response example
{
"visitorId": "user-123",
"accountId": "acct-456",
"metadata": {
"auto": { "email": "user@example.com" },
"custom": { "plan": "pro" }
}
}
List all visitors (aggregation)
- Method: POST
- URL:
https://app.pendo.io/api/v1/aggregation - Watch out for: The aggregation pipeline is the primary way to query/filter visitors at scale. Direct list endpoints are limited. Large result sets may require pipeline-level filtering.
Request example
POST /api/v1/aggregation
Headers:
x-pendo-integration-key: <KEY>
Body:
{
"response": {"mimeType": "application/json"},
"request": {"pipeline": [{"source": {"visitors": null}}]}
}
Response example
{
"results": [
{"visitorId": "user-123", "accountId": "acct-456"},
{"visitorId": "user-789", "accountId": "acct-456"}
]
}
Update visitor metadata (single)
- Method: PUT
- URL:
https://app.pendo.io/api/v1/metadata/visitor/{visitorId} - Watch out for: Only custom metadata fields can be written via this endpoint. Auto fields (email, name) set by the snippet may be overwritten on next page load if the snippet sends different values.
Request example
PUT /api/v1/metadata/visitor/user-123
Headers:
x-pendo-integration-key: <KEY>
Body:
{
"custom": { "plan": "enterprise" }
}
Response example
HTTP 200 OK
{
"visitorId": "user-123",
"custom": { "plan": "enterprise" }
}
Bulk update visitor metadata
- Method: POST
- URL:
https://app.pendo.io/api/v1/metadata/visitor/bulk - Watch out for: Recommended over individual updates to avoid rate limiting. Maximum batch size is not publicly documented; Pendo recommends keeping batches under 1,000 records.
Request example
POST /api/v1/metadata/visitor/bulk
Headers:
x-pendo-integration-key: <KEY>
Body:
[
{"visitorId": "user-123", "custom": {"plan": "pro"}},
{"visitorId": "user-456", "custom": {"plan": "free"}}
]
Response example
HTTP 200 OK
{
"total": 2,
"failed": 0
}
Delete a visitor
- Method: DELETE
- URL:
https://app.pendo.io/api/v1/visitor/{visitorId} - Watch out for: Deleting a visitor removes their metadata and event history from Pendo. This action is irreversible. The visitor will be re-created if they trigger a new Pendo snippet event.
Request example
DELETE /api/v1/visitor/user-123
Headers:
x-pendo-integration-key: <KEY>
Response example
HTTP 200 OK
{}
Get a single account
- Method: GET
- URL:
https://app.pendo.io/api/v1/account/{accountId} - Watch out for: Account objects are separate from visitor objects. Visitor-to-account association is set via accountId on the visitor.
Request example
GET /api/v1/account/acct-456
Headers:
x-pendo-integration-key: <KEY>
Response example
{
"accountId": "acct-456",
"metadata": {
"auto": { "name": "Acme Corp" },
"custom": { "tier": "enterprise" }
}
}
Bulk update account metadata
- Method: POST
- URL:
https://app.pendo.io/api/v1/metadata/account/bulk - Watch out for: Same batch-size caveats as visitor bulk endpoint apply.
Request example
POST /api/v1/metadata/account/bulk
Headers:
x-pendo-integration-key: <KEY>
Body:
[
{"accountId": "acct-456", "custom": {"tier": "enterprise"}}
]
Response example
HTTP 200 OK
{
"total": 1,
"failed": 0
}
List Pendo application users (admin users, not visitors)
- Method: GET
- URL:
https://app.pendo.io/api/v1/user - Watch out for: This endpoint manages Pendo application (team) users, not product visitors. Requires a write-scoped integration key with admin privileges. Documented behavior may vary by plan.
Request example
GET /api/v1/user
Headers:
x-pendo-integration-key: <KEY>
Response example
[
{
"id": "admin-001",
"username": "admin@example.com",
"role": "admin"
}
]
Rate limits, pagination, and events
- Rate limits: Pendo enforces rate limits on the REST API but does not publish exact numeric thresholds in public documentation. Limits are applied per integration key.
- Rate-limit headers: Unknown
- Retry-After header: Unknown
- Rate-limit notes: HTTP 429 is returned when limits are exceeded. Pendo recommends batching metadata updates using the bulk endpoint rather than individual calls to avoid throttling.
- Pagination method: none
- Default page size: 0
- Max page size: 0
- Pagination pointer: Not documented
| Plan | Limit | Concurrent |
|---|---|---|
| All plans | Not publicly documented; contact Pendo support for specifics | 0 |
- Webhooks available: No
- Webhook notes: Pendo does not offer native outbound webhooks for visitor/user events as of the last verified documentation review. Event data is consumed via the aggregation API or data sync integrations.
- Alternative event strategy: Use the Pendo aggregation API to poll for visitor events, or configure a Pendo Data Sync (ETL export) to push data to a data warehouse. Pendo also supports integrations via Segment, Salesforce, and Zapier for event forwarding.
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Premium (Pro tier or as add-on); SSO must be configured as a prerequisite
Endpoint: https://app.pendo.io/scim/v2
Supported operations: GET /Users – list provisioned users, GET /Users/{id} – retrieve a single user, POST /Users – provision a new user, PUT /Users/{id} – replace user attributes, PATCH /Users/{id} – update user attributes (activate/deactivate), DELETE /Users/{id} – deprovision a user, GET /Groups – list groups, POST /Groups – create group, PATCH /Groups/{id} – update group membership, DELETE /Groups/{id} – delete group
Limitations:
- SSO (SAML or OIDC) must be enabled before SCIM can be configured.
- No JIT (Just-in-Time) provisioning; users must be provisioned via SCIM or manually.
- SCIM manages Pendo application (team/admin) users, not product visitor records.
- Available on Premium tier or as a paid add-on; not included in Base plan.
- Supported IdPs include Okta, Microsoft Entra ID (Azure AD), and OneLogin; Google Workspace is not officially supported.
- Group push maps to Pendo user roles/groups, not visitor segments.
Common scenarios
Three integration patterns cover the majority of programmatic use cases. For identity graph enrichment - syncing CRM or IdP attributes into Pendo visitor records - use POST /api/v1/metadata/visitor/bulk on a scheduled basis, with custom metadata fields pre-defined in the Pendo UI under Data > Visitor Metadata.
writing to undefined fields fails silently or returns an error. For team user provisioning, SCIM via Okta, Entra ID, or OneLogin is the supported path; Google Workspace is not officially supported, and SCIM deprovisioning deactivates the Pendo login but does not purge visitor event history.
For querying visitors at scale, the aggregation pipeline (POST /api/v1/aggregation) is the only reliable mechanism - there is no paginated GET /visitors list endpoint, and very large exports should use Pendo Data Sync rather than the REST API.
Sync CRM user attributes to Pendo visitor metadata
- Generate a write-scoped Integration Key in Pendo Settings > Integrations.
- Pre-define any custom metadata fields (e.g., 'plan', 'mrr') in Pendo UI under Data > Visitor Metadata.
- On a nightly schedule, extract updated user records from your CRM.
- Batch records into groups and POST to https://app.pendo.io/api/v1/metadata/visitor/bulk with visitorId matching your internal user ID.
- Log HTTP 200 responses and retry any failed records with exponential backoff on HTTP 429.
Watch out for: If the Pendo snippet is also sending auto metadata (email, name), those values will overwrite API-set auto fields on each page load. Use custom metadata fields for CRM-sourced attributes to avoid conflicts.
Provision Pendo team users via SCIM from Okta
- Ensure SSO (SAML) is configured and active in Pendo for your organization.
- Confirm your Pendo subscription includes the Premium tier or SCIM add-on.
- In Pendo Settings > Integrations > SCIM, generate a SCIM bearer token.
- In Okta, add the Pendo SCIM application and configure the SCIM base URL (https://app.pendo.io/scim/v2) and bearer token.
- Map Okta user attributes to SCIM attributes (userName → email, etc.).
- Assign users/groups in Okta to trigger provisioning; verify users appear in Pendo Settings > Team.
Watch out for: SCIM provisions Pendo application (admin/team) users only, not product visitor records. Deprovisioning via SCIM deactivates the user's Pendo login but does not delete their visitor event history.
Query and export all visitors with a specific metadata attribute
- Use the aggregation API: POST https://app.pendo.io/api/v1/aggregation.
- Construct a pipeline with a source of 'visitors' and a filter stage matching the custom metadata field (e.g., custom.plan == 'enterprise').
- Parse the results array from the response.
- If result set is large, add pipeline-level limit/offset or use Pendo Data Sync for full exports.
Watch out for: There is no simple paginated GET endpoint for visitors. The aggregation pipeline is the correct approach but has undocumented result-size limits for very large datasets; Pendo Data Sync is recommended for full data exports.
Why building this yourself is a trap
The most common integration mistake is treating auto metadata fields (email, name, set by the Pendo JavaScript snippet) as writable via the REST API. The snippet overwrites API-set auto fields on every page load, making those values unreliable for any downstream identity graph or segmentation logic. Use only metadata.custom.<field_name> fields for API-sourced attributes.
A second trap: rate limit thresholds are not publicly documented, HTTP 429 is the only signal, and there are no rate-limit headers in responses - implement exponential backoff and prefer bulk endpoints over per-record calls.
Finally, deleting a visitor via DELETE /api/v1/visitor/{visitorId} is irreversible and removes all associated event history; the visitor record is recreated automatically if the snippet fires again for that visitorId, which can corrupt longitudinal analytics.
Automate Pendo workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.