Keap · Authentication Profile
Keap Authentication
Authentication
Keap declares 4 security scheme(s) across its OpenAPI definitions.
CRMSalesMarketing AutomationSmall BusinessE-CommerceContactsEmail MarketingSubscriptionAffiliate ManagementWebhookMCPPayments
Methods:
Schemes: 4
OAuth flows:
API key in:
Security Schemes
oauth2 oauth2
· flows: authorizationCode, refreshToken
personal_access_token http
scheme: bearer
service_account_key http
scheme: bearer
legacy_api_key apiKey
Source
Authentication Profile
generated: '2026-08-13'
method: searched
source: >-
https://developer.infusionsoft.com/getting-started-oauth-keys/ +
https://developer.infusionsoft.com/authentication/ +
https://developer.infusionsoft.com/pat-and-sak/ +
https://developer.infusionsoft.com/legacy-key-deprecation/ +
openapi/_original/keap-v2-openapi.json +
well-known/keap-oauth-authorization-server-mcp.json
docs: https://developer.infusionsoft.com/getting-started-oauth-keys/
summary: >-
Keap supports three live credential types against one bearer-token contract, plus a
fourth being retired. The OpenAPI declares only oauth2/authorizationCode, so the spec
alone under-describes the surface: Personal Access Tokens and Service Account Keys
are equally valid on every REST operation and are how most scripting integrations
actually authenticate. The MCP server at api.keap.com/mcp uses a SEPARATE, more
modern authorization stack — OAuth 2.1 with PKCE and dynamic client registration
against login.labs.thryv.com — and does not share the REST authorization server.
summary_types:
types: [oauth2, bearer-token]
oauth2_flows: [authorizationCode, refreshToken]
scopes: 1
mfa: n/a
schemes:
- name: oauth2
type: oauth2
declared_in_spec: true
flows:
- flow: authorizationCode
authorizationUrl: https://accounts.infusionsoft.com/app/oauth/authorize
tokenUrl: https://api.infusionsoft.com/token
scopes:
full: Full access to the Keap CRM REST API. The only scope Keap accepts.
- flow: refreshToken
tokenUrl: https://api.infusionsoft.com/token
note: >-
Documented but not declared in the spec. Requires HTTP Basic on the token
endpoint: `Authorization: Basic base64(client_id:client_secret)`.
request_parameters:
authorize: [client_id, redirect_uri, response_type=code, scope=full]
token: [client_id, client_secret, code, grant_type=authorization_code, redirect_uri]
refresh: [grant_type=refresh_token, refresh_token]
token_placement: 'Authorization: Bearer <access_token>'
redirect_uri_requirements: Must be HTTPS. Keap will not redirect to any other URL during the flow.
refresh_token_rotation: true
refresh_token_rotation_note: >-
CRITICAL AND EASY TO GET WRONG — every refresh returns a NEW refresh token as
well as a new access token. The old refresh token is spent. If the new one is not
persisted the integration is locked out and needs re-authorization by the user.
credentials_issued_at: https://keys.developer.keap.com/my-apps
- name: personal_access_token
type: http
scheme: bearer
declared_in_spec: false
token_placement: 'Authorization: Bearer <token>'
identity: Acts as the user who created it, inheriting that user's visibility and edit permissions.
scope: A single authorized Keap application.
created_by: Any app user, from Settings → API Settings.
docs: https://developer.infusionsoft.com/pat-and-sak/
note: >-
Keap's Postman quick-start page documents an alternate header,
`X-Keap-API-Key: <token>`, for the same credential. The two Keap pages
disagree; the Bearer form is what the OpenAPI declares.
- name: service_account_key
type: http
scheme: bearer
declared_in_spec: false
token_placement: 'Authorization: Bearer <token>'
identity: Admin access to all stored data in the application.
scope: A single authorized Keap application.
created_by: Admins only.
docs: https://developer.infusionsoft.com/pat-and-sak/
note: >-
Shown in full exactly once at creation. Revocation from the API Settings screen
can take several minutes to propagate through the gateway.
- name: legacy_api_key
type: apiKey
status: deprecating
declared_in_spec: false
surface: XML-RPC only
token_placement: 'Authorization: Bearer <legacy_key>'
base_url: https://api.infusionsoft.com/crm/xmlrpc
docs: https://developer.infusionsoft.com/legacy-key-deprecation/
migration: https://developer.infusionsoft.com/legacy-key-migration/
note: >-
Keap runs periodic brownouts against Legacy Keys and plans to deactivate all of
them. Replace with a Service Account Key.
mcp_authorization:
applies_to: https://api.keap.com/mcp
separate_from_rest: true
issuer: https://login.labs.thryv.com
authorization_endpoint: https://login.labs.thryv.com/authorize
token_endpoint: https://login.labs.thryv.com/oauth/token
registration_endpoint: https://api.keap.com/mcp/auth/register
dynamic_client_registration: true
pkce: S256
grant_types: [authorization_code, refresh_token]
scopes_supported: [offline_access]
public_clients: true
metadata:
- well-known/keap-oauth-protected-resource-mcp.json
- well-known/keap-oauth-authorization-server-mcp.json
gateway_behaviour:
note: >-
Auth failures rejected at the Apigee gateway return a different envelope from the
API's own errors — observed live:
{"fault":{"faultstring":"Invalid access token","detail":{"errorcode":"oauth.v2.InvalidAccessToken"}}}.
Clients must handle both.
gaps:
- The OpenAPI declares only oauth2; PAT/SAK are undeclared despite being fully supported.
- Only one scope (`full`) exists, so least-privilege delegation is not possible on the REST API.
- Two Keap pages disagree on the PAT/SAK header (Authorization: Bearer vs X-Keap-API-Key).
- No OpenID Connect; /.well-known/openid-configuration 404s on every host.