Penneo OAuth API
The OAuth API from Penneo — 3 operation(s) for oauth.
The OAuth API from Penneo — 3 operation(s) for oauth.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/penneo:penneo-oauth-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Penneo Authentication OAuth API
version: v1
description: 'This page allows you to see the requests, parameters, and responses available from our API.
You will need an account to use these endpoints, you can get a trial account by visiting penneo.com.
Please also read the documentation before you begin.'
contact:
name: Penneo Support
url: https://www.support.penneo.com
servers:
- url: https://login-sandbox.penneo.com/
description: Sandbox server (uses your test data)
- url: https://login.penneo.com/
description: Production server (uses your live data)
tags:
- name: OAuth
paths:
/oauth/authorize:
get:
summary: Authenticate a user with Penneo
description: 'The browser will redirect the user to the Penneo Login page and, after a successful login, back to the
specified `redirect_uri`.
A `code` parameter will be attached to the request so it can be later exchanged for an `access_token`.'
tags:
- OAuth
operationId: authorizeUser
parameters:
- name: response_type
in: query
required: true
schema:
type: string
enum:
- code
- name: redirect_uri
in: query
required: true
schema:
type: string
format: uri
example: https://your.domain/callback
description: 'The URL to which Penneo will redirect the browser after authorization has been granted by the user.<br>
It must be first registered in the client configuration.
'
- name: client_id
in: query
required: true
schema:
type: string
description: The alphanumeric `client_id` obtained after registering your client application.
- name: code_challenge
in: query
required: false
schema:
type: string
description: 'Value derived from code verifier created in compliance with PKCE specification.<br>
See [RFC 7636](https://www.rfc-editor.org/rfc/rfc7636) for more info.<br>
**Required if the client is configured to require PKCE**, otherwise optional but strongly recommended
for enhanced security. If provided, you must also include `code_verifier` when exchanging the
authorization code for tokens.
'
- name: code_challenge_method
in: query
required: false
schema:
type: string
enum:
- plain
- S256
default: plain
description: 'Name of the algorithm used to calculate `code_challenge`. <br>
Required only if `code_challenge` is provided.<br>
Clients are **strongly recommended** to use `S256`, as it will not only preventing
[CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) but also mitigate
[eavesdropping](https://en.wikipedia.org/wiki/Network_eavesdropping) and
[man-in-the-middle](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) attacks.
'
- name: state
in: query
required: false
schema:
type: string
description: 'An opaque value of your choice that will be included when redirecting back to your client application.<br>
This value is not required but **strongly recommended** to improve security and to prevent
[CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) attacks.<br> See [RFC-6749, Section
10.12](https://www.rfc-editor.org/rfc/rfc6749#section-10.12) for more info.
'
responses:
'302':
description: Found
headers:
Location:
schema:
format: uri
type: string
description: 'Redirect to the specified redirect_uri with a `code` and `scope` parameters attached to the query
'
example: '''https://your.domain/callback?state=<your state value>&code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...''
'
'400':
description: Bad Request
content:
text/html:
schema:
type: string
example: Missing required parameter
'403':
description: Unauthorized
content:
text/html:
schema:
type: string
example: Unauthorized client
'500':
description: Internal Server Error
content:
text/html:
schema:
type: string
example: Redirect URI does not match any of those defined for the client
'501':
description: Not Implemented
content:
text/html:
schema:
type: string
example: Unsupported response type
/oauth/revoke:
post:
summary: Revoke a refresh_token
description: 'Revokes a `refresh_token` (RFC 7009). The confidential client must authenticate with
`client_id` and `client_secret` in the body or via `Authorization: Basic` (RFC 6749 §2.3.1).
The token is removed only if it was issued to that client; otherwise the response is still 200.'
tags:
- OAuth
operationId: revokeRefreshToken
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
token:
type: string
client_id:
type: string
description: May be sent in the body or using an HTTP Basic Authorization header (RFC 6749).
client_secret:
type: string
description: May be sent in the body or using an HTTP Basic Authorization header (RFC 6749).
required:
- token
- client_id
- client_secret
responses:
'200':
description: OK | The refresh token is revoked, invalid, doesn't exist or was not issued for the client.
'400':
description: Bad Request | Missing required parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: invalid_request
error_description: Invalid request
'401':
description: Unauthorized | Invalid client credentials
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: invalid_client
error_description: Invalid client ID or secret
'500':
$ref: '#/components/responses/InternalServerError'
/oauth/token:
post:
summary: Obtain or refresh an access_token
description: Obtain a new `access_token` by exchanging an authorization `code`, a `refresh_token` or `api_keys`.
tags:
- OAuth
operationId: exchangeToken
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
grant_type:
type: string
enum:
- authorization_code
- refresh_token
- api_keys
redirect_uri:
type: string
format: uri
example: https://your.domain/callback
description: 'Required only if using the Authorization Code grant.
The registered callback URI.<br>
It''s the same URI used in the `POST /oauth/authorize` request.
'
refresh_token:
type: string
description: 'Required only if using the Refresh Token Grant.<br>
Use the value of the previously stored `refresh_token`.
'
client_id:
type: string
description: 'The alphanumeric `client_id` (may be sent in the body or via `Authorization: Basic`).
'
client_secret:
type: string
description: 'The alphanumeric `client_secret` (may be sent in the body or via `Authorization: Basic`).
'
scope:
type: string
description: 'A list of space-separated scopes that your application will have access to on behalf of the user.
'
code:
type: string
description: 'Required only if using the Authorization Code Grant.<br>
Use the value of the `code` parameter attached to callback request.
'
code_verifier:
type: string
description: 'Required only for Authorization Code Grant when PKCE is used.<br>
If `code_challenge` was provided in the `/oauth/authorize` request, you must include
the original `code_verifier` value here. If PKCE was not used (no `code_challenge` in
the authorization request), this parameter should be omitted.
'
key:
type: string
description: 'Required only for the `api_keys` grant.<br>
API Key generated in Penneo user settings.
'
digest:
type: string
description: 'Required only for the `api_keys` grant.<br>
Concatenation of the raw nonce, timestamp, and API secret, then *SHA-1 hashed*, and finally
*Base64-encoded*. The nonce, while sent as a Base64-encoded string, is used in its raw form to
generate this digest.
'
nonce:
type: string
description: 'Required only for the `api_keys` grant. Used to generate the `digest` parameter.<br>
A randomly generated string, no longer than 64 characters. It should be sent *Base64-encoded*.
'
created_at:
type: string
description: 'Required only for the `api_keys` grant. Used to generate the `digest` parameter.<br>
Current date and time in UTC or including timezone. Most standard formats are supported.
A maximum clock skew of up to 60 seconds is allowed (in plus or minus).
'
required:
- grant_type
description: 'Include `client_id` and `client_secret` in the body, **or** authenticate the client with
`Authorization: Basic` (Base64 of `client_id:client_secret`) per RFC 6749 §2.3.1.
'
examples:
code:
summary: Authorization Code Grant (with PKCE)
description: 'Example using PKCE. If you did not use `code_challenge` in the authorization request,
omit the `code_verifier` parameter.
'
value:
grant_type: authorization_code
code: string
redirect_uri: https://your.domain/callback
client_id: string
client_secret: string
code_verifier: string
codeWithoutPKCE:
summary: Authorization Code Grant (without PKCE)
description: 'Example without PKCE. Use this if you did not provide `code_challenge` in the authorization request.
'
value:
grant_type: authorization_code
code: string
redirect_uri: https://your.domain/callback
client_id: string
client_secret: string
refresh_token:
summary: Refresh Token Grant
value:
grant_type: refresh_token
refresh_token: string
redirect_uri: https://your.domain/callback
client_id: string
client_secret: string
api_keys:
summary: Api Keys Grant
description: 'This is a custom grant type, meant to exchange API keys for an access token for programmatic access.
Beware that this grant type does not issue refresh tokens. If your token has expired you will have to
use the `api_keys` again to obtain a new one.
'
value:
grant_type: api_keys
scope: read
key: paadeeesmmmdda
client_id: d7898z66d91a56e6ee39d
client_secret: taadtaadpstcsm
digest: quR/EWLAV4xLf9Zqyw4pDmfV9OY=
nonce: d36e316282959a9ed4c89851497a717f
timestamp: '2003-12-15T14:43:07Z'
responses:
'200':
description: OK
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Token'
- $ref: '#/components/schemas/TokenWithoutRefreshToken'
examples:
withRefreshToken:
summary: Access token and refresh token, which can be used to request a new access token.
value:
access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
access_token_expires_at: 1697703152
expires_at: '1234567890'
refresh_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
refresh_token_expires_at: 1698703152
token_type: bearer
withoutRefreshToken:
summary: api_keys grant
description: "The response for the `api_keys` grant does not include a refresh token. If your token has expired\n you will have to use the `api_keys` again to obtain a new one.\n"
value:
access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
access_token_expires_at: 1697703152
expires_at: '1234567890'
token_type: bearer
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Invalid authorization code:
value:
error: invalid_grant
error_description: Invalid Authorization Code
Invalid redirect URI:
value:
error: invalid_grant
error_description: Redirect URI does not match
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
Invalid Client ID or Secret:
value:
error: invalid_client
error_description: Invalid client ID or secret
Invalid Client ID:
value:
error: invalid_client
error_description: Client ID does not match
Invalid refresh token:
value:
error: invalid_token
error_description: Invalid refresh token
Expired refresh token:
value:
error: invalid_token
error_description: Refresh token expired
Missing code verifier (when PKCE was used):
value:
error: invalid_grant
error_description: Missing PKCE code verifier
Invalid code verifier:
value:
error: invalid_grant
error_description: Invalid PKCE code verifier
Code verifier provided but no challenge was used:
value:
error: invalid_grant
error_description: PKCE code verifier provided but no code challenge was used
'500':
$ref: '#/components/responses/InternalServerError'
components:
schemas:
Error:
type: object
properties:
error:
type: string
code:
type: integer
details:
type: array
items:
type: object
Token:
type: object
allOf:
- $ref: '#/components/schemas/TokenWithoutRefreshToken'
- type: object
properties:
refresh_token:
type: string
refresh_token_expires_at:
type: number
format: unix timestamp
TokenWithoutRefreshToken:
type: object
properties:
access_token:
type: string
access_token_expires_at:
type: number
format: unix timestamp
expires_in:
type: string
token_type:
type: string
responses:
InternalServerError:
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Unexpected server error occurred. If problem persists please contact the administrator.
code: 500
externalDocs:
url: https://penneo.readme.io/docs/
description: Penneo API documentation
x-provenance:
method: searched
source: https://developer.penneo.com/reference
harvested: '2026-10-27'
tool: harvest-readme-openapi.py
note: Assembled verbatim from the OpenAPI definition ReadMe embeds in each operation page of the provider's developer portal; paths and components merged by API title, nothing authored.
assembled_from:
- https://developer.penneo.com/reference/get-version.md
- https://developer.penneo.com/reference/oauth-authenticate-user.md
- https://developer.penneo.com/reference/oauth-refresh-token.md
- https://developer.penneo.com/reference/oauth-revoke-refresh-token.md
merge:
pages: 4
deduped: 4
conflicts_kept_first: 0