OAuth i prijava putem Sportyja

Kupnja putem agenta

Omogućite AI agentu da pronađe slobodne termine na terenima kluba i plati ih, putem protokola Agentic Commerce Protocol ili MCP-a.

AI agent može rezervirati teren u Sporty klubu i platiti ga karticom koju mu je kupac dao. Postoje dva ulaza, a ispod oba je ista naplata:

  • ACP: API za naplatu protokola Agentic Commerce Protocol, verzija 2026-04-17, na https://api.sporty.plus/api/acp.
  • MCP: MCP poslužitelj na https://api.sporty.plus/mcp (Streamable HTTP), s alatima za pronalaženje klubova i slobodnih termina na terenima, uz ACP alate za naplatu.

Oba su opisana na https://api.sporty.plus/.well-known/acp.json.

Plaćanje se obavlja Stripe shared payment tokenom (spt_…). Naplata se provodi na klubov vlastiti Stripe račun; klub je trgovac.

Klub prodaje putem agenata tek kad uključi kupnju putem agenta. Sve ostalo na ovoj stranici za klub koji to nije učinio odgovara 403 not_sellable.

Tko može kupovati

Svaki zahtjev nosi jedan od naših OAuth pristupnih tokena kao Authorization: Bearer. Token određuje tko je kupac.

TokenOpsegKupac
Članov, iz toka authorization codeme.purchases.writeČlan. Plaća cijenu svojeg članstva, a rezervacija je njegova.
Token odobrene platforme dobiven putem client_credentialsclub.checkout.write, koji odobrava klubGost, naveden e-poštom. Plaća onoliko koliko plaća novi korisnik.

me.purchases.write odvojen je od me.reservations.write: član koji aplikaciji dopusti da rezervira u njegovo ime time joj nije dopustio da troši njegov novac.

Kupnja za goste namijenjena je aplikacijama koje je Sporty pregledao, jer stvara račune. Klub aplikaciji mora odobriti i club.checkout.write, u svojem CMS-u pod API klijenti. Kad gost plati, stvaramo Sporty račun za njegovu e-poštu i šaljemo mu poveznicu za odabir lozinke.

Ako e-pošta već pripada nekom Sporty računu, naplata se odbija s requires_sign_in. Provedite osobu kroz OAuth i umjesto toga kupujte kao član. U suprotnom bi bilo tko mogao staviti rezervacije na tuđi račun samo upisivanjem tuđe adrese.

Pronalaženje termina na terenima

Stavke naplate su termini na terenima. Id termina sadrži teren, početak u UTC-u i trajanje:

slot_812_20261003T1700Z_90

Dobivate ih MCP alatom search_availability, koji navodi slobodne početke za kupca i koliko ga svaki stoji:

{
  "club_id": 214,
  "currency": "usd",
  "timezone": "America/New_York",
  "slots": [
    {
      "item_id": "slot_812_20261003T1700Z_90",
      "court": "Court 2",
      "sports": ["pickleball"],
      "starts_at": "2026-10-03T13:00:00-04:00",
      "ends_at": "2026-10-03T14:30:00-04:00",
      "minutes": 90,
      "total": 6533,
      "amounts": { "price": 6000, "tax": 533, "fee": 0, "total": 6533 }
    }
  ]
}

Klub najprije pronađite alatom search_clubs (po nazivu, gradu ili adresi te po želji sportu).

Iznosi su uvijek cijeli brojevi u najmanjoj jedinici valute: 6533 je 65,33 $.

Naplata putem ACP-a

Krajnje točke su ACP-ove. Svaki zahtjev šalje API-Version: 2026-04-17, a svaki POST šalje Idempotency-Key.

POST /api/acp/checkout_sessionsOtvara naplatu za jedan termin.
GET /api/acp/checkout_sessions/{id}Čita je.
POST /api/acp/checkout_sessions/{id}Mijenja termin ili kupca.
POST /api/acp/checkout_sessions/{id}/completePlaća i rezervira.
POST /api/acp/checkout_sessions/{id}/cancelOdustaje od nje.

Otvaranje ili mijenjanje naplate ništa ne rezervira. Ono određuje cijenu termina, a sesija je ready_for_payment ili not_ready_for_payment, s messages koje kažu zašto. Ništa se ne zauzima dok kupac ne plati, pa naplata koju nitko ne dovrši klub ne stoji nijednog terena. Sesija istječe 30 minuta nakon posljednje promjene.

curl -X POST https://api.sporty.plus/api/acp/checkout_sessions \
  -H "Authorization: Bearer $TOKEN" \
  -H 'API-Version: 2026-04-17' \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{
    "line_items": [{ "id": "slot_812_20261003T1700Z_90" }],
    "currency": "usd",
    "capabilities": {},
    "buyer": { "email": "jamie@example.com", "first_name": "Jamie", "last_name": "Rivera" }
  }'

Odgovor je ACP sesija naplate. Dijelovi koji su ovdje važni:

  • line_items[0]: teren, klub i vrijeme te njegovi totals.
  • totals: items_base_amount, subtotal, tax, fee (klupska naknada za plaćanje karticom, ako je ima) i total. Klub u SAD-u dodaje porez na promet povrh cijene. Klub čije cijene uključuju PDV prikazuje PDV unutar cijene, kao tax s oznakom „(included)”.
  • fulfillment_options: uvijek jedna opcija digital. Ništa se ne šalje; rezervacija se prikazuje u aplikaciji Sporty.
  • capabilities.payment.handlers: jedan handler, stripe_spt (dev.acp.tokenized.card). Njegov config.merchant_id je Stripe račun kluba, za podatke o prodavatelju u tokenu.
  • links: naši uvjeti korištenja i pravila privatnosti. Prikažite ih kupcu.

