WordPress plugins and AI agents
The Partner API is free, and software can reach it without anyone registering it by hand: a WordPress booking plugin installed on many salons’ sites, a website an AI builder generated, or an AI agent that books for a business. Each copy registers itself, then the business connects it on the United Pet Club consent page like any other app.
This page walks through the whole flow. Authentication is the reference for every field and error.
Before you start
Section titled “Before you start”| You need | Why |
|---|---|
| Nothing from United Pet Club | Registration is anonymous: no account, no key, no card. |
| A redirect URI | The page of your site or app the business’s browser comes back to: https, or http on localhost, 127.0.0.1 or [::1] while you develop. |
| A business on United Pet Club | Someone who acts as the business’s profile signs in and allows your app. |
| A payment card on the business’s account | Connecting is free, but a business connects apps only while it keeps a valid payment card on file (Dashboard → Finances → Billing). |
The flow
Section titled “The flow”| Step | Call | Who, and how often |
|---|---|---|
| 1. Discover | GET https://api.unitedpetclub.com/.well-known/oauth-protected-resource, then GET https://auth.unitedpetclub.com/.well-known/oauth-authorization-server | Your software; optional if you use the hosts on this page |
| 2. Register | POST https://auth.unitedpetclub.com/connect/register | Your software, once per site or install |
| 3. Connect | The business’s browser goes to https://auth.unitedpetclub.com/connect/authorize with a PKCE challenge | The business, once |
| 4. Exchange | POST https://auth.unitedpetclub.com/connect/token with grant_type=authorization_code | Your server, once per connection |
| 5. Call | https://api.unitedpetclub.com/api/scheduling/v1/… with the access token | Your software |
| 6. Refresh | POST https://auth.unitedpetclub.com/connect/token with grant_type=refresh_token | Your server, before the access token expires |
1. Discover the endpoints
Section titled “1. Discover the endpoints”A client that knows only the API’s address can find the rest. A call without a valid token answers
401 with a pointer to the API’s metadata:
GET /api/scheduling/v1/business HTTP/1.1Host: api.unitedpetclub.comHTTP/1.1 401 UnauthorizedWWW-Authenticate: Bearer resource_metadata="https://api.unitedpetclub.com/.well-known/oauth-protected-resource"Content-Type: application/problem+jsonThat document (RFC 9728) names the authorization server:
{ "resource": "https://api.unitedpetclub.com", "authorization_servers": ["https://auth.unitedpetclub.com"], "scopes_supported": ["scheduling:read", "appointment:read", "appointment:write", "client:read", "webhook:manage"], "bearer_methods_supported": ["header"]}and the authorization server’s document (RFC 8414,
https://auth.unitedpetclub.com/.well-known/oauth-authorization-server) names the authorization_endpoint,
token_endpoint and registration_endpoint, the supported scopes, code_challenge_methods_supported
(S256) and token_endpoint_auth_methods_supported (none for a public client). Both documents are
anonymous and may be cached for an hour. The full examples are under
Discovery metadata.
2. Register
Section titled “2. Register”Register once per site or install, when your software is set up, and store what comes back. This example registers a WordPress site’s copy of a plugin as a public client, which has no secret:
POST /connect/register HTTP/1.1Host: auth.unitedpetclub.comContent-Type: application/json
{ "client_name": "Paws & Suds online booking", "redirect_uris": ["https://pawsandsuds.example/wp-admin/admin.php?page=upc-booking-callback"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "scope": "scheduling:read appointment:read appointment:write", "client_uri": "https://pawsandsuds.example", "policy_uri": "https://pawsandsuds.example/privacy", "contacts": ["web@pawsandsuds.example"], "software_id": "upc-booking-for-wordpress", "software_version": "1.4.2"}HTTP/1.1 201 CreatedContent-Type: application/jsonCache-Control: no-store
{ "client_id": "upc-…", "client_id_issued_at": 1790345678, "redirect_uris": ["https://pawsandsuds.example/wp-admin/admin.php?page=upc-booking-callback"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "client_name": "Paws & Suds online booking", "client_uri": "https://pawsandsuds.example", "policy_uri": "https://pawsandsuds.example/privacy", "scope": "scheduling:read appointment:read appointment:write", "software_id": "upc-booking-for-wordpress", "software_version": "1.4.2"}- Public or confidential. With
token_endpoint_auth_methodnonethere is no secret. If your software runs on a server that can keep one (a WordPress site can, in its database), you may leave the field out (client_secret_basic) or sendclient_secret_post: the answer then also carriesclient_secret, shown this once, andclient_secret_expires_at0(it does not expire). Either way, a self-registered app must use PKCE. - Redirect URIs match exactly, scheme, host, port, path and query included. Register every address the browser may come back to (up to 10), for example the exact loopback URL and port an agent listens on.
- The name is what businesses see. It may not name United Pet Club; without one, businesses see the host of your first redirect URI.
- Scopes. Ask only for what you need. Leave
scopeout to register all five Partner API scopes; no other scope can be registered. - Limits. At most 20 apps can be registered from one address in 24 hours, and self-registration
pauses for the day when a platform-wide limit is reached:
429withRetry-After: 3600. Sites on shared hosting share their server’s address, so never register per request, per business or per visitor.
Every refusal and field rule is listed under Self-registration.
3. Send the business to the consent page
Section titled “3. Send the business to the consent page”For every connection attempt, make a PKCE pair and a state value, and keep both on your server with the
user’s session:
// WordPress / PHP 7.1+$verifier = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');$challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '=');$state = bin2hex(random_bytes(16));// Node.js 18+import crypto from "node:crypto";
const verifier = crypto.randomBytes(32).toString("base64url");const challenge = crypto.createHash("sha256").update(verifier).digest("base64url");const state = crypto.randomBytes(16).toString("hex");Then send the business’s browser to the authorize URL:
https://auth.unitedpetclub.com/connect/authorize ?response_type=code &client_id=upc-… &redirect_uri=https%3A%2F%2Fpawsandsuds.example%2Fwp-admin%2Fadmin.php%3Fpage%3Dupc-booking-callback &scope=scheduling%3Aread%20appointment%3Aread%20appointment%3Awrite &state=… &code_challenge=… &code_challenge_method=S256A self-registered app must send code_challenge with code_challenge_method=S256. Without it, or with a
redirect URI you did not register, the consent page explains the problem to the business and does not
send the browser back.
The business signs in, acting as its business profile, and sees:
- your app as an Unverified app, Registered by the host of your redirect URI (not by a publisher), with the advice to allow it only if it trusts that site;
- the business it is connecting (it can switch to another of its businesses) and each permission you ask for;
- After you choose, you’ll go back to your redirect URI’s host;
- Add a payment card first when the business has no valid card on file. Allow stays off until it adds one (a link takes it to Finances → Billing) and comes back to the page.
On Allow the browser comes back with ?code=…&state=…; on Deny, with ?error=access_denied&….
Check state first. The code is valid for 10 minutes, once.
4. Exchange the code
Section titled “4. Exchange the code”A public client sends its client_id and the code_verifier, and no client_secret:
curl -X POST https://auth.unitedpetclub.com/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=upcac_..." \ --data-urlencode "redirect_uri=https://pawsandsuds.example/wp-admin/admin.php?page=upc-booking-callback" \ -d "code_verifier=THE_VERIFIER_FROM_STEP_3" \ -d "client_id=upc-…"{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6ImRldi1hY2Nlc3MifQ...", "token_type": "Bearer", "expires_in": 3600, "scope": "scheduling:read appointment:read appointment:write", "refresh_token": "upcrt_..."}A confidential client adds its client_secret (or HTTP Basic). A public client that sends a secret is
refused with 401 invalid_client. Store the refresh token with the business’s connection, encrypted: for
a public client it is all anyone needs to get new access tokens.
5. Call the API
Section titled “5. Call the API”curl https://api.unitedpetclub.com/api/scheduling/v1/services \ -H "Authorization: Bearer $ACCESS_TOKEN"The token acts for the business that allowed your app and for nothing else: its services, open slots, estimates, bookings, appointments, clients and webhooks, within the scopes it granted. The booking guide covers every route.
| You get | Why | What to do |
|---|---|---|
401 0010010000402 | The business disconnected your app, or United Pet Club suspended or revoked it | Stop calling; offer to connect again. |
403 0010010000407 | The business has no valid payment card on file | Tell the business to add one (Dashboard → Finances → Billing). Calls work again within about 10 seconds of the card being added. |
503 0010010000503 | The connection or the card could not be checked | Retry after Retry-After seconds. |
6. Refresh
Section titled “6. Refresh”curl -X POST https://auth.unitedpetclub.com/connect/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=refresh_token" \ -d "refresh_token=upcrt_..." \ -d "client_id=upc-…"Each refresh returns a new access token and a new refresh token; the one you used stops working. A refresh token lasts 90 days from when it was issued, so an integration that refreshes within that time never has to send the business through the consent page again. Refresh one business at a time from one worker (see Authentication → Refresh).
AI agents and MCP clients
Section titled “AI agents and MCP clients”An AI agent can use this flow as it is. A client that follows RFC 9728 and RFC 8414 finds the
authorization server from the API’s 401, registers itself, and asks a person at the business to approve
it in a browser: an agent cannot connect itself to a business. An agent that only needs to read can use the
United Pet Club MCP server instead (https://mcp.unitedpetclub.com, read-only,
free, no card on file); an agent that books for a business calls this REST API with the business’s access token.
- Register once and keep the
client_id; do not register for every conversation. - An agent on a person’s computer can use a loopback redirect URI such as
http://127.0.0.1:8765/callback. Register the exact address and port it listens on. - Ask for the fewest scopes that do the job. The business sees each one before it allows the agent.
What “self-registered” means
Section titled “What “self-registered” means”- No publisher. The app belongs to no United Pet Club profile, so nobody can manage it under Account → Developer → Applications: its secret cannot be rotated, and its redirect URIs and scopes cannot be changed. To change them, register a new client and have the businesses connect it.
- Shown as unverified on the consent page and in the business’s Connected Apps, with the site it came from.
- PKCE always, whether or not it has a secret.
- The Partner API scopes only, for the businesses that allowed it. A business can disconnect it at any time, and United Pet Club can suspend or revoke it.
If you want businesses to see your company as the publisher, to rotate a secret and to see the businesses that connected your app, register it yourself under Account → Developer → Applications instead (see Registering an application). Those apps are confidential clients: your server keeps the secret.
Terms, reviews and fees
Section titled “Terms, reviews and fees”Registering or operating an app means accepting the United Pet Club Platform Agreement for yourself and for the app. Section 13.7 (Apps, APIs & Integrations), new in version 1.2 of the Agreement, says in short:
- The developer services are free unless United Pet Club tells you otherwise; rate limits and the permissions each business grants apply.
- An app acts for a business only with its permission and only while the business keeps a valid payment card on file. The business is responsible for what the app does for it, including the bookings it makes and their fees.
- United Pet Club may review and test any app at any time, with or without notice: test accounts, test requests, and test bookings, which carry no fees. You must not detect these reviews or treat them differently from ordinary use.
- Self-registered apps are shown as unverified. United Pet Club may suspend, limit or revoke any app.
Bookings your app makes carry the business’s usual Commission and Platform Processing Fee (see Fees on bookings). The Agreement also requires the true price of every booking and sale (section 13.5) and sets a fine for trying to avoid fees (section 13.6).
- Authentication — every field, grant and error.
- Booking & Scheduling → Partner API — what a connected business’s token can do.
- Webhooks — appointment notices instead of polling.