- Create a Public Client
- Create a Confidential Client
- Validation Rules
- List Clients
- Retrieve a Client
- Update a Client
- Delete a Client
- Notes
Managing OAuth clients
Organization administrators can create and manage OAuth clients for their organization directly via the REST API.
All endpoints in this reference require an organization-admin access token in the Authorization header. See Obtaining a ClientID for your Application for background on Client IDs.
Anonymous requests return 401 Unauthorized; requests from non-admin users return 403 Forbidden. A request for a client that belongs to a different organization returns 404 Not Found, so the existence of other organizations’ clients is never revealed.
The response examples on this page show the main fields; actual responses can include additional fields.
Create a Public Client
Creates a public OAuth client (mobile, desktop, SPA, CLI). Public clients use authorization_code with PKCE and have no client secret.
POST "https://account.ezeep.com/v1/oauth-clients/public/"
| Attribute | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Human-readable name shown on the consent screen. Must be unique within your organization, ignoring case. |
| redirect_urls | string array | yes | Allowed redirect URIs. Max 20. Each URL must be HTTPS, http://localhost, or a reverse-DNS native scheme (e.g. com.example.app://cb). No wildcards, no fragments, no userinfo. |
| external_description | string | no | Description shown on the consent screen. |
| allowed_scopes | string | no | Space-separated scopes. See Validation Rules below. |
Public clients support the authorization_code grant only and must use PKCE with the S256 method; no client_secret is issued. The grant_types field is not accepted in the request body for public clients.
Example Request
curl -X POST "https://account.ezeep.com/v1/oauth-clients/public/" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer <access_token>" \
--data '{
"name": "Acme Print SPA",
"redirect_urls": ["https://app.acme.example/oauth/callback"],
"external_description": "Acme document printing for the web",
"allowed_scopes": "printing.print printing.documents.upload printing.printers.readonly openid profile"
}'
Example Response (201 Created)
{
"client_id": "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCd",
"name": "Acme Print SPA",
"external_description": "Acme document printing for the web",
"redirect_urls": ["https://app.acme.example/oauth/callback"],
"allowed_scopes": ["printing.print", "printing.documents.upload", "printing.printers.readonly", "openid", "profile"],
"grant_types": ["authorization_code"],
"client_type": "public"
}
Create a Confidential Client
Creates a confidential OAuth client (server-side backend that can protect a secret). Confidential clients receive a client_secret that is shown once in this response and cannot be retrieved later. Store it in a secure backend immediately. If it is lost, delete the client and create a new one.
POST "https://account.ezeep.com/v1/oauth-clients/confidential/"
| Attribute | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Human-readable name shown on the consent screen. Must be unique within your organization, ignoring case. |
| grant_types | string array | yes | Exactly one of authorization_code or pairing_code. |
| redirect_urls | string array | conditional | Required for authorization_code. May be empty for pairing-only clients. Same validation as public clients: max 20; HTTPS, http://localhost, or reverse-DNS native scheme; no wildcards, no fragments, no userinfo. |
| external_description | string | no | Description shown on the consent screen. |
| allowed_scopes | string | no | Space-separated scopes. See Validation Rules below. |
Confidential clients accept exactly one grant type per client. Admins who need both authorization_code and pairing_code should register two clients.
Example Request
curl -X POST "https://account.ezeep.com/v1/oauth-clients/confidential/" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer <access_token>" \
--data '{
"name": "Acme Print Backend",
"grant_types": ["authorization_code"],
"redirect_urls": ["https://backend.acme.example/ezeep/callback"],
"external_description": "Acme document printing backend",
"allowed_scopes": "printing.print printing.documents.upload printing.printers.readonly openid profile"
}'
Example Response (201 Created)
{
"client_id": "ZyXwVuTsRqPoNmLkJiHgFeDcBa9876543210zYxW",
"client_secret": "s3cr3t_shown_once_store_immediately_a1b2c3d4e5f6g7h8i9j0",
"name": "Acme Print Backend",
"external_description": "Acme document printing backend",
"redirect_urls": ["https://backend.acme.example/ezeep/callback"],
"allowed_scopes": ["printing.print", "printing.documents.upload", "printing.printers.readonly", "openid", "profile"],
"grant_types": ["authorization_code"],
"client_type": "confidential"
}
Validation Rules
The following rules apply to both public and confidential clients.
Redirect URLs
- Must be HTTPS,
http://localhost(any port and path), or a reverse-DNS native scheme (e.g.com.example.app://callback). - Wildcards, URL fragments (
#...), and userinfo (user:pass@...) are rejected. - Maximum of 20 URLs per client.
Scopes
- On input: space-separated string, maximum length 2048 characters. On output: JSON array of scope strings.
- Only defined ezeep scopes from the
printing,accounts,reporting,azureandwebhooksfamilies are accepted, plusopenid,profileandemail. - Any other scope is rejected with
400 Bad Requestand the message “One or more requested scopes are not permitted via API.” - Tokens issued to the client only carry scopes listed in
allowed_scopes; any other requested scope is dropped without an error. A client created withoutallowed_scopesissues tokens without any scopes, so list every scope your application will request. - For a printing integration, use
printing.print printing.documents.upload printing.printers.readonly openid profile, the same set the MCP self-service prompt uses. If your application also calls the reporting or webhooks APIs, addreportingorwebhooks; for read-only access,reporting.reports.readonlyorwebhooks.readonly.
Consent screen
The ezeep consent screen is always shown to end users during the authorization flow for clients created through this API.
Refresh-token rotation
Clients created through this API have refresh-token rotation enabled by default: each refresh_token is single-use, and the token-exchange response returns a new refresh_token that must replace the stored value.
Rate and count limits
Two limits apply at creation. Both return 429 Too Many Requests.
- Per admin: up to 10 create requests per hour, including requests rejected by validation. Exceeding this returns
429with aRetry-Afterheader. - Per organization: up to 100 OAuth clients created through this API. Exceeding this returns
429immediately; delete a client you no longer need to free a slot.
List Clients
Lists OAuth clients owned by the caller’s organization. Results are ordered by created descending (newest first) and then by client_id. Clients that were not created through this API are not included. Results are paginated with the limit and offset query parameters: 20 per page by default, up to 100.
GET "https://account.ezeep.com/v1/oauth-clients/"
Example Request
curl -X GET "https://account.ezeep.com/v1/oauth-clients/" \
--header "Authorization: Bearer <access_token>"
Example Response
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"client_id": "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCd",
"name": "Acme Print SPA",
"client_type": "public",
"grant_types": ["authorization_code"]
},
{
"client_id": "ZyXwVuTsRqPoNmLkJiHgFeDcBa9876543210zYxW",
"name": "Acme Print Backend",
"client_type": "confidential",
"grant_types": ["authorization_code"]
}
]
}
Client secrets are never returned by this endpoint (or any other endpoint after creation).
Retrieve a Client
Returns the current configuration of a single client.
GET "https://account.ezeep.com/v1/oauth-clients/<client_id>/"
Example Request
curl -X GET "https://account.ezeep.com/v1/oauth-clients/aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCd/" \
--header "Authorization: Bearer <access_token>"
Update a Client
Partially updates a client. Only the fields below may be changed; client_type and grant_types are immutable and must be set correctly at creation. Unknown fields in the request body are rejected with 400 Bad Request.
PATCH "https://account.ezeep.com/v1/oauth-clients/<client_id>/"
| Attribute | Type | Required | Description |
|---|---|---|---|
| name | string | no | Human-readable name shown on the consent screen. Must be unique within your organization, ignoring case. |
| external_description | string | no | Description shown on the consent screen. |
| redirect_urls | string array | no | Same validation rules as at creation. |
| allowed_scopes | string | no | Space-separated string on input; same validation as at creation. The response body returns allowed_scopes as a JSON array. |
Example Request
curl -X PATCH "https://account.ezeep.com/v1/oauth-clients/aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCd/" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer <access_token>" \
--data '{
"redirect_urls": [
"https://app.acme.example/oauth/callback",
"https://staging.acme.example/oauth/callback"
]
}'
Delete a Client
Deletes a client immediately. Existing access tokens issued to the client remain valid until they expire, but no new tokens can be issued and no refresh will succeed. There is no soft-delete window. A subsequent GET for the same client_id returns 404.
DELETE "https://account.ezeep.com/v1/oauth-clients/<client_id>/"
Example Request
curl -X DELETE "https://account.ezeep.com/v1/oauth-clients/aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789AbCd/" \
--header "Authorization: Bearer <access_token>"
Returns 204 No Content on success.
Notes
MCP self-service. The ezeep MCP server’s register_oauth_client tool calls the public-client endpoint on behalf of an organization administrator; see the MCP self-service prompt for a conversational alternative to the raw endpoint.
Clients not visible to this API. Clients that were not created through this API are not listed and return 404 on direct access. They must continue to be managed by ezeep; contact the ezeep team via the API Contact Form.