PadelSwap API — for AI builders
Build AI agents for the PadelSwap marketplace on behalf of a logged-in user. The rule: anything a user can do in the app, an agent can do through the API — browse, make and counter offers, manage listings and orders, open disputes, leave reviews. The single exception is the final payment, which is always confirmed by a human in the browser. REST + a fully MCP-compatible server.
counter_offer back. Free-form chat (send_message) opens only after payment, scoped to that order, between the two parties. So: pre-purchase → offers; post-purchase → order chat.Quickstart
- The end-user generates a token at padelswap.ee/profile/api-tokens and shares it with your agent. The Helpful assistant preset is a sensible default; the user can broaden it later.
- The token (
psk_live_…) is shown only once at creation. Store it as a secret on your side. - Send it as a Bearer header on every request.
# Read the authenticated user's profile
curl https://padelswap.ee/api/v1/me \
-H "Authorization: Bearer psk_live_…"
# Browse listings
curl "https://padelswap.ee/api/v1/listings?category=RACKET&q=hack&limit=5" \
-H "Authorization: Bearer psk_live_…"Model Context Protocol (MCP)
The same capabilities are exposed as MCP tools at https://padelswap.ee/api/mcp. Any MCP-aware agent — Claude Desktop, Cursor, Copilot Workspaces — can discover and call them automatically.
{
"mcpServers": {
"padelswap": {
"url": "https://padelswap.ee/api/mcp",
"headers": {
"Authorization": "Bearer psk_live_…"
}
}
}
}After saving the config and restarting your agent, the full tool set becomes available — one MCP tool per user action, grouped below:
list_listingsread:catalogSearch active listingsget_listingread:catalogFull listing details by idget_meread:selfAuthenticated user profilelist_my_listingsread:selfListings owned by the user (any status)list_my_ordersread:selfOrders where the user is buyer or seller (role-annotated)list_my_favouritesread:selfListings the user has favouritedfavourite_listingwrite:favouritesAdd a listing to favouritesunfavourite_listingwrite:favouritesRemove a listing from favouritessend_messagewrite:messagesSend a chat message on a paid ordercreate_listingwrite:listingsCreate a listing for sale (with inline base64 photos)update_listingwrite:listingsEdit title / description / price / condition / delivery / citydelete_listingwrite:listingsSoft-delete one of the user’s listingsplace_offerwrite:offersPlace an offer on a listing (≥70% of ask, < ask)accept_offerwrite:offersSeller accepts a pending offerreject_offerwrite:offersSeller rejects a pending offercounter_offerwrite:offersSeller counters a buyer’s offerwithdraw_offerwrite:offersWithdraw your own pending offermark_shippedwrite:ordersSeller records the parcel as shippedmark_receivedwrite:ordersBuyer confirms receipt (opens 48h window)start_meetupwrite:ordersSeller starts the in-person meetupverify_meetupwrite:ordersSeller enters the buyer’s 4-digit codeswitch_to_omnivawrite:ordersBuyer switches a meetup to parcel-lockerretry_shipmentwrite:ordersSeller re-runs Omniva label generationopen_disputewrite:disputesBuyer opens a dispute (48h window)respond_disputewrite:disputesSeller responds to a disputewithdraw_disputewrite:disputesBuyer withdraws their disputesubmit_reviewwrite:reviewsBuyer reviews the seller (1–5 stars)delete_reviewwrite:reviewsDelete your own review (in window)update_profilewrite:profileSet phone / Playtomic URL / chat-email togglefollow_sellerwrite:favouritesFollow a seller’s new listingsunfollow_sellerwrite:favouritesUnfollow a sellersearch_racketsread:catalogFind Padelful racket specs by namecompare_racketsread:catalogCompare 1–3 rackets side-by-sideprepare_checkoutwrite:checkoutPrepare a purchase. Returns a one-time URL the user opens to confirm payment.
Protocol version 2024-11-05 · transport: http+jsonrpc · methods: initialize, ping, tools/list, tools/call.
Auth + scopes
Tokens are scoped — the agent gets exactly the permissions you grant when creating it, nothing more. The available scopes:
| Scope | In preset | What it does |
|---|---|---|
| read:catalog | all | Browse listings, search, fetch racket specs. |
| read:self | all | The user's profile, orders, and favourites. |
| write:favourites | helpful + full | Add or remove favourites; follow or unfollow sellers. |
| write:messages | helpful + full | Send chat messages on the user’s orders (post-payment order chat only). |
| write:reviews | helpful + full | Leave, edit, or delete the user’s review of a seller. |
| write:listings | full | Create, edit, and remove the user’s own listings. |
| write:offers | full | Place / withdraw offers as a buyer; accept / reject / counter offers as a seller. |
| write:orders | full | Order lifecycle: mark shipped, confirm receipt, meetup start + code, switch to Omniva, retry shipment. |
| write:disputes | full | Open, respond to, or withdraw a dispute on an order. |
| write:profile | full | Update phone, Playtomic URL, and the chat-email notification toggle. |
| write:checkout | full | Prepare a checkout and receive a one-time confirm URL. The user confirms payment in their browser. |
A scope mismatch returns 403 missing_scope. Pick a preset when creating the token, or hand-pick scopes via the custom option.
Purchases — the human in the loop
Agents can prepare a purchase, but cannot complete it. The API has no "confirm" or "capture" endpoint. prepare_checkout reserves the listing, sets up the payment, and returns a one-time URL. The user opens the URL in their own browser and clicks Confirm and pay there. Money never moves without an explicit human click.
curl -X POST https://padelswap.ee/api/v1/orders/checkout-prepare \
-H "Authorization: Bearer psk_live_…" \
-H "Content-Type: application/json" \
-d '{
"listingId": "00000000-0000-0000-0000-000000000000",
"delivery": {
"method": "OMNIVA",
"locker": { "zip": "10116", "name": "Solaris pakiautomaat" }
}
}'{
"data": {
"order_id": "…",
"confirm_url": "https://padelswap.ee/checkout/confirm/tk_…",
"expires_at": "2026-05-21T19:30:00Z",
"total_cents": 10465,
"currency": "EUR",
"breakdown": {
"item_cents": 9900,
"buyer_protection_cents": 565,
"shipping_cents": 0
}
}
}Show the confirm_url to the user. They have 15 minutes to open it and complete the purchase. The URL is one-time-use; reopening after a successful purchase redirects to the order.
REST endpoints
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/me | read:self | The authenticated user’s profile |
| GET | /api/v1/me/listings | read:self | Listings owned by the user (any status) |
| GET | /api/v1/me/orders | read:self | Orders the user is buyer or seller on. Optional ?side=buyer|seller |
| GET | /api/v1/me/favourites | read:self | Listings the user has favourited |
| POST | /api/v1/me/favourites | write:favourites | Add a listing to favourites |
| DELETE | /api/v1/me/favourites/{listingId} | write:favourites | Remove a listing from favourites |
| GET | /api/v1/listings | read:catalog | Active listings (paginated). Filters: ?q, ?category, ?limit, ?offset |
| GET | /api/v1/listings/{id} | read:catalog | Full listing details |
| POST | /api/v1/messages | write:messages | Send a chat message on one of the user’s paid orders |
| POST | /api/v1/listings | write:listings | Create a listing for sale (with inline base64 photos) |
| PATCH | /api/v1/listings/{id} | write:listings | Edit one of the user’s listings (title, description, price, condition, …) |
| DELETE | /api/v1/listings/{id} | write:listings | Soft-delete a listing (status → REMOVED) |
| POST | /api/v1/offers | write:offers | Place an offer on a listing as a buyer |
| POST | /api/v1/offers/{id}/accept | write:offers | Seller accepts a pending offer (24h payment window starts) |
| POST | /api/v1/offers/{id}/reject | write:offers | Seller rejects a pending offer |
| POST | /api/v1/offers/{id}/counter | write:offers | Seller counters with a new linked offer (body: offeredCents, message?) |
| POST | /api/v1/offers/{id}/withdraw | write:offers | Withdraw your own pending offer |
| PATCH | /api/v1/me | write:profile | Update phone / playtomicUrl / chatEmailNotifications (any subset) |
| POST | /api/v1/me/follows | write:favourites | Follow a seller (body: sellerId) |
| DELETE | /api/v1/me/follows/{sellerId} | write:favourites | Unfollow a seller |
| POST | /api/v1/orders/{id}/mark-shipped | write:orders | Seller marks shipped (body: tracking) |
| POST | /api/v1/orders/{id}/mark-received | write:orders | Buyer confirms receipt → DELIVERED + 48h window |
| POST | /api/v1/orders/{id}/start-meetup | write:orders | Seller starts the meetup (unlocks code entry) |
| POST | /api/v1/orders/{id}/verify-meetup | write:orders | Seller enters the buyer’s 4-digit code (body: code) |
| POST | /api/v1/orders/{id}/switch-to-omniva | write:orders | Buyer switches a meetup to parcel-locker (body: locker) |
| POST | /api/v1/orders/{id}/retry-shipment | write:orders | Seller re-runs Omniva label generation |
| POST | /api/v1/orders/{id}/dispute | write:disputes | Buyer opens a dispute (body: reason, message, evidenceUrls?) |
| POST | /api/v1/orders/{id}/dispute/respond | write:disputes | Seller responds to the dispute (body: message, evidenceUrls?) |
| POST | /api/v1/orders/{id}/dispute/withdraw | write:disputes | Buyer withdraws the dispute |
| POST | /api/v1/orders/{id}/review | write:reviews | Buyer submits / edits a review (body: stars, text?) |
| DELETE | /api/v1/orders/{id}/review | write:reviews | Delete your review on this order |
| POST | /api/v1/orders/checkout-prepare | write:checkout | Prepare a purchase. Returns a one-time confirm URL (15-min TTL). |
Error format
Every error returns a JSON body with a stable code and a human-readable message:
{
"error": {
"code": "missing_scope",
"message": "Token is missing required scope: write:checkout."
}
}Codes you'll see:
missing_token·malformed_token·invalid_token·revoked_token·expired_token— auth issuesmissing_scope— token lacks the required scoperate_limited— quota hit; see Rate limits belowbad_request·not_found·forbidden·precondition_failed— request issuesdb_error·upstream_error— server-side
Rate limits
Each token: 60 requests per minute and 5,000 requests per day. Over the cap returns 429 rate_limited with a Retry-After header in seconds.
For partner integrations needing higher limits, write to support@padelswap.ee.
Activity log
Every authenticated request is recorded — endpoint, scope used, HTTP status, IP, and user-agent. Users review their own activity at Profile → AI tokens → Activity. Revoked tokens stop working within 30 seconds.
Design principles
- Personal access tokens, not OAuth. The AI is the user's own agent — tokens are issued and revoked by the user, like an SSH key. No third-party app flow, no consent screens, no client registration.
- Payment confirmation stays in the browser. Even with
write:checkout, the AI can only prepare a purchase. The final confirm is a real click in the user's logged-in browser session. AI mistakes cap at a 10-minute listing reservation; money never moves without a human. - Same handlers behind REST and MCP. Pick the transport that fits your stack. Auth, scopes, rate limits, and audit log are identical across both.