Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Assinafy Com Br OAuth API
version: 1.0.0
description: 'Operations tagged OAuth across 2 of this provider''s published API definitions: assinafy-com-br-openapi.json, assinafy-com-br-openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.assinafy.com.br
description: Production
- url: https://sandbox.assinafy.com.br
description: Sandbox
tags:
- name: OAuth
description: 'The token, revocation and userinfo endpoints an OAuth application calls, and this API''s protected-resource metadata. New to OAuth with Assinafy? Read **OAuth Integration Guide** first. The authorization server''s own metadata is served at `https://auth.assinafy.com.br/.well-known/oauth-authorization-server`, not on this API: read endpoint URLs from it instead of hardcoding them.'
paths:
/v1/oauth/token:
post:
tags:
- OAuth
summary: Exchange a code, refresh token, or subject token for an access token
description: 'Implements the RFC 6749 §5.1/§5.2 token-endpoint body contract in
* both directions: a successful exchange returns a flat JSON object with
* `access_token` at the top level, and a failure returns a flat
* `{error, error_description}` object — neither is wrapped in this API''s
* usual response envelope, since no standard OAuth client library (or MCP
* connector) would find `access_token` or `error` inside a `data` key.
*
* The third grant, `urn:ietf:params:oauth:grant-type:token-exchange` (RFC 8693),
* is restricted to a confidential internal-service client (see `/oauth/introspect`)
* and trades a front-end resource''s access token (the `subject_token`) for one
* minted for THIS API — the crossing an MCP server makes after a user consents,
* since its own token can never be forwarded here directly. The issued token is
* never wider than the subject: `scope`, when sent, must be a subset of the
* subject''s own scopes, and `resource` must equal this API''s own resource
* identifier exactly. No refresh token is issued; the caller re-exchanges from
* the user''s own token instead of holding unattended API access.
Copy as Markdown Open in ChatGPT Open in Claude'
operationId: b214b71efe5b11ac52d79597108ab2ba
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/OAuthTokenRequest'
application/json:
schema:
$ref: '#/components/schemas/OAuthTokenRequest'
responses:
'200':
description: The token response
content:
application/json:
schema:
properties:
access_token:
type: string
issued_token_type:
description: Present only for the token-exchange grant, per RFC 8693 §2.2.1.
type: string
example: urn:ietf:params:oauth:token-type:access_token
token_type:
type: string
example: Bearer
expires_in:
description: For the token-exchange grant, clamped to the subject token's own remaining lifetime as well as the exchanged-token TTL — never longer than either.
type: integer
example: 3600
refresh_token:
description: Present only when the `offline_access` scope was requested AND consented on the authorization_code/refresh_token grants. Never present for the token-exchange grant. Without it a client must send the user through the authorization flow again once the access token expires.
type:
- string
- 'null'
scope:
description: The scope of the ACCESS token. `offline_access` is a request-time signal rather than a permission, so it never appears here even when it was requested.
type: string
example: documents:read
id_token:
description: A signed OIDC id_token (RS256). Present only when the openid scope was granted.
type:
- string
- 'null'
type: object
'400':
description: '`invalid_grant` (bad, expired, replayed, or wrong-client authorization code; a `code_verifier` outside the RFC 7636 grammar of 43-128 unreserved characters; redirect_uri mismatch; a refresh token whose authorization no longer includes `offline_access`; for token-exchange, a `subject_token` that is unusable, itself an exchanged token, not visible to service clients, or expired), `invalid_target` (a `resource` this server does not issue tokens for, one disagreeing with the authorized value, or — for token-exchange — one other than this API''s own resource identifier), `invalid_scope` (token-exchange only: the requested `scope` is not a subset of the subject token''s own scopes), `invalid_request` (token-exchange only: an unsupported `subject_token_type`/`requested_token_type`), or `unsupported_grant_type`'
content:
application/json:
schema:
properties:
error:
type: string
enum:
- invalid_grant
- invalid_target
- invalid_scope
- invalid_request
- unsupported_grant_type
error_description:
type: string
type: object
'401':
description: '`invalid_client` — unknown/disabled client or failed client authentication. The description never reveals whether client_id exists.'
content:
application/json:
schema:
properties:
error:
type: string
example: invalid_client
error_description:
type: string
example: Client authentication failed.
type: object
'429':
description: Rate limit exceeded; wait the `Retry-After` seconds. Limited per caller IP.
'500':
$ref: '#/components/responses/ServerError'
security: []
servers:
- url: https://api.assinafy.com.br
description: Production
- url: https://sandbox.assinafy.com.br
description: Sandbox
/v1/oauth/revoke:
post:
tags:
- OAuth
summary: Revoke a token
description: 'Revokes an access or refresh token. Every token outcome always returns 200 — including a token that does not exist, is already revoked, or is malformed — so the endpoint can never be used to probe whether a token exists. The one exception is failed client authentication, which returns 401.
Copy as Markdown Open in ChatGPT Open in Claude'
operationId: 4da9798b52b228fa0be9ddc534b42eee
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/OAuthRevokeRequest'
application/json:
schema:
$ref: '#/components/schemas/OAuthRevokeRequest'
responses:
'200':
description: Revoked
'401':
description: '`invalid_client` — the only case that is not reported as success. Every token outcome (revoked, already revoked, unknown, malformed) always returns 200; only failed client authentication returns 401.'
content:
application/json:
schema:
properties:
error:
type: string
example: invalid_client
error_description:
type: string
example: Client authentication failed.
type: object
'500':
$ref: '#/components/responses/ServerError'
security: []
servers:
- url: https://api.assinafy.com.br
description: Production
- url: https://sandbox.assinafy.com.br
description: Sandbox
/v1/oauth/userinfo:
get:
tags:
- OAuth
summary: OpenID Connect userinfo
description: 'Claims about the user who authorized this token. Requires the openid scope; name requires profile and email requires email. Per OIDC Core §5.3.2, the response is a flat JSON object of claims — never this API''s usual `{status, data, message}` envelope.
Copy as Markdown Open in ChatGPT Open in Claude'
operationId: b920740c01ff33773b9e6c13be139f7f
responses:
'200':
description: The user's claims
content:
application/json:
schema:
properties:
sub:
type: string
example: d6zqpbyog2v3xvxerwn8la94
name:
type:
- string
- 'null'
example: Maria Silva
email:
type:
- string
- 'null'
format: email
email_verified:
type:
- boolean
- 'null'
type: object
'403':
$ref: '#/components/responses/Forbidden'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
$ref: '#/components/responses/ServerError'
security:
- bearerAuth: []
- apiKeyAuth: []
servers:
- url: https://api.assinafy.com.br
description: Production
- url: https://sandbox.assinafy.com.br
description: Sandbox
/.well-known/oauth-protected-resource:
get:
tags:
- OAuth
summary: OAuth 2.0 protected resource metadata
description: 'RFC 9728. Identifies this API as a protected resource, the
* authorization server(s) that can issue tokens for it, and the scopes it
* accepts. `scopes_supported` deliberately excludes `offline_access` — per the
* MCP specification, requesting a refresh token is a client concern, not
* something a resource is protected by. Also referenced from the
* `WWW-Authenticate: Bearer resource_metadata="..."` challenge on a 401/403.
* Per RFC 8615, the response is the bare metadata object itself — never this
* API''s usual `{status, data, message}` envelope. The `authorization_servers` entry names the host that owns the browser-facing flow — start every integration by fetching `{authorization_servers[0]}/.well-known/oauth-authorization-server` (RFC 8414) from there, not from this API.
Copy as Markdown Open in ChatGPT Open in Claude'
operationId: 94f8ad95c46aea75be0241484f573ed6
responses:
'200':
description: The protected resource metadata
content:
application/json:
schema:
properties:
resource:
type: string
format: uri
authorization_servers:
type: array
items:
type: string
format: uri
scopes_supported:
type: array
items:
type: string
bearer_methods_supported:
type: array
items:
type: string
example: header
type: object
'500':
$ref: '#/components/responses/ServerError'
security: []
servers:
- url: https://api.assinafy.com.br
description: Production
- url: https://sandbox.assinafy.com.br
description: Sandbox
components:
schemas:
OAuthTokenRequest:
description: Body of `POST /v1/oauth/token`. Sent form-encoded per RFC 6749, or as JSON.
required:
- grant_type
- client_id
properties:
grant_type:
description: '`urn:ietf:params:oauth:grant-type:token-exchange` is for internal service clients only (Assinafy''s own MCP server) — an ordinary confidential or public client authenticates with it and always gets `invalid_client`, exactly as an unrecognized client would. Everyday integrators use `authorization_code` and `refresh_token`.'
type: string
enum:
- authorization_code
- refresh_token
- urn:ietf:params:oauth:grant-type:token-exchange
code:
type: string
redirect_uri:
type: string
format: uri
code_verifier:
description: 'RFC 7636: 43-128 characters from [A-Za-z0-9-._~]. Shorter values are rejected with `invalid_grant`.'
type: string
refresh_token:
type: string
client_id:
type: string
client_secret:
description: Confidential clients only. Public clients authenticate with PKCE and are never issued a secret; the token-exchange grant requires a confidential, internal-service client and therefore always requires this.
type: string
resource:
description: RFC 8707 resource indicator. For `authorization_code`/`refresh_token`, optional; when present it must be the `resource` value published by /.well-known/oauth-protected-resource and must match the one sent to /authorize, otherwise `invalid_target`. For the token-exchange grant it is REQUIRED and must equal this API's own resource identifier exactly (never a front-end resource such as the MCP server), otherwise `invalid_target`.
type: string
format: uri
subject_token:
description: Token-exchange grant only. The front-end resource's access token being traded in. Must be a live, original (never itself exchanged) token minted for a resource this server issues tokens for, other than this API's own audience.
type: string
subject_token_type:
description: Token-exchange grant only. Required; only `urn:ietf:params:oauth:token-type:access_token` is supported.
type: string
enum:
- urn:ietf:params:oauth:token-type:access_token
requested_token_type:
description: Token-exchange grant only. Optional; when present it must agree with the only type this server issues.
type: string
enum:
- urn:ietf:params:oauth:token-type:access_token
type: object
OAuthRevokeRequest:
description: Body of `POST /v1/oauth/revoke`. Sent form-encoded per RFC 7009, or as JSON.
required:
- token
- client_id
properties:
token:
type: string
token_type_hint:
type: string
enum:
- access_token
- refresh_token
client_id:
type: string
client_secret:
type: string
type: object
ErrorEnvelope:
description: Standard error wrapper. `status` mirrors the HTTP status code.
properties:
status:
type: integer
example: 400
message:
description: Human-readable error message.
type: string
example: Bad request.
data:
type:
- object
- 'null'
example: null
type: object
responses:
Unauthorized:
description: Missing or invalid credentials.
content:
application/json:
schema:
type: object
allOf:
- $ref: '#/components/schemas/ErrorEnvelope'
- properties:
status:
type: integer
example: 401
message:
type: string
example: Your request was made with invalid credentials.
type: object
Forbidden:
description: Authenticated but not allowed to perform this action.
content:
application/json:
schema:
type: object
allOf:
- $ref: '#/components/schemas/ErrorEnvelope'
- properties:
status:
type: integer
example: 403
message:
type: string
example: You are not allowed to perform this action.
type: object
ServerError:
description: Unexpected server error.
content:
application/json:
schema:
type: object
allOf:
- $ref: '#/components/schemas/ErrorEnvelope'
- properties:
status:
type: integer
example: 500
message:
type: string
example: An unexpected error occurred.
type: object
securitySchemes:
bearerAuth:
type: http
description: 'Access token: `Authorization: Bearer {access_token}`.'
bearerFormat: JWT
scheme: bearer
apiKeyAuth:
type: apiKey
description: Permanent API key (recommended for back-end integrations).
name: X-Api-Key
in: header
signerAccessCode:
type: apiKey
description: 'Signer access code used by signer-facing (Signing) endpoints instead of a user token: the code in the signer''s signing link, sent as the `signer-access-code` query or body parameter. It can be used again and has no expiry; it stops working when the signing request is removed. Treat it as a secret.'
name: signer-access-code
in: query
oauth2:
type: oauth2
description: 'OAuth 2.1 authorization code flow with mandatory PKCE (S256), for applications and AI assistants acting in a user''s workspace with that user''s permission — as opposed to `apiKeyAuth`/`bearerAuth`, which authenticate the workspace or user directly. A token carries only the scopes the user approved and works for one workspace. Endpoints are published by the authorization server at `https://auth.assinafy.com.br/.well-known/oauth-authorization-server`. An OAuth token cannot reach billing, account lifecycle, credential management or admin surfaces regardless of scope. A missing scope answers `403` with `WWW-Authenticate: Bearer error="insufficient_scope"` naming it. See **OAuth Integration Guide** for the full flow.'
flows:
authorizationCode:
authorizationUrl: https://auth.assinafy.com.br/oauth/authorize
tokenUrl: https://api.assinafy.com.br/v1/oauth/token
refreshUrl: https://api.assinafy.com.br/v1/oauth/token
scopes:
documents:read: Read documents, their pages, tags, signers, assignments and activity, and the WhatsApp notifications sent for an assignment.
documents:write: Create, update and delete documents, and manage their signers, assignments and activity.
templates:read: Read reusable document templates, their pages, roles, fields and tags.
templates:write: Create, update and delete templates, their pages, roles, fields and tags.
account:read: Read the workspace's profile, theme and logo.
webhooks:write: Change the workspace's webhook subscription (delivery URL, events, contact email), deactivate it, manage webhook endpoints and re-send a delivery.
openid: Identify the authenticated user (OpenID Connect `sub` claim) and enable the `/v1/oauth/userinfo` endpoint.
profile: Include the user's name in the `id_token`/userinfo claims.
email: Include the user's email and its verification status in the `id_token`/userinfo claims.
offline_access: Request a refresh token, so the app keeps working after the user's session expires without prompting them again. Only granted to a client that explicitly asks for it.
x-refined-from:
- assinafy-com-br-openapi.json
- assinafy-com-br-openapi.json