Za plaćanje pošaljite token:

{
  "payment_data": {
    "handler_id": "stripe_spt",
    "instrument": { "type": "card", "credential": { "type": "spt", "token": "spt_123" } }
  }
}

Uspješno dovršenje odgovara s status: "completed" i order, čiji je permalink_url stranica s rezervacijama člana na web-stranici kluba.

Kad ne prođe

Ovo se vraća kao messages u sesiji, a ne kao HTTP pogreške, jer kupac može nešto poduzeti:

codeŠto se dogodiloSesija
payment_declinedKartica je odbijena. Ništa nije rezervirano.ready_for_payment: pokušajte s drugim tokenom.
requires_3dsKartica traži 3-D Secure, koji kupnja putem agenta još ne podržava.ready_for_payment
out_of_stockNetko je zauzeo termin nakon što mu je određena cijena.not_ready_for_payment: odaberite drugi termin.
price_change (upozorenje)Cijena se promijenila nakon ponude, primjerice zato što je gostovo prvo članstvo drugačije naplaćeno. Ništa nije naplaćeno.ready_for_payment s novim ukupnim iznosom: potvrdite ga s kupcem.
missingNedostaje gostova e-pošta ili ime.not_ready_for_payment
requires_sign_inGostova e-pošta već ima Sporty račun.not_ready_for_payment

HTTP pogreške koriste ACP-ovo tijelo pogreške, {type, code, message, param}, i odnose se na zahtjeve koje je agent pogrešno poslao: nepoznata stavka (400 invalid_item_id), klub koji ne prodaje putem agenata ili nije dopustio ovu aplikaciju (403), tuđa sesija (404), otkazivanje dovršene sesije (405).

Idempotentnost

POST ponovljen s istim Idempotency-Key vraća prvi odgovor, uz Idempotent-Replayed: true, i ništa se ne događa dvaput. To uključuje i terećenje kartice. Isti ključ s drugačijim tijelom odgovara 422 idempotency_conflict. Dok se prvi zahtjev još izvodi, ponovljeni odgovara 409 idempotency_in_flight. Ključevi se pamte 24 sata, po aplikaciji i članu.

Naplata putem MCP-a

MCP poslužitelj autentificira se istim OAuth tokenima. Klijent bez tokena dobiva 401 s WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp" i ondje pronalazi naš autorizacijski poslužitelj. Klijent se može sam registrirati i od člana zatražiti me.purchases.write.

Alat
search_clubsKlubovi koji termine na terenima prodaju putem agenata.
search_availabilitySlobodni počeci u klubu, s cijenom za kupca.
create_checkout_sessionACP create.
get_checkout_sessionACP get.
update_checkout_sessionACP update.
complete_checkout_sessionACP complete.
cancel_checkout_sessionACP cancel.

Alati za naplatu prate ACP-ovo MCP povezivanje: argumenti su {meta, id, payload}, pri čemu meta nosi api_version (obavezno) i idempotency_key, a payload je REST tijelo. structuredContent rezultata ista je sesija naplate kojom odgovara REST API.

Odbijanje se vraća kao pogreška alata (isError: true) čiji je tekst ACP-ov objekt pogreške, a ne kao JSON-RPC pogreška.

Obavijesti o narudžbi nakon kupnje

Registrirajte kamo idu događaji vaših narudžbi:

curl -X PUT https://api.sporty.plus/api/acp/webhook \
  -H "Authorization: Bearer $TOKEN" -H 'API-Version: 2026-04-17' \
  -H 'Content-Type: application/json' \
  -d '{ "url": "https://agent.example/agentic_commerce/webhooks/order_events", "secret": "…" }'

Donesite vlastiti tajni ključ od najmanje 24 znaka ili ga izostavite, pa će se stvoriti jedan i prikazati vam jednom. GET prikazuje webhook i njegovu posljednju isporuku; DELETE ga uklanja. URL mora biti https na javnoj adresi.

Šaljemo ACP događaje narudžbe, svaki s cijelom narudžbom:

  • order_create kad je naplata plaćena;
  • order_update kad je rezervacija otkazana i novac vraćen. status narudžbe postaje canceled, a njezini adjustments navode povrat.
POST /agentic_commerce/webhooks/order_events
Merchant-Signature: t=1790000000,v1=5f2c…
Content-Type: application/json

{"type":"order_create","data":{"type":"order","id":"ord_48213","checkout_session_id":"cs_…","status":"confirmed", …}}

v1 je heksadecimalni HMAC-SHA256 od {t}.{body} s vašim tajnim ključem. Odbijte t stariji od pet minuta. Isporuka je barem jednom: neuspjela isporuka ponavlja se s dvostruko duljim čekanjem, do deset puta.

Otkazivanje i povrati

Rezervacija kupljena putem agenta, kad se otkaže unutar klupskog roka za otkazivanje, vraća se na karticu kojom je plaćena. Kupac može otkazati u aplikaciji Sporty ili putem DELETE /api/partner/v1/me/reservations/{id} ako agent ima me.reservations.write. Povrat uključuje i eventualnu naknadu za plaćanje karticom.

Još nije podržano

  • Bilo što osim termina na terenima: članstva, događaji i artikli iz trgovine.
  • 3-D Secure provjere.
  • Dijeljenje cijene među igračima. Kupac rezervira teren i plaća ga u cijelosti; partneri se mogu dodati u aplikaciji.
  • Više od jednog termina po naplati.
  • Feed proizvoda. Termini na terenima mijenjaju se iz minute u minutu, pa ih agenti pronalaze alatom search_availability.